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