123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236 |
- //===-- ubsan_diag.h --------------------------------------------*- C++ -*-===//
- //
- // This file is distributed under the University of Illinois Open Source
- // License. See LICENSE.TXT for details.
- //
- //===----------------------------------------------------------------------===//
- //
- // 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_suppressions.h"
- namespace __ubsan {
- /// \brief A location within a loaded module in the program. These are used when
- /// the location can't be resolved to a SourceLocation.
- class ModuleLocation {
- const char *ModuleName;
- uptr Offset;
- public:
- ModuleLocation() : ModuleName(0), Offset(0) {}
- ModuleLocation(const char *ModuleName, uptr Offset)
- : ModuleName(ModuleName), Offset(Offset) {}
- const char *getModuleName() const { return ModuleName; }
- uptr getOffset() const { return Offset; }
- };
- /// 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 ModuleLocation, or a MemoryLocation.
- class Location {
- public:
- enum LocationKind { LK_Null, LK_Source, LK_Module, LK_Memory };
- private:
- LocationKind Kind;
- // FIXME: In C++11, wrap these in an anonymous union.
- SourceLocation SourceLoc;
- ModuleLocation ModuleLoc;
- MemoryLocation MemoryLoc;
- public:
- Location() : Kind(LK_Null) {}
- Location(SourceLocation Loc) :
- Kind(LK_Source), SourceLoc(Loc) {}
- Location(ModuleLocation Loc) :
- Kind(LK_Module), ModuleLoc(Loc) {}
- Location(MemoryLocation Loc) :
- Kind(LK_Memory), MemoryLoc(Loc) {}
- LocationKind getKind() const { return Kind; }
- bool isSourceLocation() const { return Kind == LK_Source; }
- bool isModuleLocation() const { return Kind == LK_Module; }
- bool isMemoryLocation() const { return Kind == LK_Memory; }
- SourceLocation getSourceLocation() const {
- CHECK(isSourceLocation());
- return SourceLoc;
- }
- ModuleLocation getModuleLocation() const {
- CHECK(isModuleLocation());
- return ModuleLoc;
- }
- MemoryLocation getMemoryLocation() const {
- CHECK(isMemoryLocation());
- return MemoryLoc;
- }
- };
- /// Try to obtain a location for the caller. This might fail, and produce either
- /// an invalid location or a module location for the caller.
- Location getCallerLocation(uptr CallerLoc = GET_CALLER_PC());
- /// Try to obtain a location for the given function pointer. This might fail,
- /// and produce either an invalid location or a module location for the caller.
- /// If FName is non-null and the name of the function is known, set *FName to
- /// the function name, otherwise *FName is unchanged.
- Location getFunctionLocation(uptr Loc, const char **FName);
- /// 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 mangled C++ name. Really just a strong typedef for 'const char*'.
- class MangledName {
- const char *Name;
- public:
- MangledName(const char *Name) : Name(Name) {}
- const char *getName() const { return Name; }
- };
- /// \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 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_Mangled,///< A C++ mangled name, 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(MangledName MN) : Kind(AK_Mangled), String(MN.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 = 5;
- 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, const char *Message)
- : Loc(Loc), Level(Level), Message(Message), NumArgs(0), NumRanges(0) {}
- ~Diag();
- Diag &operator<<(const char *Str) { return AddArg(Str); }
- Diag &operator<<(MangledName MN) { return AddArg(MN); }
- 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 DieAfterReport is specified, UBSan will terminate the program after the
- /// report is printed.
- bool DieAfterReport;
- /// pc/bp are used to unwind the stack trace.
- uptr pc;
- uptr bp;
- };
- #define GET_REPORT_OPTIONS(die_after_report) \
- GET_CALLER_PC_BP; \
- ReportOptions Opts = {die_after_report, 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 {
- ReportOptions Opts;
- Location SummaryLoc;
- public:
- ScopedReport(ReportOptions Opts, Location SummaryLoc);
- ~ScopedReport();
- };
- bool MatchSuppression(const char *Str, SuppressionType Type);
- } // namespace __ubsan
- #endif // UBSAN_DIAG_H
|