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