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