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