1 //===-- ubsan_diag.h --------------------------------------------*- C++ -*-===//
3 // This file is distributed under the University of Illinois Open Source
4 // License. See LICENSE.TXT for details.
6 //===----------------------------------------------------------------------===//
8 // Diagnostics emission for Clang's undefined behavior sanitizer.
10 //===----------------------------------------------------------------------===//
14 #include "ubsan_value.h"
15 #include "sanitizer_common/sanitizer_stacktrace.h"
16 #include "sanitizer_common/sanitizer_symbolizer.h"
20 class SymbolizedStackHolder
{
21 SymbolizedStack
*Stack
;
29 explicit SymbolizedStackHolder(SymbolizedStack
*Stack
= nullptr)
31 ~SymbolizedStackHolder() { clear(); }
32 void reset(SymbolizedStack
*S
) {
37 const SymbolizedStack
*get() const { return Stack
; }
40 SymbolizedStack
*getSymbolizedLocation(uptr PC
);
42 inline SymbolizedStack
*getCallerLocation(uptr CallerPC
) {
44 uptr PC
= StackTrace::GetPreviousInstructionPc(CallerPC
);
45 return getSymbolizedLocation(PC
);
48 /// A location of some data within the program's address space.
49 typedef uptr MemoryLocation
;
51 /// \brief Location at which a diagnostic can be emitted. Either a
52 /// SourceLocation, a MemoryLocation, or a SymbolizedStack.
55 enum LocationKind
{ LK_Null
, LK_Source
, LK_Memory
, LK_Symbolized
};
59 // FIXME: In C++11, wrap these in an anonymous union.
60 SourceLocation SourceLoc
;
61 MemoryLocation MemoryLoc
;
62 const SymbolizedStack
*SymbolizedLoc
; // Not owned.
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()) {}
74 LocationKind
getKind() const { return Kind
; }
76 bool isSourceLocation() const { return Kind
== LK_Source
; }
77 bool isMemoryLocation() const { return Kind
== LK_Memory
; }
78 bool isSymbolizedStack() const { return Kind
== LK_Symbolized
; }
80 SourceLocation
getSourceLocation() const {
81 CHECK(isSourceLocation());
84 MemoryLocation
getMemoryLocation() const {
85 CHECK(isMemoryLocation());
88 const SymbolizedStack
*getSymbolizedStack() const {
89 CHECK(isSymbolizedStack());
94 /// A diagnostic severity level.
96 DL_Error
, ///< An error.
97 DL_Note
///< A note, attached to a prior diagnostic.
100 /// \brief Annotation for a range of locations in a diagnostic.
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
; }
114 /// \brief A C++ type name. Really just a strong typedef for 'const char*'.
118 TypeName(const char *Name
) : Name(Name
) {}
119 const char *getName() const { return Name
; }
122 /// \brief Representation of an in-flight diagnostic.
124 /// Temporary \c Diag instances are created by the handler routines to
125 /// accumulate arguments for a diagnostic. The destructor emits the diagnostic
128 /// The location at which the problem occurred.
131 /// The diagnostic level.
134 /// The message which will be emitted, with %0, %1, ... placeholders for
139 /// Kinds of arguments, corresponding to members of \c Arg's union.
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.
149 /// An individual diagnostic message argument.
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
) {}
170 static const unsigned MaxArgs
= 5;
171 static const unsigned MaxRanges
= 1;
173 /// The arguments which have been added to this diagnostic so far.
177 /// The ranges which have been added to this diagnostic so far.
178 Range Ranges
[MaxRanges
];
181 Diag
&AddArg(Arg A
) {
182 CHECK(NumArgs
!= MaxArgs
);
187 Diag
&AddRange(Range A
) {
188 CHECK(NumRanges
!= MaxRanges
);
189 Ranges
[NumRanges
++] = A
;
193 /// \c Diag objects are not copyable.
194 Diag(const Diag
&); // NOT IMPLEMENTED
195 Diag
&operator=(const Diag
&);
198 Diag(Location Loc
, DiagLevel Level
, const char *Message
)
199 : Loc(Loc
), Level(Level
), Message(Message
), NumArgs(0), NumRanges(0) {}
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
); }
211 struct ReportOptions
{
212 /// If DieAfterReport is specified, UBSan will terminate the program after the
213 /// report is printed.
215 /// pc/bp are used to unwind the stack trace.
220 enum class ErrorType
{
221 #define UBSAN_CHECK(Name, SummaryKind, FlagName) Name,
222 #include "ubsan_checks.inc"
226 #define GET_REPORT_OPTIONS(die_after_report) \
228 ReportOptions Opts = {die_after_report, pc, bp}
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.
239 ScopedReport(ReportOptions Opts
, Location SummaryLoc
,
240 ErrorType Type
= ErrorType::GenericUB
);
241 void setErrorType(ErrorType T
) { Type
= T
; }
245 void InitializeSuppressions();
246 bool IsVptrCheckSuppressed(const char *TypeName
);
248 } // namespace __ubsan
250 #endif // UBSAN_DIAG_H