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