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