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