1eda8bd0fc07df35c9ad7de5b698bb717b063e7afRichard Smith//===-- ubsan_handlers_cxx.cc ---------------------------------------------===//
2eda8bd0fc07df35c9ad7de5b698bb717b063e7afRichard Smith//
3eda8bd0fc07df35c9ad7de5b698bb717b063e7afRichard Smith//                     The LLVM Compiler Infrastructure
4eda8bd0fc07df35c9ad7de5b698bb717b063e7afRichard Smith//
5eda8bd0fc07df35c9ad7de5b698bb717b063e7afRichard Smith// This file is distributed under the University of Illinois Open Source
6eda8bd0fc07df35c9ad7de5b698bb717b063e7afRichard Smith// License. See LICENSE.TXT for details.
7eda8bd0fc07df35c9ad7de5b698bb717b063e7afRichard Smith//
8eda8bd0fc07df35c9ad7de5b698bb717b063e7afRichard Smith//===----------------------------------------------------------------------===//
9eda8bd0fc07df35c9ad7de5b698bb717b063e7afRichard Smith//
10eda8bd0fc07df35c9ad7de5b698bb717b063e7afRichard Smith// Error logging entry points for the UBSan runtime, which are only used for C++
11eda8bd0fc07df35c9ad7de5b698bb717b063e7afRichard Smith// compilations. This file is permitted to use language features which require
12eda8bd0fc07df35c9ad7de5b698bb717b063e7afRichard Smith// linking against a C++ ABI library.
13eda8bd0fc07df35c9ad7de5b698bb717b063e7afRichard Smith//
14eda8bd0fc07df35c9ad7de5b698bb717b063e7afRichard Smith//===----------------------------------------------------------------------===//
15eda8bd0fc07df35c9ad7de5b698bb717b063e7afRichard Smith
167c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar#include "ubsan_platform.h"
177c9150579ed0278492f51cc8434b1d63a44b9bd1Pirama Arumuga Nainar#if CAN_SANITIZE_UB
18c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar#include "ubsan_handlers.h"
19eda8bd0fc07df35c9ad7de5b698bb717b063e7afRichard Smith#include "ubsan_handlers_cxx.h"
20eda8bd0fc07df35c9ad7de5b698bb717b063e7afRichard Smith#include "ubsan_diag.h"
21eda8bd0fc07df35c9ad7de5b698bb717b063e7afRichard Smith#include "ubsan_type_hash.h"
22eda8bd0fc07df35c9ad7de5b698bb717b063e7afRichard Smith
23eda8bd0fc07df35c9ad7de5b698bb717b063e7afRichard Smith#include "sanitizer_common/sanitizer_common.h"
246d1862363c88c183b0ed7740fca876342cf0474bStephen Hines#include "sanitizer_common/sanitizer_suppressions.h"
25eda8bd0fc07df35c9ad7de5b698bb717b063e7afRichard Smith
26eda8bd0fc07df35c9ad7de5b698bb717b063e7afRichard Smithusing namespace __sanitizer;
27eda8bd0fc07df35c9ad7de5b698bb717b063e7afRichard Smithusing namespace __ubsan;
28eda8bd0fc07df35c9ad7de5b698bb717b063e7afRichard Smith
29eda8bd0fc07df35c9ad7de5b698bb717b063e7afRichard Smithnamespace __ubsan {
30eda8bd0fc07df35c9ad7de5b698bb717b063e7afRichard Smith  extern const char *TypeCheckKinds[];
31eda8bd0fc07df35c9ad7de5b698bb717b063e7afRichard Smith}
32eda8bd0fc07df35c9ad7de5b698bb717b063e7afRichard Smith
33799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar// Returns true if UBSan has printed an error report.
34799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainarstatic bool HandleDynamicTypeCacheMiss(
3525ee97fe8ada76755c8bd1087fac9cc3cd03b28cRichard Smith    DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash,
366d1862363c88c183b0ed7740fca876342cf0474bStephen Hines    ReportOptions Opts) {
37eda8bd0fc07df35c9ad7de5b698bb717b063e7afRichard Smith  if (checkDynamicType((void*)Pointer, Data->TypeInfo, Hash))
38eda8bd0fc07df35c9ad7de5b698bb717b063e7afRichard Smith    // Just a cache miss. The type matches after all.
39799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar    return false;
40eda8bd0fc07df35c9ad7de5b698bb717b063e7afRichard Smith
416d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  // Check if error report should be suppressed.
42799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar  DynamicTypeInfo DTI = getDynamicTypeInfoFromObject((void*)Pointer);
4386277eb844c4983c81de62d7c050e92fe7155788Stephen Hines  if (DTI.isValid() && IsVptrCheckSuppressed(DTI.getMostDerivedTypeName()))
44799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar    return false;
456d1862363c88c183b0ed7740fca876342cf0474bStephen Hines
462af552f98f980178db37eed28a609b6bf55f6df8Will Dietz  SourceLocation Loc = Data->Loc.acquire();
47799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar  ErrorType ET = ErrorType::DynamicTypeMismatch;
48799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar  if (ignoreReport(Loc, Opts, ET))
49799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar    return false;
502af552f98f980178db37eed28a609b6bf55f6df8Will Dietz
51799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar  ScopedReport R(Opts, Loc, ET);
526d1862363c88c183b0ed7740fca876342cf0474bStephen Hines
532af552f98f980178db37eed28a609b6bf55f6df8Will Dietz  Diag(Loc, DL_Error,
5425ee97fe8ada76755c8bd1087fac9cc3cd03b28cRichard Smith       "%0 address %1 which does not point to an object of type %2")
55eda8bd0fc07df35c9ad7de5b698bb717b063e7afRichard Smith    << TypeCheckKinds[Data->TypeCheckKind] << (void*)Pointer << Data->Type;
5625ee97fe8ada76755c8bd1087fac9cc3cd03b28cRichard Smith
5725ee97fe8ada76755c8bd1087fac9cc3cd03b28cRichard Smith  // If possible, say what type it actually points to.
58c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar  if (!DTI.isValid()) {
59c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar    if (DTI.getOffset() < -VptrMaxOffsetToTop || DTI.getOffset() > VptrMaxOffsetToTop) {
60c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar      Diag(Pointer, DL_Note, "object has a possibly invalid vptr: abs(offset to top) too big")
61c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar          << TypeName(DTI.getMostDerivedTypeName())
62c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar          << Range(Pointer, Pointer + sizeof(uptr), "possibly invalid vptr");
63c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar    } else {
64c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar      Diag(Pointer, DL_Note, "object has invalid vptr")
65c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar          << TypeName(DTI.getMostDerivedTypeName())
66c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar          << Range(Pointer, Pointer + sizeof(uptr), "invalid vptr");
67c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar    }
68c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar  } else if (!DTI.getOffset())
6925ee97fe8ada76755c8bd1087fac9cc3cd03b28cRichard Smith    Diag(Pointer, DL_Note, "object is of type %0")
70799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar        << TypeName(DTI.getMostDerivedTypeName())
716d1862363c88c183b0ed7740fca876342cf0474bStephen Hines        << Range(Pointer, Pointer + sizeof(uptr), "vptr for %0");
7225ee97fe8ada76755c8bd1087fac9cc3cd03b28cRichard Smith  else
730ad23f7f860e27b8b9a889be665cfaea830503ceRichard Smith    // FIXME: Find the type at the specified offset, and include that
740ad23f7f860e27b8b9a889be665cfaea830503ceRichard Smith    //        in the note.
7525ee97fe8ada76755c8bd1087fac9cc3cd03b28cRichard Smith    Diag(Pointer - DTI.getOffset(), DL_Note,
7625ee97fe8ada76755c8bd1087fac9cc3cd03b28cRichard Smith         "object is base class subobject at offset %0 within object of type %1")
77799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar        << DTI.getOffset() << TypeName(DTI.getMostDerivedTypeName())
78799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar        << TypeName(DTI.getSubobjectTypeName())
796d1862363c88c183b0ed7740fca876342cf0474bStephen Hines        << Range(Pointer, Pointer + sizeof(uptr),
806d1862363c88c183b0ed7740fca876342cf0474bStephen Hines                 "vptr for %2 base class of %1");
81799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar  return true;
82a82a5d360b19080f2b1beae374c12d4f26146450Will Dietz}
83a82a5d360b19080f2b1beae374c12d4f26146450Will Dietz
84a82a5d360b19080f2b1beae374c12d4f26146450Will Dietzvoid __ubsan::__ubsan_handle_dynamic_type_cache_miss(
8525ee97fe8ada76755c8bd1087fac9cc3cd03b28cRichard Smith    DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash) {
866d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  GET_REPORT_OPTIONS(false);
876d1862363c88c183b0ed7740fca876342cf0474bStephen Hines  HandleDynamicTypeCacheMiss(Data, Pointer, Hash, Opts);
88a82a5d360b19080f2b1beae374c12d4f26146450Will Dietz}
89a82a5d360b19080f2b1beae374c12d4f26146450Will Dietzvoid __ubsan::__ubsan_handle_dynamic_type_cache_miss_abort(
9025ee97fe8ada76755c8bd1087fac9cc3cd03b28cRichard Smith    DynamicTypeCacheMissData *Data, ValueHandle Pointer, ValueHandle Hash) {
91799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar  // Note: -fsanitize=vptr is always recoverable.
92799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar  GET_REPORT_OPTIONS(false);
93799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar  if (HandleDynamicTypeCacheMiss(Data, Pointer, Hash, Opts))
94799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar    Die();
95799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar}
96799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar
97c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainarnamespace __ubsan {
98c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainarvoid HandleCFIBadType(CFICheckFailData *Data, ValueHandle Vtable,
99c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar                      bool ValidVtable, ReportOptions Opts) {
100799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar  SourceLocation Loc = Data->Loc.acquire();
101799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar  ErrorType ET = ErrorType::CFIBadType;
102799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar
103799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar  if (ignoreReport(Loc, Opts, ET))
104799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar    return;
105799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar
106799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar  ScopedReport R(Opts, Loc, ET);
107c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar  DynamicTypeInfo DTI = ValidVtable
108c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar                            ? getDynamicTypeInfoFromVtable((void *)Vtable)
109c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar                            : DynamicTypeInfo(0, 0, 0);
110c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar
111c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar  const char *CheckKindStr;
112c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar  switch (Data->CheckKind) {
113c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar  case CFITCK_VCall:
114c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar    CheckKindStr = "virtual call";
115c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar    break;
116c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar  case CFITCK_NVCall:
117c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar    CheckKindStr = "non-virtual call";
118c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar    break;
119c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar  case CFITCK_DerivedCast:
120c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar    CheckKindStr = "base-to-derived cast";
121c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar    break;
122c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar  case CFITCK_UnrelatedCast:
123c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar    CheckKindStr = "cast to unrelated type";
124c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar    break;
125c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar  case CFITCK_ICall:
126c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar    Die();
127c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar  }
128799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar
129799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar  Diag(Loc, DL_Error, "control flow integrity check for type %0 failed during "
130799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar                      "%1 (vtable address %2)")
131c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar      << Data->Type << CheckKindStr << (void *)Vtable;
132799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar
133799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar  // If possible, say what type it actually points to.
134c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar  if (!DTI.isValid()) {
135c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar    const char *module = Symbolizer::GetOrInit()->GetModuleNameForPc(Vtable);
136c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar    if (module)
137c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar      Diag(Vtable, DL_Note, "invalid vtable in module %0") << module;
138c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar    else
139c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar      Diag(Vtable, DL_Note, "invalid vtable");
140c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar  } else {
141799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar    Diag(Vtable, DL_Note, "vtable is of type %0")
142799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar        << TypeName(DTI.getMostDerivedTypeName());
143c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar  }
144799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar}
145c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar}  // namespace __ubsan
146799172d60d32feb1acba1a6867f3a9c39a999e5cPirama Arumuga Nainar
147c58a43648cd6121c51a2e795a28e2ef90d7813e6Pirama Arumuga Nainar#endif // CAN_SANITIZE_UB
148