xref: /openbsd-src/gnu/llvm/compiler-rt/lib/ubsan/ubsan_handlers_cxx.cpp (revision 810390e339a5425391477d5d41c78d7cab2424ac)
13cab2bb3Spatrick //===-- ubsan_handlers_cxx.cpp --------------------------------------------===//
23cab2bb3Spatrick //
33cab2bb3Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43cab2bb3Spatrick // See https://llvm.org/LICENSE.txt for license information.
53cab2bb3Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63cab2bb3Spatrick //
73cab2bb3Spatrick //===----------------------------------------------------------------------===//
83cab2bb3Spatrick //
93cab2bb3Spatrick // Error logging entry points for the UBSan runtime, which are only used for C++
103cab2bb3Spatrick // compilations. This file is permitted to use language features which require
113cab2bb3Spatrick // linking against a C++ ABI library.
123cab2bb3Spatrick //
133cab2bb3Spatrick //===----------------------------------------------------------------------===//
143cab2bb3Spatrick 
153cab2bb3Spatrick #include "ubsan_platform.h"
163cab2bb3Spatrick #if CAN_SANITIZE_UB
173cab2bb3Spatrick #include "ubsan_handlers.h"
183cab2bb3Spatrick #include "ubsan_handlers_cxx.h"
193cab2bb3Spatrick #include "ubsan_diag.h"
203cab2bb3Spatrick #include "ubsan_type_hash.h"
213cab2bb3Spatrick 
223cab2bb3Spatrick #include "sanitizer_common/sanitizer_common.h"
233cab2bb3Spatrick #include "sanitizer_common/sanitizer_suppressions.h"
243cab2bb3Spatrick 
253cab2bb3Spatrick using namespace __sanitizer;
263cab2bb3Spatrick using namespace __ubsan;
273cab2bb3Spatrick 
283cab2bb3Spatrick namespace __ubsan {
29*810390e3Srobert   extern const char *const TypeCheckKinds[];
303cab2bb3Spatrick }
313cab2bb3Spatrick 
323cab2bb3Spatrick // Returns true if UBSan has printed an error report.
HandleDynamicTypeCacheMiss(DynamicTypeCacheMissData * Data,ValueHandle Pointer,ValueHandle Hash,ReportOptions Opts)333cab2bb3Spatrick static bool HandleDynamicTypeCacheMiss(
343cab2bb3Spatrick     DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash,
353cab2bb3Spatrick     ReportOptions Opts) {
363cab2bb3Spatrick   if (checkDynamicType((void*)Pointer, Data->TypeInfo, Hash))
373cab2bb3Spatrick     // Just a cache miss. The type matches after all.
383cab2bb3Spatrick     return false;
393cab2bb3Spatrick 
403cab2bb3Spatrick   // Check if error report should be suppressed.
413cab2bb3Spatrick   DynamicTypeInfo DTI = getDynamicTypeInfoFromObject((void*)Pointer);
423cab2bb3Spatrick   if (DTI.isValid() && IsVptrCheckSuppressed(DTI.getMostDerivedTypeName()))
433cab2bb3Spatrick     return false;
443cab2bb3Spatrick 
453cab2bb3Spatrick   SourceLocation Loc = Data->Loc.acquire();
463cab2bb3Spatrick   ErrorType ET = ErrorType::DynamicTypeMismatch;
473cab2bb3Spatrick   if (ignoreReport(Loc, Opts, ET))
483cab2bb3Spatrick     return false;
493cab2bb3Spatrick 
503cab2bb3Spatrick   ScopedReport R(Opts, Loc, ET);
513cab2bb3Spatrick 
523cab2bb3Spatrick   Diag(Loc, DL_Error, ET,
533cab2bb3Spatrick        "%0 address %1 which does not point to an object of type %2")
543cab2bb3Spatrick     << TypeCheckKinds[Data->TypeCheckKind] << (void*)Pointer << Data->Type;
553cab2bb3Spatrick 
563cab2bb3Spatrick   // If possible, say what type it actually points to.
573cab2bb3Spatrick   if (!DTI.isValid()) {
583cab2bb3Spatrick     if (DTI.getOffset() < -VptrMaxOffsetToTop || DTI.getOffset() > VptrMaxOffsetToTop) {
593cab2bb3Spatrick       Diag(Pointer, DL_Note, ET,
603cab2bb3Spatrick            "object has a possibly invalid vptr: abs(offset to top) too big")
613cab2bb3Spatrick           << TypeName(DTI.getMostDerivedTypeName())
623cab2bb3Spatrick           << Range(Pointer, Pointer + sizeof(uptr), "possibly invalid vptr");
633cab2bb3Spatrick     } else {
643cab2bb3Spatrick       Diag(Pointer, DL_Note, ET, "object has invalid vptr")
653cab2bb3Spatrick           << TypeName(DTI.getMostDerivedTypeName())
663cab2bb3Spatrick           << Range(Pointer, Pointer + sizeof(uptr), "invalid vptr");
673cab2bb3Spatrick     }
683cab2bb3Spatrick   } else if (!DTI.getOffset())
693cab2bb3Spatrick     Diag(Pointer, DL_Note, ET, "object is of type %0")
703cab2bb3Spatrick         << TypeName(DTI.getMostDerivedTypeName())
713cab2bb3Spatrick         << Range(Pointer, Pointer + sizeof(uptr), "vptr for %0");
723cab2bb3Spatrick   else
733cab2bb3Spatrick     // FIXME: Find the type at the specified offset, and include that
743cab2bb3Spatrick     //        in the note.
753cab2bb3Spatrick     Diag(Pointer - DTI.getOffset(), DL_Note, ET,
763cab2bb3Spatrick          "object is base class subobject at offset %0 within object of type %1")
773cab2bb3Spatrick         << DTI.getOffset() << TypeName(DTI.getMostDerivedTypeName())
783cab2bb3Spatrick         << TypeName(DTI.getSubobjectTypeName())
793cab2bb3Spatrick         << Range(Pointer, Pointer + sizeof(uptr),
803cab2bb3Spatrick                  "vptr for %2 base class of %1");
813cab2bb3Spatrick   return true;
823cab2bb3Spatrick }
833cab2bb3Spatrick 
__ubsan_handle_dynamic_type_cache_miss(DynamicTypeCacheMissData * Data,ValueHandle Pointer,ValueHandle Hash)843cab2bb3Spatrick void __ubsan::__ubsan_handle_dynamic_type_cache_miss(
853cab2bb3Spatrick     DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash) {
863cab2bb3Spatrick   GET_REPORT_OPTIONS(false);
873cab2bb3Spatrick   HandleDynamicTypeCacheMiss(Data, Pointer, Hash, Opts);
883cab2bb3Spatrick }
__ubsan_handle_dynamic_type_cache_miss_abort(DynamicTypeCacheMissData * Data,ValueHandle Pointer,ValueHandle Hash)893cab2bb3Spatrick void __ubsan::__ubsan_handle_dynamic_type_cache_miss_abort(
903cab2bb3Spatrick     DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash) {
913cab2bb3Spatrick   // Note: -fsanitize=vptr is always recoverable.
923cab2bb3Spatrick   GET_REPORT_OPTIONS(false);
933cab2bb3Spatrick   if (HandleDynamicTypeCacheMiss(Data, Pointer, Hash, Opts))
943cab2bb3Spatrick     Die();
953cab2bb3Spatrick }
963cab2bb3Spatrick 
973cab2bb3Spatrick namespace __ubsan {
__ubsan_handle_cfi_bad_type(CFICheckFailData * Data,ValueHandle Vtable,bool ValidVtable,ReportOptions Opts)983cab2bb3Spatrick void __ubsan_handle_cfi_bad_type(CFICheckFailData *Data, ValueHandle Vtable,
993cab2bb3Spatrick                                  bool ValidVtable, ReportOptions Opts) {
1003cab2bb3Spatrick   SourceLocation Loc = Data->Loc.acquire();
1013cab2bb3Spatrick   ErrorType ET = ErrorType::CFIBadType;
1023cab2bb3Spatrick 
1033cab2bb3Spatrick   if (ignoreReport(Loc, Opts, ET))
1043cab2bb3Spatrick     return;
1053cab2bb3Spatrick 
1063cab2bb3Spatrick   ScopedReport R(Opts, Loc, ET);
1073cab2bb3Spatrick   DynamicTypeInfo DTI = ValidVtable
1083cab2bb3Spatrick                             ? getDynamicTypeInfoFromVtable((void *)Vtable)
1093cab2bb3Spatrick                             : DynamicTypeInfo(0, 0, 0);
1103cab2bb3Spatrick 
1113cab2bb3Spatrick   const char *CheckKindStr;
1123cab2bb3Spatrick   switch (Data->CheckKind) {
1133cab2bb3Spatrick   case CFITCK_VCall:
1143cab2bb3Spatrick     CheckKindStr = "virtual call";
1153cab2bb3Spatrick     break;
1163cab2bb3Spatrick   case CFITCK_NVCall:
1173cab2bb3Spatrick     CheckKindStr = "non-virtual call";
1183cab2bb3Spatrick     break;
1193cab2bb3Spatrick   case CFITCK_DerivedCast:
1203cab2bb3Spatrick     CheckKindStr = "base-to-derived cast";
1213cab2bb3Spatrick     break;
1223cab2bb3Spatrick   case CFITCK_UnrelatedCast:
1233cab2bb3Spatrick     CheckKindStr = "cast to unrelated type";
1243cab2bb3Spatrick     break;
1253cab2bb3Spatrick   case CFITCK_VMFCall:
1263cab2bb3Spatrick     CheckKindStr = "virtual pointer to member function call";
1273cab2bb3Spatrick     break;
1283cab2bb3Spatrick   case CFITCK_ICall:
1293cab2bb3Spatrick   case CFITCK_NVMFCall:
1303cab2bb3Spatrick     Die();
1313cab2bb3Spatrick   }
1323cab2bb3Spatrick 
1333cab2bb3Spatrick   Diag(Loc, DL_Error, ET,
1343cab2bb3Spatrick        "control flow integrity check for type %0 failed during "
1353cab2bb3Spatrick        "%1 (vtable address %2)")
1363cab2bb3Spatrick       << Data->Type << CheckKindStr << (void *)Vtable;
1373cab2bb3Spatrick 
1383cab2bb3Spatrick   // If possible, say what type it actually points to.
1393cab2bb3Spatrick   if (!DTI.isValid())
1403cab2bb3Spatrick     Diag(Vtable, DL_Note, ET, "invalid vtable");
1413cab2bb3Spatrick   else
1423cab2bb3Spatrick     Diag(Vtable, DL_Note, ET, "vtable is of type %0")
1433cab2bb3Spatrick         << TypeName(DTI.getMostDerivedTypeName());
1443cab2bb3Spatrick 
1453cab2bb3Spatrick   // If the failure involved different DSOs for the check location and vtable,
1463cab2bb3Spatrick   // report the DSO names.
1473cab2bb3Spatrick   const char *DstModule = Symbolizer::GetOrInit()->GetModuleNameForPc(Vtable);
1483cab2bb3Spatrick   if (!DstModule)
1493cab2bb3Spatrick     DstModule = "(unknown)";
1503cab2bb3Spatrick 
1513cab2bb3Spatrick   const char *SrcModule = Symbolizer::GetOrInit()->GetModuleNameForPc(Opts.pc);
1523cab2bb3Spatrick   if (!SrcModule)
1533cab2bb3Spatrick     SrcModule = "(unknown)";
1543cab2bb3Spatrick 
1553cab2bb3Spatrick   if (internal_strcmp(SrcModule, DstModule))
1563cab2bb3Spatrick     Diag(Loc, DL_Note, ET, "check failed in %0, vtable located in %1")
1573cab2bb3Spatrick         << SrcModule << DstModule;
1583cab2bb3Spatrick }
1593cab2bb3Spatrick 
handleFunctionTypeMismatch(FunctionTypeMismatchData * Data,ValueHandle Function,ValueHandle calleeRTTI,ValueHandle fnRTTI,ReportOptions Opts)1603cab2bb3Spatrick static bool handleFunctionTypeMismatch(FunctionTypeMismatchData *Data,
1613cab2bb3Spatrick                                        ValueHandle Function,
1623cab2bb3Spatrick                                        ValueHandle calleeRTTI,
1633cab2bb3Spatrick                                        ValueHandle fnRTTI, ReportOptions Opts) {
1643cab2bb3Spatrick   if (checkTypeInfoEquality(reinterpret_cast<void *>(calleeRTTI),
1653cab2bb3Spatrick                             reinterpret_cast<void *>(fnRTTI)))
1663cab2bb3Spatrick     return false;
1673cab2bb3Spatrick 
1683cab2bb3Spatrick   SourceLocation CallLoc = Data->Loc.acquire();
1693cab2bb3Spatrick   ErrorType ET = ErrorType::FunctionTypeMismatch;
1703cab2bb3Spatrick 
1713cab2bb3Spatrick   if (ignoreReport(CallLoc, Opts, ET))
1723cab2bb3Spatrick     return true;
1733cab2bb3Spatrick 
1743cab2bb3Spatrick   ScopedReport R(Opts, CallLoc, ET);
1753cab2bb3Spatrick 
1763cab2bb3Spatrick   SymbolizedStackHolder FLoc(getSymbolizedLocation(Function));
1773cab2bb3Spatrick   const char *FName = FLoc.get()->info.function;
1783cab2bb3Spatrick   if (!FName)
1793cab2bb3Spatrick     FName = "(unknown)";
1803cab2bb3Spatrick 
1813cab2bb3Spatrick   Diag(CallLoc, DL_Error, ET,
1823cab2bb3Spatrick        "call to function %0 through pointer to incorrect function type %1")
1833cab2bb3Spatrick       << FName << Data->Type;
1843cab2bb3Spatrick   Diag(FLoc, DL_Note, ET, "%0 defined here") << FName;
1853cab2bb3Spatrick   return true;
1863cab2bb3Spatrick }
1873cab2bb3Spatrick 
__ubsan_handle_function_type_mismatch_v1(FunctionTypeMismatchData * Data,ValueHandle Function,ValueHandle calleeRTTI,ValueHandle fnRTTI)1883cab2bb3Spatrick void __ubsan_handle_function_type_mismatch_v1(FunctionTypeMismatchData *Data,
1893cab2bb3Spatrick                                               ValueHandle Function,
1903cab2bb3Spatrick                                               ValueHandle calleeRTTI,
1913cab2bb3Spatrick                                               ValueHandle fnRTTI) {
1923cab2bb3Spatrick   GET_REPORT_OPTIONS(false);
1933cab2bb3Spatrick   handleFunctionTypeMismatch(Data, Function, calleeRTTI, fnRTTI, Opts);
1943cab2bb3Spatrick }
1953cab2bb3Spatrick 
__ubsan_handle_function_type_mismatch_v1_abort(FunctionTypeMismatchData * Data,ValueHandle Function,ValueHandle calleeRTTI,ValueHandle fnRTTI)1963cab2bb3Spatrick void __ubsan_handle_function_type_mismatch_v1_abort(
1973cab2bb3Spatrick     FunctionTypeMismatchData *Data, ValueHandle Function,
1983cab2bb3Spatrick     ValueHandle calleeRTTI, ValueHandle fnRTTI) {
1993cab2bb3Spatrick   GET_REPORT_OPTIONS(true);
2003cab2bb3Spatrick   if (handleFunctionTypeMismatch(Data, Function, calleeRTTI, fnRTTI, Opts))
2013cab2bb3Spatrick     Die();
2023cab2bb3Spatrick }
2033cab2bb3Spatrick }  // namespace __ubsan
2043cab2bb3Spatrick 
2053cab2bb3Spatrick #endif // CAN_SANITIZE_UB
206