diff options
Diffstat (limited to 'lib/ubsan')
-rw-r--r-- | lib/ubsan/lit_tests/CMakeLists.txt | 1 | ||||
-rw-r--r-- | lib/ubsan/lit_tests/TypeCheck/Function/function.cpp | 17 | ||||
-rw-r--r-- | lib/ubsan/lit_tests/TypeCheck/Function/lit.local.cfg | 3 | ||||
-rw-r--r-- | lib/ubsan/lit_tests/lit.cfg | 3 | ||||
-rw-r--r-- | lib/ubsan/ubsan_diag.cc | 9 | ||||
-rw-r--r-- | lib/ubsan/ubsan_diag.h | 6 | ||||
-rw-r--r-- | lib/ubsan/ubsan_handlers.cc | 20 | ||||
-rw-r--r-- | lib/ubsan/ubsan_handlers.h | 9 |
8 files changed, 68 insertions, 0 deletions
diff --git a/lib/ubsan/lit_tests/CMakeLists.txt b/lib/ubsan/lit_tests/CMakeLists.txt index 7e1a13c78..6abc8a01e 100644 --- a/lib/ubsan/lit_tests/CMakeLists.txt +++ b/lib/ubsan/lit_tests/CMakeLists.txt @@ -8,6 +8,7 @@ if(COMPILER_RT_CAN_EXECUTE_TESTS) # working binaries. set(UBSAN_TEST_DEPS ${SANITIZER_COMMON_LIT_TEST_DEPS} + asan ${UBSAN_RUNTIME_LIBRARIES}) set(UBSAN_TEST_PARAMS ubsan_site_config=${CMAKE_CURRENT_BINARY_DIR}/lit.site.cfg diff --git a/lib/ubsan/lit_tests/TypeCheck/Function/function.cpp b/lib/ubsan/lit_tests/TypeCheck/Function/function.cpp new file mode 100644 index 000000000..feff0f5aa --- /dev/null +++ b/lib/ubsan/lit_tests/TypeCheck/Function/function.cpp @@ -0,0 +1,17 @@ +// RUN: %clangxx -fsanitize=address,function %s -O3 -g -o %t +// RUN: %t 2>&1 | FileCheck %s + +#include <stdint.h> + +void f() {} + +void g(int x) {} + +int main(void) { + // CHECK: runtime error: call to function f() through pointer to incorrect function type 'void (*)(int)' + // CHECK-NEXT: function.cpp:6: note: f() defined here + reinterpret_cast<void (*)(int)>(reinterpret_cast<uintptr_t>(f))(42); + + // CHECK-NOT: runtime error: call to function g + reinterpret_cast<void (*)(int)>(reinterpret_cast<uintptr_t>(g))(42); +} diff --git a/lib/ubsan/lit_tests/TypeCheck/Function/lit.local.cfg b/lib/ubsan/lit_tests/TypeCheck/Function/lit.local.cfg new file mode 100644 index 000000000..27c61a343 --- /dev/null +++ b/lib/ubsan/lit_tests/TypeCheck/Function/lit.local.cfg @@ -0,0 +1,3 @@ +# The function type checker is only supported on x86 and x86_64 for now. +if config.root.host_arch not in ['x86', 'x86_64']: + config.unsupported = True diff --git a/lib/ubsan/lit_tests/lit.cfg b/lib/ubsan/lit_tests/lit.cfg index 4a5bc237b..d96912fe8 100644 --- a/lib/ubsan/lit_tests/lit.cfg +++ b/lib/ubsan/lit_tests/lit.cfg @@ -54,6 +54,9 @@ config.substitutions.append( ("%clang ", (" " + config.clang + " ")) ) config.substitutions.append( ("%clangxx ", (" " + config.clang + " --driver-mode=g++ ")) ) +# Setup path to external LLVM symbolizer. +config.environment['ASAN_SYMBOLIZER_PATH'] = config.llvm_symbolizer_path + # Default test suffixes. config.suffixes = ['.c', '.cc', '.cpp'] diff --git a/lib/ubsan/ubsan_diag.cc b/lib/ubsan/ubsan_diag.cc index e4ca4e4af..968e7790d 100644 --- a/lib/ubsan/ubsan_diag.cc +++ b/lib/ubsan/ubsan_diag.cc @@ -26,12 +26,21 @@ Location __ubsan::getCallerLocation(uptr CallerLoc) { return Location(); uptr Loc = StackTrace::GetPreviousInstructionPc(CallerLoc); + return getFunctionLocation(Loc, 0); +} + +Location __ubsan::getFunctionLocation(uptr Loc, const char **FName) { + if (!Loc) + return Location(); AddressInfo Info; if (!getSymbolizer()->SymbolizeCode(Loc, &Info, 1) || !Info.module || !*Info.module) return Location(Loc); + if (FName && Info.function) + *FName = Info.function; + if (!Info.file) return ModuleLocation(Info.module, Info.module_offset); diff --git a/lib/ubsan/ubsan_diag.h b/lib/ubsan/ubsan_diag.h index 16afffdb0..54d15a0cc 100644 --- a/lib/ubsan/ubsan_diag.h +++ b/lib/ubsan/ubsan_diag.h @@ -80,6 +80,12 @@ public: /// an invalid location or a module location for the caller. Location getCallerLocation(uptr CallerLoc = GET_CALLER_PC()); +/// Try to obtain a location for the given function pointer. This might fail, +/// and produce either an invalid location or a module location for the caller. +/// If FName is non-null and the name of the function is known, set *FName to +/// the function name, otherwise *FName is unchanged. +Location getFunctionLocation(uptr Loc, const char **FName); + /// A diagnostic severity level. enum DiagLevel { DL_Error, ///< An error. diff --git a/lib/ubsan/ubsan_handlers.cc b/lib/ubsan/ubsan_handlers.cc index 5ed0d5923..d55643143 100644 --- a/lib/ubsan/ubsan_handlers.cc +++ b/lib/ubsan/ubsan_handlers.cc @@ -259,3 +259,23 @@ void __ubsan::__ubsan_handle_load_invalid_value_abort(InvalidValueData *Data, __ubsan_handle_load_invalid_value(Data, Val); Die(); } + +void __ubsan::__ubsan_handle_function_type_mismatch( + FunctionTypeMismatchData *Data, + ValueHandle Function) { + const char *FName = "(unknown)"; + + Location Loc = getFunctionLocation(Function, &FName); + + Diag(Data->Loc, DL_Error, + "call to function %0 through pointer to incorrect function type %1") + << FName << Data->Type; + Diag(Loc, DL_Note, "%0 defined here") << FName; +} + +void __ubsan::__ubsan_handle_function_type_mismatch_abort( + FunctionTypeMismatchData *Data, + ValueHandle Function) { + __ubsan_handle_function_type_mismatch(Data, Function); + Die(); +} diff --git a/lib/ubsan/ubsan_handlers.h b/lib/ubsan/ubsan_handlers.h index 9406207fa..14e6f04c2 100644 --- a/lib/ubsan/ubsan_handlers.h +++ b/lib/ubsan/ubsan_handlers.h @@ -112,6 +112,15 @@ struct InvalidValueData { /// \brief Handle a load of an invalid value for the type. RECOVERABLE(load_invalid_value, InvalidValueData *Data, ValueHandle Val) +struct FunctionTypeMismatchData { + SourceLocation Loc; + const TypeDescriptor &Type; +}; + +RECOVERABLE(function_type_mismatch, + FunctionTypeMismatchData *Data, + ValueHandle Val) + } #endif // UBSAN_HANDLERS_H |