xref: /netbsd-src/external/gpl3/gcc.old/dist/libsanitizer/ubsan/ubsan_diag.h (revision aef5eb5f59cdfe8314f1b5f78ac04eb144e44010)
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 
23   void clear() {
24     if (Stack)
25       Stack->ClearAll();
26   }
27 
28 public:
29   explicit SymbolizedStackHolder(SymbolizedStack *Stack = nullptr)
30       : Stack(Stack) {}
31   ~SymbolizedStackHolder() { clear(); }
32   void reset(SymbolizedStack *S) {
33     if (Stack != S)
34       clear();
35     Stack = S;
36   }
37   const SymbolizedStack *get() const { return Stack; }
38 };
39 
40 SymbolizedStack *getSymbolizedLocation(uptr PC);
41 
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:
65   Location() : Kind(LK_Null) {}
66   Location(SourceLocation Loc) :
67     Kind(LK_Source), SourceLoc(Loc) {}
68   Location(MemoryLocation Loc) :
69     Kind(LK_Memory), MemoryLoc(Loc) {}
70   // SymbolizedStackHolder must outlive Location object.
71   Location(const SymbolizedStackHolder &Stack) :
72     Kind(LK_Symbolized), SymbolizedLoc(Stack.get()) {}
73 
74   LocationKind getKind() const { return Kind; }
75 
76   bool isSourceLocation() const { return Kind == LK_Source; }
77   bool isMemoryLocation() const { return Kind == LK_Memory; }
78   bool isSymbolizedStack() const { return Kind == LK_Symbolized; }
79 
80   SourceLocation getSourceLocation() const {
81     CHECK(isSourceLocation());
82     return SourceLoc;
83   }
84   MemoryLocation getMemoryLocation() const {
85     CHECK(isMemoryLocation());
86     return MemoryLoc;
87   }
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:
106   Range() : Start(), End(), Text() {}
107   Range(MemoryLocation Start, MemoryLocation End, const char *Text)
108     : Start(Start), End(End), Text(Text) {}
109   Location getStart() const { return Start; }
110   Location getEnd() const { return End; }
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:
118   TypeName(const char *Name) : Name(Name) {}
119   const char *getName() const { return Name; }
120 };
121 
122 enum class ErrorType {
123 #define UBSAN_CHECK(Name, SummaryKind, FSanitizeFlagName) Name,
124 #include "ubsan_checks.inc"
125 #undef UBSAN_CHECK
126 };
127 
128 /// \brief Representation of an in-flight diagnostic.
129 ///
130 /// Temporary \c Diag instances are created by the handler routines to
131 /// accumulate arguments for a diagnostic. The destructor emits the diagnostic
132 /// message.
133 class Diag {
134   /// The location at which the problem occurred.
135   Location Loc;
136 
137   /// The diagnostic level.
138   DiagLevel Level;
139 
140   /// The error type.
141   ErrorType ET;
142 
143   /// The message which will be emitted, with %0, %1, ... placeholders for
144   /// arguments.
145   const char *Message;
146 
147 public:
148   /// Kinds of arguments, corresponding to members of \c Arg's union.
149   enum ArgKind {
150     AK_String, ///< A string argument, displayed as-is.
151     AK_TypeName,///< A C++ type name, possibly demangled before display.
152     AK_UInt,   ///< An unsigned integer argument.
153     AK_SInt,   ///< A signed integer argument.
154     AK_Float,  ///< A floating-point argument.
155     AK_Pointer ///< A pointer argument, displayed in hexadecimal.
156   };
157 
158   /// An individual diagnostic message argument.
159   struct Arg {
160     Arg() {}
161     Arg(const char *String) : Kind(AK_String), String(String) {}
162     Arg(TypeName TN) : Kind(AK_TypeName), String(TN.getName()) {}
163     Arg(UIntMax UInt) : Kind(AK_UInt), UInt(UInt) {}
164     Arg(SIntMax SInt) : Kind(AK_SInt), SInt(SInt) {}
165     Arg(FloatMax Float) : Kind(AK_Float), Float(Float) {}
166     Arg(const void *Pointer) : Kind(AK_Pointer), Pointer(Pointer) {}
167 
168     ArgKind Kind;
169     union {
170       const char *String;
171       UIntMax UInt;
172       SIntMax SInt;
173       FloatMax Float;
174       const void *Pointer;
175     };
176   };
177 
178 private:
179   static const unsigned MaxArgs = 8;
180   static const unsigned MaxRanges = 1;
181 
182   /// The arguments which have been added to this diagnostic so far.
183   Arg Args[MaxArgs];
184   unsigned NumArgs;
185 
186   /// The ranges which have been added to this diagnostic so far.
187   Range Ranges[MaxRanges];
188   unsigned NumRanges;
189 
190   Diag &AddArg(Arg A) {
191     CHECK(NumArgs != MaxArgs);
192     Args[NumArgs++] = A;
193     return *this;
194   }
195 
196   Diag &AddRange(Range A) {
197     CHECK(NumRanges != MaxRanges);
198     Ranges[NumRanges++] = A;
199     return *this;
200   }
201 
202   /// \c Diag objects are not copyable.
203   Diag(const Diag &); // NOT IMPLEMENTED
204   Diag &operator=(const Diag &);
205 
206 public:
207   Diag(Location Loc, DiagLevel Level, ErrorType ET, const char *Message)
208       : Loc(Loc), Level(Level), ET(ET), Message(Message), NumArgs(0),
209         NumRanges(0) {}
210   ~Diag();
211 
212   Diag &operator<<(const char *Str) { return AddArg(Str); }
213   Diag &operator<<(TypeName TN) { return AddArg(TN); }
214   Diag &operator<<(unsigned long long V) { return AddArg(UIntMax(V)); }
215   Diag &operator<<(const void *V) { return AddArg(V); }
216   Diag &operator<<(const TypeDescriptor &V);
217   Diag &operator<<(const Value &V);
218   Diag &operator<<(const Range &R) { return AddRange(R); }
219 };
220 
221 struct ReportOptions {
222   // If FromUnrecoverableHandler is specified, UBSan runtime handler is not
223   // expected to return.
224   bool FromUnrecoverableHandler;
225   /// pc/bp are used to unwind the stack trace.
226   uptr pc;
227   uptr bp;
228 };
229 
230 bool ignoreReport(SourceLocation SLoc, ReportOptions Opts, ErrorType ET);
231 
232 #define GET_REPORT_OPTIONS(unrecoverable_handler) \
233     GET_CALLER_PC_BP; \
234     ReportOptions Opts = {unrecoverable_handler, pc, bp}
235 
236 void GetStackTrace(BufferedStackTrace *stack, uptr max_depth, uptr pc, uptr bp,
237                    void *context, bool fast);
238 
239 /// \brief Instantiate this class before printing diagnostics in the error
240 /// report. This class ensures that reports from different threads and from
241 /// different sanitizers won't be mixed.
242 class ScopedReport {
243   struct Initializer {
244     Initializer();
245   };
246   Initializer initializer_;
247   ScopedErrorReportLock report_lock_;
248 
249   ReportOptions Opts;
250   Location SummaryLoc;
251   ErrorType Type;
252 
253 public:
254   ScopedReport(ReportOptions Opts, Location SummaryLoc, ErrorType Type);
255   ~ScopedReport();
256 
257   static void CheckLocked() { ScopedErrorReportLock::CheckLocked(); }
258 };
259 
260 void InitializeSuppressions();
261 bool IsVptrCheckSuppressed(const char *TypeName);
262 // Sometimes UBSan runtime can know filename from handlers arguments, even if
263 // debug info is missing.
264 bool IsPCSuppressed(ErrorType ET, uptr PC, const char *Filename);
265 
266 } // namespace __ubsan
267 
268 #endif // UBSAN_DIAG_H
269