xref: /freebsd/contrib/llvm-project/compiler-rt/lib/ubsan/ubsan_handlers_cxx.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
168d75effSDimitry Andric //===-- ubsan_handlers_cxx.cpp --------------------------------------------===//
268d75effSDimitry Andric //
368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
668d75effSDimitry Andric //
768d75effSDimitry Andric //===----------------------------------------------------------------------===//
868d75effSDimitry Andric //
968d75effSDimitry Andric // Error logging entry points for the UBSan runtime, which are only used for C++
1068d75effSDimitry Andric // compilations. This file is permitted to use language features which require
1168d75effSDimitry Andric // linking against a C++ ABI library.
1268d75effSDimitry Andric //
1368d75effSDimitry Andric //===----------------------------------------------------------------------===//
1468d75effSDimitry Andric 
1568d75effSDimitry Andric #include "ubsan_platform.h"
1668d75effSDimitry Andric #if CAN_SANITIZE_UB
1768d75effSDimitry Andric #include "ubsan_handlers.h"
1868d75effSDimitry Andric #include "ubsan_handlers_cxx.h"
1968d75effSDimitry Andric #include "ubsan_diag.h"
2068d75effSDimitry Andric #include "ubsan_type_hash.h"
2168d75effSDimitry Andric 
2268d75effSDimitry Andric #include "sanitizer_common/sanitizer_common.h"
2368d75effSDimitry Andric #include "sanitizer_common/sanitizer_suppressions.h"
2468d75effSDimitry Andric 
2568d75effSDimitry Andric using namespace __sanitizer;
2668d75effSDimitry Andric using namespace __ubsan;
2768d75effSDimitry Andric 
2868d75effSDimitry Andric namespace __ubsan {
29*bdd1243dSDimitry Andric   extern const char *const TypeCheckKinds[];
3068d75effSDimitry Andric }
3168d75effSDimitry Andric 
3268d75effSDimitry Andric // Returns true if UBSan has printed an error report.
HandleDynamicTypeCacheMiss(DynamicTypeCacheMissData * Data,ValueHandle Pointer,ValueHandle Hash,ReportOptions Opts)3368d75effSDimitry Andric static bool HandleDynamicTypeCacheMiss(
3468d75effSDimitry Andric     DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash,
3568d75effSDimitry Andric     ReportOptions Opts) {
3668d75effSDimitry Andric   if (checkDynamicType((void*)Pointer, Data->TypeInfo, Hash))
3768d75effSDimitry Andric     // Just a cache miss. The type matches after all.
3868d75effSDimitry Andric     return false;
3968d75effSDimitry Andric 
4068d75effSDimitry Andric   // Check if error report should be suppressed.
4168d75effSDimitry Andric   DynamicTypeInfo DTI = getDynamicTypeInfoFromObject((void*)Pointer);
4268d75effSDimitry Andric   if (DTI.isValid() && IsVptrCheckSuppressed(DTI.getMostDerivedTypeName()))
4368d75effSDimitry Andric     return false;
4468d75effSDimitry Andric 
4568d75effSDimitry Andric   SourceLocation Loc = Data->Loc.acquire();
4668d75effSDimitry Andric   ErrorType ET = ErrorType::DynamicTypeMismatch;
4768d75effSDimitry Andric   if (ignoreReport(Loc, Opts, ET))
4868d75effSDimitry Andric     return false;
4968d75effSDimitry Andric 
5068d75effSDimitry Andric   ScopedReport R(Opts, Loc, ET);
5168d75effSDimitry Andric 
5268d75effSDimitry Andric   Diag(Loc, DL_Error, ET,
5368d75effSDimitry Andric        "%0 address %1 which does not point to an object of type %2")
5468d75effSDimitry Andric     << TypeCheckKinds[Data->TypeCheckKind] << (void*)Pointer << Data->Type;
5568d75effSDimitry Andric 
5668d75effSDimitry Andric   // If possible, say what type it actually points to.
5768d75effSDimitry Andric   if (!DTI.isValid()) {
5868d75effSDimitry Andric     if (DTI.getOffset() < -VptrMaxOffsetToTop || DTI.getOffset() > VptrMaxOffsetToTop) {
5968d75effSDimitry Andric       Diag(Pointer, DL_Note, ET,
6068d75effSDimitry Andric            "object has a possibly invalid vptr: abs(offset to top) too big")
6168d75effSDimitry Andric           << TypeName(DTI.getMostDerivedTypeName())
6268d75effSDimitry Andric           << Range(Pointer, Pointer + sizeof(uptr), "possibly invalid vptr");
6368d75effSDimitry Andric     } else {
6468d75effSDimitry Andric       Diag(Pointer, DL_Note, ET, "object has invalid vptr")
6568d75effSDimitry Andric           << TypeName(DTI.getMostDerivedTypeName())
6668d75effSDimitry Andric           << Range(Pointer, Pointer + sizeof(uptr), "invalid vptr");
6768d75effSDimitry Andric     }
6868d75effSDimitry Andric   } else if (!DTI.getOffset())
6968d75effSDimitry Andric     Diag(Pointer, DL_Note, ET, "object is of type %0")
7068d75effSDimitry Andric         << TypeName(DTI.getMostDerivedTypeName())
7168d75effSDimitry Andric         << Range(Pointer, Pointer + sizeof(uptr), "vptr for %0");
7268d75effSDimitry Andric   else
7368d75effSDimitry Andric     // FIXME: Find the type at the specified offset, and include that
7468d75effSDimitry Andric     //        in the note.
7568d75effSDimitry Andric     Diag(Pointer - DTI.getOffset(), DL_Note, ET,
7668d75effSDimitry Andric          "object is base class subobject at offset %0 within object of type %1")
7768d75effSDimitry Andric         << DTI.getOffset() << TypeName(DTI.getMostDerivedTypeName())
7868d75effSDimitry Andric         << TypeName(DTI.getSubobjectTypeName())
7968d75effSDimitry Andric         << Range(Pointer, Pointer + sizeof(uptr),
8068d75effSDimitry Andric                  "vptr for %2 base class of %1");
8168d75effSDimitry Andric   return true;
8268d75effSDimitry Andric }
8368d75effSDimitry Andric 
__ubsan_handle_dynamic_type_cache_miss(DynamicTypeCacheMissData * Data,ValueHandle Pointer,ValueHandle Hash)8468d75effSDimitry Andric void __ubsan::__ubsan_handle_dynamic_type_cache_miss(
8568d75effSDimitry Andric     DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash) {
8668d75effSDimitry Andric   GET_REPORT_OPTIONS(false);
8768d75effSDimitry Andric   HandleDynamicTypeCacheMiss(Data, Pointer, Hash, Opts);
8868d75effSDimitry Andric }
__ubsan_handle_dynamic_type_cache_miss_abort(DynamicTypeCacheMissData * Data,ValueHandle Pointer,ValueHandle Hash)8968d75effSDimitry Andric void __ubsan::__ubsan_handle_dynamic_type_cache_miss_abort(
9068d75effSDimitry Andric     DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash) {
9168d75effSDimitry Andric   // Note: -fsanitize=vptr is always recoverable.
9268d75effSDimitry Andric   GET_REPORT_OPTIONS(false);
9368d75effSDimitry Andric   if (HandleDynamicTypeCacheMiss(Data, Pointer, Hash, Opts))
9468d75effSDimitry Andric     Die();
9568d75effSDimitry Andric }
9668d75effSDimitry Andric 
9768d75effSDimitry Andric namespace __ubsan {
__ubsan_handle_cfi_bad_type(CFICheckFailData * Data,ValueHandle Vtable,bool ValidVtable,ReportOptions Opts)9868d75effSDimitry Andric void __ubsan_handle_cfi_bad_type(CFICheckFailData *Data, ValueHandle Vtable,
9968d75effSDimitry Andric                                  bool ValidVtable, ReportOptions Opts) {
10068d75effSDimitry Andric   SourceLocation Loc = Data->Loc.acquire();
10168d75effSDimitry Andric   ErrorType ET = ErrorType::CFIBadType;
10268d75effSDimitry Andric 
10368d75effSDimitry Andric   if (ignoreReport(Loc, Opts, ET))
10468d75effSDimitry Andric     return;
10568d75effSDimitry Andric 
10668d75effSDimitry Andric   ScopedReport R(Opts, Loc, ET);
10768d75effSDimitry Andric   DynamicTypeInfo DTI = ValidVtable
10868d75effSDimitry Andric                             ? getDynamicTypeInfoFromVtable((void *)Vtable)
10968d75effSDimitry Andric                             : DynamicTypeInfo(0, 0, 0);
11068d75effSDimitry Andric 
11168d75effSDimitry Andric   const char *CheckKindStr;
11268d75effSDimitry Andric   switch (Data->CheckKind) {
11368d75effSDimitry Andric   case CFITCK_VCall:
11468d75effSDimitry Andric     CheckKindStr = "virtual call";
11568d75effSDimitry Andric     break;
11668d75effSDimitry Andric   case CFITCK_NVCall:
11768d75effSDimitry Andric     CheckKindStr = "non-virtual call";
11868d75effSDimitry Andric     break;
11968d75effSDimitry Andric   case CFITCK_DerivedCast:
12068d75effSDimitry Andric     CheckKindStr = "base-to-derived cast";
12168d75effSDimitry Andric     break;
12268d75effSDimitry Andric   case CFITCK_UnrelatedCast:
12368d75effSDimitry Andric     CheckKindStr = "cast to unrelated type";
12468d75effSDimitry Andric     break;
12568d75effSDimitry Andric   case CFITCK_VMFCall:
12668d75effSDimitry Andric     CheckKindStr = "virtual pointer to member function call";
12768d75effSDimitry Andric     break;
12868d75effSDimitry Andric   case CFITCK_ICall:
12968d75effSDimitry Andric   case CFITCK_NVMFCall:
13068d75effSDimitry Andric     Die();
13168d75effSDimitry Andric   }
13268d75effSDimitry Andric 
13368d75effSDimitry Andric   Diag(Loc, DL_Error, ET,
13468d75effSDimitry Andric        "control flow integrity check for type %0 failed during "
13568d75effSDimitry Andric        "%1 (vtable address %2)")
13668d75effSDimitry Andric       << Data->Type << CheckKindStr << (void *)Vtable;
13768d75effSDimitry Andric 
13868d75effSDimitry Andric   // If possible, say what type it actually points to.
13968d75effSDimitry Andric   if (!DTI.isValid())
14068d75effSDimitry Andric     Diag(Vtable, DL_Note, ET, "invalid vtable");
14168d75effSDimitry Andric   else
14268d75effSDimitry Andric     Diag(Vtable, DL_Note, ET, "vtable is of type %0")
14368d75effSDimitry Andric         << TypeName(DTI.getMostDerivedTypeName());
14468d75effSDimitry Andric 
14568d75effSDimitry Andric   // If the failure involved different DSOs for the check location and vtable,
14668d75effSDimitry Andric   // report the DSO names.
14768d75effSDimitry Andric   const char *DstModule = Symbolizer::GetOrInit()->GetModuleNameForPc(Vtable);
14868d75effSDimitry Andric   if (!DstModule)
14968d75effSDimitry Andric     DstModule = "(unknown)";
15068d75effSDimitry Andric 
15168d75effSDimitry Andric   const char *SrcModule = Symbolizer::GetOrInit()->GetModuleNameForPc(Opts.pc);
15268d75effSDimitry Andric   if (!SrcModule)
15368d75effSDimitry Andric     SrcModule = "(unknown)";
15468d75effSDimitry Andric 
15568d75effSDimitry Andric   if (internal_strcmp(SrcModule, DstModule))
15668d75effSDimitry Andric     Diag(Loc, DL_Note, ET, "check failed in %0, vtable located in %1")
15768d75effSDimitry Andric         << SrcModule << DstModule;
15868d75effSDimitry Andric }
15968d75effSDimitry Andric }  // namespace __ubsan
16068d75effSDimitry Andric 
16168d75effSDimitry Andric #endif // CAN_SANITIZE_UB
162