123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266 |
- //===-- 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
|