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