1//===-- ubsan_handlers_cxx.cc ---------------------------------------------===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9// 10// Error logging entry points for the UBSan runtime, which are only used for C++ 11// compilations. This file is permitted to use language features which require 12// linking against a C++ ABI library. 13// 14//===----------------------------------------------------------------------===// 15 16#include "ubsan_platform.h" 17#if CAN_SANITIZE_UB 18#include "ubsan_handlers.h" 19#include "ubsan_handlers_cxx.h" 20#include "ubsan_diag.h" 21#include "ubsan_type_hash.h" 22 23#include "sanitizer_common/sanitizer_common.h" 24#include "sanitizer_common/sanitizer_suppressions.h" 25 26using namespace __sanitizer; 27using namespace __ubsan; 28 29namespace __ubsan { 30 extern const char *TypeCheckKinds[]; 31} 32 33// Returns true if UBSan has printed an error report. 34static bool HandleDynamicTypeCacheMiss( 35 DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash, 36 ReportOptions Opts) { 37 if (checkDynamicType((void*)Pointer, Data->TypeInfo, Hash)) 38 // Just a cache miss. The type matches after all. 39 return false; 40 41 // Check if error report should be suppressed. 42 DynamicTypeInfo DTI = getDynamicTypeInfoFromObject((void*)Pointer); 43 if (DTI.isValid() && IsVptrCheckSuppressed(DTI.getMostDerivedTypeName())) 44 return false; 45 46 SourceLocation Loc = Data->Loc.acquire(); 47 ErrorType ET = ErrorType::DynamicTypeMismatch; 48 if (ignoreReport(Loc, Opts, ET)) 49 return false; 50 51 ScopedReport R(Opts, Loc, ET); 52 53 Diag(Loc, DL_Error, 54 "%0 address %1 which does not point to an object of type %2") 55 << TypeCheckKinds[Data->TypeCheckKind] << (void*)Pointer << Data->Type; 56 57 // If possible, say what type it actually points to. 58 if (!DTI.isValid()) { 59 if (DTI.getOffset() < -VptrMaxOffsetToTop || DTI.getOffset() > VptrMaxOffsetToTop) { 60 Diag(Pointer, DL_Note, "object has a possibly invalid vptr: abs(offset to top) too big") 61 << TypeName(DTI.getMostDerivedTypeName()) 62 << Range(Pointer, Pointer + sizeof(uptr), "possibly invalid vptr"); 63 } else { 64 Diag(Pointer, DL_Note, "object has invalid vptr") 65 << TypeName(DTI.getMostDerivedTypeName()) 66 << Range(Pointer, Pointer + sizeof(uptr), "invalid vptr"); 67 } 68 } else if (!DTI.getOffset()) 69 Diag(Pointer, DL_Note, "object is of type %0") 70 << TypeName(DTI.getMostDerivedTypeName()) 71 << Range(Pointer, Pointer + sizeof(uptr), "vptr for %0"); 72 else 73 // FIXME: Find the type at the specified offset, and include that 74 // in the note. 75 Diag(Pointer - DTI.getOffset(), DL_Note, 76 "object is base class subobject at offset %0 within object of type %1") 77 << DTI.getOffset() << TypeName(DTI.getMostDerivedTypeName()) 78 << TypeName(DTI.getSubobjectTypeName()) 79 << Range(Pointer, Pointer + sizeof(uptr), 80 "vptr for %2 base class of %1"); 81 return true; 82} 83 84void __ubsan::__ubsan_handle_dynamic_type_cache_miss( 85 DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash) { 86 GET_REPORT_OPTIONS(false); 87 HandleDynamicTypeCacheMiss(Data, Pointer, Hash, Opts); 88} 89void __ubsan::__ubsan_handle_dynamic_type_cache_miss_abort( 90 DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash) { 91 // Note: -fsanitize=vptr is always recoverable. 92 GET_REPORT_OPTIONS(false); 93 if (HandleDynamicTypeCacheMiss(Data, Pointer, Hash, Opts)) 94 Die(); 95} 96 97namespace __ubsan { 98void HandleCFIBadType(CFICheckFailData *Data, ValueHandle Vtable, 99 bool ValidVtable, ReportOptions Opts) { 100 SourceLocation Loc = Data->Loc.acquire(); 101 ErrorType ET = ErrorType::CFIBadType; 102 103 if (ignoreReport(Loc, Opts, ET)) 104 return; 105 106 ScopedReport R(Opts, Loc, ET); 107 DynamicTypeInfo DTI = ValidVtable 108 ? getDynamicTypeInfoFromVtable((void *)Vtable) 109 : DynamicTypeInfo(0, 0, 0); 110 111 const char *CheckKindStr; 112 switch (Data->CheckKind) { 113 case CFITCK_VCall: 114 CheckKindStr = "virtual call"; 115 break; 116 case CFITCK_NVCall: 117 CheckKindStr = "non-virtual call"; 118 break; 119 case CFITCK_DerivedCast: 120 CheckKindStr = "base-to-derived cast"; 121 break; 122 case CFITCK_UnrelatedCast: 123 CheckKindStr = "cast to unrelated type"; 124 break; 125 case CFITCK_ICall: 126 Die(); 127 } 128 129 Diag(Loc, DL_Error, "control flow integrity check for type %0 failed during " 130 "%1 (vtable address %2)") 131 << Data->Type << CheckKindStr << (void *)Vtable; 132 133 // If possible, say what type it actually points to. 134 if (!DTI.isValid()) { 135 const char *module = Symbolizer::GetOrInit()->GetModuleNameForPc(Vtable); 136 if (module) 137 Diag(Vtable, DL_Note, "invalid vtable in module %0") << module; 138 else 139 Diag(Vtable, DL_Note, "invalid vtable"); 140 } else { 141 Diag(Vtable, DL_Note, "vtable is of type %0") 142 << TypeName(DTI.getMostDerivedTypeName()); 143 } 144} 145} // namespace __ubsan 146 147#endif // CAN_SANITIZE_UB 148