ubsan_diag.h 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266
  1. //===-- ubsan_diag.h --------------------------------------------*- C++ -*-===//
  2. //
  3. // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
  4. // See https://llvm.org/LICENSE.txt for license information.
  5. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. //
  9. // Diagnostics emission for Clang's undefined behavior sanitizer.
  10. //
  11. //===----------------------------------------------------------------------===//
  12. #ifndef UBSAN_DIAG_H
  13. #define UBSAN_DIAG_H
  14. #include "ubsan_value.h"
  15. #include "sanitizer_common/sanitizer_stacktrace.h"
  16. #include "sanitizer_common/sanitizer_symbolizer.h"
  17. namespace __ubsan {
  18. class SymbolizedStackHolder {
  19. SymbolizedStack *Stack;
  20. void clear() {
  21. if (Stack)
  22. Stack->ClearAll();
  23. }
  24. public:
  25. explicit SymbolizedStackHolder(SymbolizedStack *Stack = nullptr)
  26. : Stack(Stack) {}
  27. ~SymbolizedStackHolder() { clear(); }
  28. void reset(SymbolizedStack *S) {
  29. if (Stack != S)
  30. clear();
  31. Stack = S;
  32. }
  33. const SymbolizedStack *get() const { return Stack; }
  34. };
  35. SymbolizedStack *getSymbolizedLocation(uptr PC);
  36. inline SymbolizedStack *getCallerLocation(uptr CallerPC) {
  37. CHECK(CallerPC);
  38. uptr PC = StackTrace::GetPreviousInstructionPc(CallerPC);
  39. return getSymbolizedLocation(PC);
  40. }
  41. /// A location of some data within the program's address space.
  42. typedef uptr MemoryLocation;
  43. /// \brief Location at which a diagnostic can be emitted. Either a
  44. /// SourceLocation, a MemoryLocation, or a SymbolizedStack.
  45. class Location {
  46. public:
  47. enum LocationKind { LK_Null, LK_Source, LK_Memory, LK_Symbolized };
  48. private:
  49. LocationKind Kind;
  50. // FIXME: In C++11, wrap these in an anonymous union.
  51. SourceLocation SourceLoc;
  52. MemoryLocation MemoryLoc;
  53. const SymbolizedStack *SymbolizedLoc; // Not owned.
  54. public:
  55. Location() : Kind(LK_Null) {}
  56. Location(SourceLocation Loc) :
  57. Kind(LK_Source), SourceLoc(Loc) {}
  58. Location(MemoryLocation Loc) :
  59. Kind(LK_Memory), MemoryLoc(Loc) {}
  60. // SymbolizedStackHolder must outlive Location object.
  61. Location(const SymbolizedStackHolder &Stack) :
  62. Kind(LK_Symbolized), SymbolizedLoc(Stack.get()) {}
  63. LocationKind getKind() const { return Kind; }
  64. bool isSourceLocation() const { return Kind == LK_Source; }
  65. bool isMemoryLocation() const { return Kind == LK_Memory; }
  66. bool isSymbolizedStack() const { return Kind == LK_Symbolized; }
  67. SourceLocation getSourceLocation() const {
  68. CHECK(isSourceLocation());
  69. return SourceLoc;
  70. }
  71. MemoryLocation getMemoryLocation() const {
  72. CHECK(isMemoryLocation());
  73. return MemoryLoc;
  74. }
  75. const SymbolizedStack *getSymbolizedStack() const {
  76. CHECK(isSymbolizedStack());
  77. return SymbolizedLoc;
  78. }
  79. };
  80. /// A diagnostic severity level.
  81. enum DiagLevel {
  82. DL_Error, ///< An error.
  83. DL_Note ///< A note, attached to a prior diagnostic.
  84. };
  85. /// \brief Annotation for a range of locations in a diagnostic.
  86. class Range {
  87. Location Start, End;
  88. const char *Text;
  89. public:
  90. Range() : Start(), End(), Text() {}
  91. Range(MemoryLocation Start, MemoryLocation End, const char *Text)
  92. : Start(Start), End(End), Text(Text) {}
  93. Location getStart() const { return Start; }
  94. Location getEnd() const { return End; }
  95. const char *getText() const { return Text; }
  96. };
  97. /// \brief A C++ type name. Really just a strong typedef for 'const char*'.
  98. class TypeName {
  99. const char *Name;
  100. public:
  101. TypeName(const char *Name) : Name(Name) {}
  102. const char *getName() const { return Name; }
  103. };
  104. enum class ErrorType {
  105. #define UBSAN_CHECK(Name, SummaryKind, FSanitizeFlagName) Name,
  106. #include "ubsan_checks.inc"
  107. #undef UBSAN_CHECK
  108. };
  109. /// \brief Representation of an in-flight diagnostic.
  110. ///
  111. /// Temporary \c Diag instances are created by the handler routines to
  112. /// accumulate arguments for a diagnostic. The destructor emits the diagnostic
  113. /// message.
  114. class Diag {
  115. /// The location at which the problem occurred.
  116. Location Loc;
  117. /// The diagnostic level.
  118. DiagLevel Level;
  119. /// The error type.
  120. ErrorType ET;
  121. /// The message which will be emitted, with %0, %1, ... placeholders for
  122. /// arguments.
  123. const char *Message;
  124. public:
  125. /// Kinds of arguments, corresponding to members of \c Arg's union.
  126. enum ArgKind {
  127. AK_String, ///< A string argument, displayed as-is.
  128. AK_TypeName,///< A C++ type name, possibly demangled before display.
  129. AK_UInt, ///< An unsigned integer argument.
  130. AK_SInt, ///< A signed integer argument.
  131. AK_Float, ///< A floating-point argument.
  132. AK_Pointer ///< A pointer argument, displayed in hexadecimal.
  133. };
  134. /// An individual diagnostic message argument.
  135. struct Arg {
  136. Arg() {}
  137. Arg(const char *String) : Kind(AK_String), String(String) {}
  138. Arg(TypeName TN) : Kind(AK_TypeName), String(TN.getName()) {}
  139. Arg(UIntMax UInt) : Kind(AK_UInt), UInt(UInt) {}
  140. Arg(SIntMax SInt) : Kind(AK_SInt), SInt(SInt) {}
  141. Arg(FloatMax Float) : Kind(AK_Float), Float(Float) {}
  142. Arg(const void *Pointer) : Kind(AK_Pointer), Pointer(Pointer) {}
  143. ArgKind Kind;
  144. union {
  145. const char *String;
  146. UIntMax UInt;
  147. SIntMax SInt;
  148. FloatMax Float;
  149. const void *Pointer;
  150. };
  151. };
  152. private:
  153. static const unsigned MaxArgs = 8;
  154. static const unsigned MaxRanges = 1;
  155. /// The arguments which have been added to this diagnostic so far.
  156. Arg Args[MaxArgs];
  157. unsigned NumArgs;
  158. /// The ranges which have been added to this diagnostic so far.
  159. Range Ranges[MaxRanges];
  160. unsigned NumRanges;
  161. Diag &AddArg(Arg A) {
  162. CHECK(NumArgs != MaxArgs);
  163. Args[NumArgs++] = A;
  164. return *this;
  165. }
  166. Diag &AddRange(Range A) {
  167. CHECK(NumRanges != MaxRanges);
  168. Ranges[NumRanges++] = A;
  169. return *this;
  170. }
  171. /// \c Diag objects are not copyable.
  172. Diag(const Diag &); // NOT IMPLEMENTED
  173. Diag &operator=(const Diag &);
  174. public:
  175. Diag(Location Loc, DiagLevel Level, ErrorType ET, const char *Message)
  176. : Loc(Loc), Level(Level), ET(ET), Message(Message), NumArgs(0),
  177. NumRanges(0) {}
  178. ~Diag();
  179. Diag &operator<<(const char *Str) { return AddArg(Str); }
  180. Diag &operator<<(TypeName TN) { return AddArg(TN); }
  181. Diag &operator<<(unsigned long long V) { return AddArg(UIntMax(V)); }
  182. Diag &operator<<(const void *V) { return AddArg(V); }
  183. Diag &operator<<(const TypeDescriptor &V);
  184. Diag &operator<<(const Value &V);
  185. Diag &operator<<(const Range &R) { return AddRange(R); }
  186. };
  187. struct ReportOptions {
  188. // If FromUnrecoverableHandler is specified, UBSan runtime handler is not
  189. // expected to return.
  190. bool FromUnrecoverableHandler;
  191. /// pc/bp are used to unwind the stack trace.
  192. uptr pc;
  193. uptr bp;
  194. };
  195. bool ignoreReport(SourceLocation SLoc, ReportOptions Opts, ErrorType ET);
  196. #define GET_REPORT_OPTIONS(unrecoverable_handler) \
  197. GET_CALLER_PC_BP; \
  198. ReportOptions Opts = {unrecoverable_handler, pc, bp}
  199. /// \brief Instantiate this class before printing diagnostics in the error
  200. /// report. This class ensures that reports from different threads and from
  201. /// different sanitizers won't be mixed.
  202. class ScopedReport {
  203. struct Initializer {
  204. Initializer();
  205. };
  206. Initializer initializer_;
  207. ScopedErrorReportLock report_lock_;
  208. ReportOptions Opts;
  209. Location SummaryLoc;
  210. ErrorType Type;
  211. public:
  212. ScopedReport(ReportOptions Opts, Location SummaryLoc, ErrorType Type);
  213. ~ScopedReport();
  214. static void CheckLocked() { ScopedErrorReportLock::CheckLocked(); }
  215. };
  216. void InitializeSuppressions();
  217. bool IsVptrCheckSuppressed(const char *TypeName);
  218. // Sometimes UBSan runtime can know filename from handlers arguments, even if
  219. // debug info is missing.
  220. bool IsPCSuppressed(ErrorType ET, uptr PC, const char *Filename);
  221. } // namespace __ubsan
  222. #endif // UBSAN_DIAG_H