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