summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--lib/ubsan/ubsan_handlers.cc56
-rw-r--r--lib/ubsan/ubsan_handlers.h3
-rw-r--r--test/ubsan/TestCases/TypeCheck/Function/function.cpp40
3 files changed, 89 insertions, 10 deletions
diff --git a/lib/ubsan/ubsan_handlers.cc b/lib/ubsan/ubsan_handlers.cc
index 1112ce1cc..064d9b78c 100644
--- a/lib/ubsan/ubsan_handlers.cc
+++ b/lib/ubsan/ubsan_handlers.cc
@@ -18,6 +18,9 @@
#include "sanitizer_common/sanitizer_common.h"
+#include <cstring>
+#include <typeinfo>
+
using namespace __sanitizer;
using namespace __ubsan;
@@ -461,14 +464,50 @@ void __ubsan::__ubsan_handle_invalid_builtin_abort(InvalidBuiltinData *Data) {
Die();
}
-static void handleFunctionTypeMismatch(FunctionTypeMismatchData *Data,
- ValueHandle Function,
+// Check that TI2 represents the same function type as TI1, except that TI2 has
+// "noexcept" and TI1 does not.
+static bool checkForAddedNoexcept(const std::type_info *TI1,
+ const std::type_info *TI2) {
+ const char *Mangled1 = TI1->name();
+ const char *Mangled2 = TI2->name();
+
+ // Skip <CV-qualifiers>.
+ if (*Mangled1 == 'V') {
+ if (*Mangled2 != 'V')
+ return false;
+ ++Mangled1;
+ ++Mangled2;
+ }
+ if (*Mangled1 == 'K') {
+ if (*Mangled2 != 'K')
+ return false;
+ ++Mangled1;
+ ++Mangled2;
+ }
+
+ // Check for "Do" <exception-spec>.
+ if (*Mangled2++ != 'D' || *Mangled2++ != 'o')
+ return false;
+
+ // Check remainder is identical.
+ return std::strcmp(Mangled1, Mangled2) == 0;
+}
+
+static bool handleFunctionTypeMismatch(FunctionTypeMismatchData *Data,
+ ValueHandle Function, ValueHandle RTTI,
ReportOptions Opts) {
+ if (Data->NonNoexceptRTTI &&
+ checkForAddedNoexcept(
+ reinterpret_cast<std::type_info *>(Data->NonNoexceptRTTI),
+ reinterpret_cast<std::type_info *>(RTTI))) {
+ return false;
+ }
+
SourceLocation CallLoc = Data->Loc.acquire();
ErrorType ET = ErrorType::FunctionTypeMismatch;
if (ignoreReport(CallLoc, Opts, ET))
- return;
+ return true;
ScopedReport R(Opts, CallLoc, ET);
@@ -481,20 +520,21 @@ static void handleFunctionTypeMismatch(FunctionTypeMismatchData *Data,
"call to function %0 through pointer to incorrect function type %1")
<< FName << Data->Type;
Diag(FLoc, DL_Note, "%0 defined here") << FName;
+ return true;
}
void
__ubsan::__ubsan_handle_function_type_mismatch(FunctionTypeMismatchData *Data,
- ValueHandle Function) {
+ ValueHandle Function, ValueHandle RTTI) {
GET_REPORT_OPTIONS(false);
- handleFunctionTypeMismatch(Data, Function, Opts);
+ handleFunctionTypeMismatch(Data, Function, RTTI, Opts);
}
void __ubsan::__ubsan_handle_function_type_mismatch_abort(
- FunctionTypeMismatchData *Data, ValueHandle Function) {
+ FunctionTypeMismatchData *Data, ValueHandle Function, ValueHandle RTTI) {
GET_REPORT_OPTIONS(true);
- handleFunctionTypeMismatch(Data, Function, Opts);
- Die();
+ if (handleFunctionTypeMismatch(Data, Function, RTTI, Opts))
+ Die();
}
static void handleNonNullReturn(NonNullReturnData *Data, SourceLocation *LocPtr,
diff --git a/lib/ubsan/ubsan_handlers.h b/lib/ubsan/ubsan_handlers.h
index 311776b9f..4ec2592e3 100644
--- a/lib/ubsan/ubsan_handlers.h
+++ b/lib/ubsan/ubsan_handlers.h
@@ -140,11 +140,12 @@ RECOVERABLE(invalid_builtin, InvalidBuiltinData *Data)
struct FunctionTypeMismatchData {
SourceLocation Loc;
const TypeDescriptor &Type;
+ ValueHandle NonNoexceptRTTI;
};
RECOVERABLE(function_type_mismatch,
FunctionTypeMismatchData *Data,
- ValueHandle Val)
+ ValueHandle Val, ValueHandle RTTI)
struct NonNullReturnData {
SourceLocation AttrLoc;
diff --git a/test/ubsan/TestCases/TypeCheck/Function/function.cpp b/test/ubsan/TestCases/TypeCheck/Function/function.cpp
index 25b2bdc32..409eeb2ff 100644
--- a/test/ubsan/TestCases/TypeCheck/Function/function.cpp
+++ b/test/ubsan/TestCases/TypeCheck/Function/function.cpp
@@ -1,4 +1,4 @@
-// RUN: %clangxx -fsanitize=function %s -O3 -g -o %t
+// RUN: %clangxx -std=c++17 -fsanitize=function %s -O3 -g -o %t
// RUN: %run %t 2>&1 | FileCheck %s
// Verify that we can disable symbolization if needed:
// RUN: %env_ubsan_opts=symbolize=0 %run %t 2>&1 | FileCheck %s --check-prefix=NOSYM
@@ -23,9 +23,47 @@ void make_invalid_call() {
reinterpret_cast<void (*)(int)>(reinterpret_cast<uintptr_t>(f))(42);
}
+void f1(int) {}
+void f2(unsigned int) {}
+void f3(int) noexcept {}
+void f4(unsigned int) noexcept {}
+
+void check_noexcept_calls() {
+ void (*p1)(int);
+ p1 = &f1;
+ p1(0);
+ p1 = reinterpret_cast<void (*)(int)>(&f2);
+ // CHECK: function.cpp:[[@LINE+2]]:3: runtime error: call to function f2(unsigned int) through pointer to incorrect function type 'void (*)(int)'
+ // NOSYM: function.cpp:[[@LINE+1]]:3: runtime error: call to function (unknown) through pointer to incorrect function type 'void (*)(int)'
+ p1(0);
+ p1 = &f3;
+ p1(0);
+ p1 = reinterpret_cast<void (*)(int)>(&f4);
+ // CHECK: function.cpp:[[@LINE+2]]:3: runtime error: call to function f4(unsigned int) through pointer to incorrect function type 'void (*)(int)'
+ // NOSYM: function.cpp:[[@LINE+1]]:3: runtime error: call to function (unknown) through pointer to incorrect function type 'void (*)(int)'
+ p1(0);
+
+ void (*p2)(int) noexcept;
+ p2 = reinterpret_cast<void (*)(int) noexcept>(&f1);
+ // CHECK: function.cpp:[[@LINE+2]]:3: runtime error: call to function f1(int) through pointer to incorrect function type 'void (*)(int) noexcept'
+ // NOSYM: function.cpp:[[@LINE+1]]:3: runtime error: call to function (unknown) through pointer to incorrect function type 'void (*)(int) noexcept'
+ p2(0);
+ p2 = reinterpret_cast<void (*)(int) noexcept>(&f2);
+ // CHECK: function.cpp:[[@LINE+2]]:3: runtime error: call to function f2(unsigned int) through pointer to incorrect function type 'void (*)(int) noexcept'
+ // NOSYM: function.cpp:[[@LINE+1]]:3: runtime error: call to function (unknown) through pointer to incorrect function type 'void (*)(int) noexcept'
+ p2(0);
+ p2 = &f3;
+ p2(0);
+ p2 = reinterpret_cast<void (*)(int) noexcept>(&f4);
+ // CHECK: function.cpp:[[@LINE+2]]:3: runtime error: call to function f4(unsigned int) through pointer to incorrect function type 'void (*)(int) noexcept'
+ // NOSYM: function.cpp:[[@LINE+1]]:3: runtime error: call to function (unknown) through pointer to incorrect function type 'void (*)(int) noexcept'
+ p2(0);
+}
+
int main(void) {
make_valid_call();
make_invalid_call();
+ check_noexcept_calls();
// Check that no more errors will be printed.
// CHECK-NOT: runtime error: call to function
// NOSYM-NOT: runtime error: call to function