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
18namespace __ubsan {
19
20class SymbolizedStackHolder {
21  SymbolizedStack *Stack;
22
23  void clear() {
24    if (Stack)
25      Stack->ClearAll();
26  }
27
28public:
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
40SymbolizedStack *getSymbolizedLocation(uptr PC);
41
42inline 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.
49typedef uptr MemoryLocation;
50
51/// \brief Location at which a diagnostic can be emitted. Either a
52/// SourceLocation, a MemoryLocation, or a SymbolizedStack.
53class Location {
54public:
55  enum LocationKind { LK_Null, LK_Source, LK_Memory, LK_Symbolized };
56
57private:
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
64public:
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.
95enum 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.
101class Range {
102  Location Start, End;
103  const char *Text;
104
105public:
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*'.
115class TypeName {
116  const char *Name;
117public:
118  TypeName(const char *Name) : Name(Name) {}
119  const char *getName() const { return Name; }
120};
121
122enum 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.
133class 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
147public:
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
178private:
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
206public:
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
221struct 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
230bool 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
236void 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.
242class 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
253public:
254  ScopedReport(ReportOptions Opts, Location SummaryLoc, ErrorType Type);
255  ~ScopedReport();
256
257  static void CheckLocked() { ScopedErrorReportLock::CheckLocked(); }
258};
259
260void InitializeSuppressions();
261bool IsVptrCheckSuppressed(const char *TypeName);
262// Sometimes UBSan runtime can know filename from handlers arguments, even if
263// debug info is missing.
264bool IsPCSuppressed(ErrorType ET, uptr PC, const char *Filename);
265
266} // namespace __ubsan
267
268#endif // UBSAN_DIAG_H
269