diff options
author | Stephan Bergmann <sbergman@redhat.com> | 2019-05-02 06:40:33 +0000 |
---|---|---|
committer | Stephan Bergmann <sbergman@redhat.com> | 2019-05-02 06:40:33 +0000 |
commit | d139bd8e458debdc7392d1042a74d0bc335ac856 (patch) | |
tree | 205a240147bea7739e19791fbaec68ca8facade5 | |
parent | fc6f4a6ed7e7a8a77d1592f1ec6948fbb3ca42fa (diff) | |
download | compiler-rt-d139bd8e458debdc7392d1042a74d0bc335ac856.tar.gz |
Adapt -fsanitize=function to SANITIZER_NON_UNIQUE_TYPEINFO
This follows up after b7692bc3e9ad2691fc07261904b88fb15f30696b "[UBSan] Fix
isDerivedFromAtOffset on iOS ARM64" fixed the RTTI comparison in
isDerivedFromAtOffset on just one platform and then
a25a2c7c9a7e1e328a5bd8274d2d86b1fadc4692 "Always compare C++ typeinfo (based on
libstdc++ implementation)" extended that fix to more platforms.
But there is another RTTI comparison for -fsanitize=function generated in
clang's CodeGenFunction::EmitCall as just a pointer comparison. For
SANITIZER_NON_UNIQUE_TYPEINFO platforms this needs to be extended to also do
string comparison. For that, __ubsan_handle_function_type_mismatch[_abort]
takes the two std::type_info pointers as additional parameters now, checks them
internally for potential equivalence, and returns without reporting failure if
they turn out to be equivalent after all. (NORETURN needed to be dropped from
the _abort variant for that.) Also these functions depend on ABI-specific RTTI
now, so needed to be moved from plain UBSAN_SOURCES (ubsan_handlers.h/cc) to
UBSAN_CXXABI_SOURCES (ubsan_handlers_cxx.h/cc), but as -fsanitize=function is
only supported in C++ mode that's not a problem.
Differential Revision: https://reviews.llvm.org/D60760
git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@359759 91177308-0d34-0410-b5e6-96231b3b80d8
-rw-r--r-- | lib/ubsan/ubsan_handlers.cc | 36 | ||||
-rw-r--r-- | lib/ubsan/ubsan_handlers.h | 9 | ||||
-rw-r--r-- | lib/ubsan/ubsan_handlers_cxx.cc | 45 | ||||
-rw-r--r-- | lib/ubsan/ubsan_handlers_cxx.h | 15 | ||||
-rw-r--r-- | lib/ubsan/ubsan_type_hash.h | 4 | ||||
-rw-r--r-- | lib/ubsan/ubsan_type_hash_itanium.cc | 13 | ||||
-rw-r--r-- | lib/ubsan/ubsan_type_hash_win.cc | 5 |
7 files changed, 79 insertions, 48 deletions
diff --git a/lib/ubsan/ubsan_handlers.cc b/lib/ubsan/ubsan_handlers.cc index d4b8f13b7..938ac8975 100644 --- a/lib/ubsan/ubsan_handlers.cc +++ b/lib/ubsan/ubsan_handlers.cc @@ -598,42 +598,6 @@ void __ubsan::__ubsan_handle_invalid_builtin_abort(InvalidBuiltinData *Data) { Die(); } -static void handleFunctionTypeMismatch(FunctionTypeMismatchData *Data, - ValueHandle Function, - ReportOptions Opts) { - SourceLocation CallLoc = Data->Loc.acquire(); - ErrorType ET = ErrorType::FunctionTypeMismatch; - - if (ignoreReport(CallLoc, Opts, ET)) - return; - - ScopedReport R(Opts, CallLoc, ET); - - SymbolizedStackHolder FLoc(getSymbolizedLocation(Function)); - const char *FName = FLoc.get()->info.function; - if (!FName) - FName = "(unknown)"; - - Diag(CallLoc, DL_Error, ET, - "call to function %0 through pointer to incorrect function type %1") - << FName << Data->Type; - Diag(FLoc, DL_Note, ET, "%0 defined here") << FName; -} - -void -__ubsan::__ubsan_handle_function_type_mismatch(FunctionTypeMismatchData *Data, - ValueHandle Function) { - GET_REPORT_OPTIONS(false); - handleFunctionTypeMismatch(Data, Function, Opts); -} - -void __ubsan::__ubsan_handle_function_type_mismatch_abort( - FunctionTypeMismatchData *Data, ValueHandle Function) { - GET_REPORT_OPTIONS(true); - handleFunctionTypeMismatch(Data, Function, Opts); - Die(); -} - static void handleNonNullReturn(NonNullReturnData *Data, SourceLocation *LocPtr, ReportOptions Opts, bool IsAttr) { if (!LocPtr) diff --git a/lib/ubsan/ubsan_handlers.h b/lib/ubsan/ubsan_handlers.h index 37a63c565..22ca96422 100644 --- a/lib/ubsan/ubsan_handlers.h +++ b/lib/ubsan/ubsan_handlers.h @@ -168,15 +168,6 @@ struct InvalidBuiltinData { /// Handle a builtin called in an invalid way. RECOVERABLE(invalid_builtin, InvalidBuiltinData *Data) -struct FunctionTypeMismatchData { - SourceLocation Loc; - const TypeDescriptor &Type; -}; - -RECOVERABLE(function_type_mismatch, - FunctionTypeMismatchData *Data, - ValueHandle Val) - struct NonNullReturnData { SourceLocation AttrLoc; }; diff --git a/lib/ubsan/ubsan_handlers_cxx.cc b/lib/ubsan/ubsan_handlers_cxx.cc index 56b5a9e9a..839bba369 100644 --- a/lib/ubsan/ubsan_handlers_cxx.cc +++ b/lib/ubsan/ubsan_handlers_cxx.cc @@ -156,6 +156,51 @@ void __ubsan_handle_cfi_bad_type(CFICheckFailData *Data, ValueHandle Vtable, Diag(Loc, DL_Note, ET, "check failed in %0, vtable located in %1") << SrcModule << DstModule; } + +static bool handleFunctionTypeMismatch(FunctionTypeMismatchData *Data, + ValueHandle Function, + ValueHandle calleeRTTI, + ValueHandle fnRTTI, ReportOptions Opts) { + if (checkTypeInfoEquality(reinterpret_cast<void *>(calleeRTTI), + reinterpret_cast<void *>(fnRTTI))) + return false; + + SourceLocation CallLoc = Data->Loc.acquire(); + ErrorType ET = ErrorType::FunctionTypeMismatch; + + if (ignoreReport(CallLoc, Opts, ET)) + return true; + + ScopedReport R(Opts, CallLoc, ET); + + SymbolizedStackHolder FLoc(getSymbolizedLocation(Function)); + const char *FName = FLoc.get()->info.function; + if (!FName) + FName = "(unknown)"; + + Diag(CallLoc, DL_Error, ET, + "call to function %0 through pointer to incorrect function type %1") + << FName << Data->Type; + Diag(FLoc, DL_Note, ET, "%0 defined here") << FName; + return true; +} + +void __ubsan_handle_function_type_mismatch(FunctionTypeMismatchData *Data, + ValueHandle Function, + ValueHandle calleeRTTI, + ValueHandle fnRTTI) { + GET_REPORT_OPTIONS(false); + handleFunctionTypeMismatch(Data, Function, calleeRTTI, fnRTTI, Opts); +} + +void __ubsan_handle_function_type_mismatch_abort(FunctionTypeMismatchData *Data, + ValueHandle Function, + ValueHandle calleeRTTI, + ValueHandle fnRTTI) { + GET_REPORT_OPTIONS(true); + if (handleFunctionTypeMismatch(Data, Function, calleeRTTI, fnRTTI, Opts)) + Die(); +} } // namespace __ubsan #endif // CAN_SANITIZE_UB diff --git a/lib/ubsan/ubsan_handlers_cxx.h b/lib/ubsan/ubsan_handlers_cxx.h index 8dd5f1a0f..be2345dc1 100644 --- a/lib/ubsan/ubsan_handlers_cxx.h +++ b/lib/ubsan/ubsan_handlers_cxx.h @@ -33,6 +33,21 @@ void __ubsan_handle_dynamic_type_cache_miss( extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __ubsan_handle_dynamic_type_cache_miss_abort( DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash); + +struct FunctionTypeMismatchData { + SourceLocation Loc; + const TypeDescriptor &Type; +}; + +extern "C" SANITIZER_INTERFACE_ATTRIBUTE void +__ubsan_handle_function_type_mismatch(FunctionTypeMismatchData *Data, + ValueHandle Val, ValueHandle calleeRTTI, + ValueHandle fnRTTI); +extern "C" SANITIZER_INTERFACE_ATTRIBUTE void +__ubsan_handle_function_type_mismatch_abort(FunctionTypeMismatchData *Data, + ValueHandle Val, + ValueHandle calleeRTTI, + ValueHandle fnRTTI); } #endif // UBSAN_HANDLERS_H diff --git a/lib/ubsan/ubsan_type_hash.h b/lib/ubsan/ubsan_type_hash.h index 811aeb83e..e42884b76 100644 --- a/lib/ubsan/ubsan_type_hash.h +++ b/lib/ubsan/ubsan_type_hash.h @@ -64,6 +64,10 @@ const int VptrMaxOffsetToTop = 1<<20; extern "C" SANITIZER_INTERFACE_ATTRIBUTE HashValue __ubsan_vptr_type_cache[VptrTypeCacheSize]; +/// \brief Do whatever is required by the ABI to check for std::type_info +/// equivalence beyond simple pointer comparison. +bool checkTypeInfoEquality(const void *TypeInfo1, const void *TypeInfo2); + } // namespace __ubsan #endif // UBSAN_TYPE_HASH_H diff --git a/lib/ubsan/ubsan_type_hash_itanium.cc b/lib/ubsan/ubsan_type_hash_itanium.cc index 3d5e536d3..c4b048f20 100644 --- a/lib/ubsan/ubsan_type_hash_itanium.cc +++ b/lib/ubsan/ubsan_type_hash_itanium.cc @@ -117,9 +117,7 @@ static bool isDerivedFromAtOffset(const abi::__class_type_info *Derived, const abi::__class_type_info *Base, sptr Offset) { if (Derived->__type_name == Base->__type_name || - (SANITIZER_NON_UNIQUE_TYPEINFO && - Derived->__type_name[0] != '*' && - !internal_strcmp(Derived->__type_name, Base->__type_name))) + __ubsan::checkTypeInfoEquality(Derived, Base)) return Offset == 0; if (const abi::__si_class_type_info *SI = @@ -258,4 +256,13 @@ __ubsan::getDynamicTypeInfoFromVtable(void *VtablePtr) { ObjectType ? ObjectType->__type_name : "<unknown>"); } +bool __ubsan::checkTypeInfoEquality(const void *TypeInfo1, + const void *TypeInfo2) { + auto TI1 = static_cast<const std::type_info *>(TypeInfo1); + auto TI2 = static_cast<const std::type_info *>(TypeInfo2); + return SANITIZER_NON_UNIQUE_TYPEINFO && TI1->__type_name[0] != '*' && + TI2->__type_name[0] != '*' && + !internal_strcmp(TI1->__type_name, TI2->__type_name); +} + #endif // CAN_SANITIZE_UB && !SANITIZER_WINDOWS diff --git a/lib/ubsan/ubsan_type_hash_win.cc b/lib/ubsan/ubsan_type_hash_win.cc index f3035e121..21c51e328 100644 --- a/lib/ubsan/ubsan_type_hash_win.cc +++ b/lib/ubsan/ubsan_type_hash_win.cc @@ -77,4 +77,9 @@ __ubsan::getDynamicTypeInfoFromVtable(void *VtablePtr) { "<unknown>"); } +bool __ubsan::checkTypeInfoEquality(const std::type_info *, + const std::type_info *) { + return false; +} + #endif // CAN_SANITIZE_UB && SANITIZER_WINDOWS |