1 //===-- ubsan_diag.h --------------------------------------------*- C++ -*-===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // Diagnostics emission for Clang's undefined behavior sanitizer.
11 //===----------------------------------------------------------------------===//
15 #include "ubsan_value.h"
16 #include "sanitizer_common/sanitizer_stacktrace.h"
17 #include "sanitizer_common/sanitizer_symbolizer.h"
21 class SymbolizedStackHolder
{
22 SymbolizedStack
*Stack
;
30 explicit SymbolizedStackHolder(SymbolizedStack
*Stack
= nullptr)
32 ~SymbolizedStackHolder() { clear(); }
33 void reset(SymbolizedStack
*S
) {
38 const SymbolizedStack
*get() const { return Stack
; }
41 SymbolizedStack
*getSymbolizedLocation(uptr PC
);
43 inline SymbolizedStack
*getCallerLocation(uptr CallerPC
) {
45 uptr PC
= StackTrace::GetPreviousInstructionPc(CallerPC
);
46 return getSymbolizedLocation(PC
);
49 /// A location of some data within the program's address space.
50 typedef uptr MemoryLocation
;
52 /// \brief Location at which a diagnostic can be emitted. Either a
53 /// SourceLocation, a MemoryLocation, or a SymbolizedStack.
56 enum LocationKind
{ LK_Null
, LK_Source
, LK_Memory
, LK_Symbolized
};
60 // FIXME: In C++11, wrap these in an anonymous union.
61 SourceLocation SourceLoc
;
62 MemoryLocation MemoryLoc
;
63 const SymbolizedStack
*SymbolizedLoc
; // Not owned.
66 Location() : Kind(LK_Null
) {}
67 Location(SourceLocation Loc
) :
68 Kind(LK_Source
), SourceLoc(Loc
) {}
69 Location(MemoryLocation Loc
) :
70 Kind(LK_Memory
), MemoryLoc(Loc
) {}
71 // SymbolizedStackHolder must outlive Location object.
72 Location(const SymbolizedStackHolder
&Stack
) :
73 Kind(LK_Symbolized
), SymbolizedLoc(Stack
.get()) {}
75 LocationKind
getKind() const { return Kind
; }
77 bool isSourceLocation() const { return Kind
== LK_Source
; }
78 bool isMemoryLocation() const { return Kind
== LK_Memory
; }
79 bool isSymbolizedStack() const { return Kind
== LK_Symbolized
; }
81 SourceLocation
getSourceLocation() const {
82 CHECK(isSourceLocation());
85 MemoryLocation
getMemoryLocation() const {
86 CHECK(isMemoryLocation());
89 const SymbolizedStack
*getSymbolizedStack() const {
90 CHECK(isSymbolizedStack());
95 /// A diagnostic severity level.
97 DL_Error
, ///< An error.
98 DL_Note
///< A note, attached to a prior diagnostic.
101 /// \brief Annotation for a range of locations in a diagnostic.
107 Range() : Start(), End(), Text() {}
108 Range(MemoryLocation Start
, MemoryLocation End
, const char *Text
)
109 : Start(Start
), End(End
), Text(Text
) {}
110 Location
getStart() const { return Start
; }
111 Location
getEnd() const { return End
; }
112 const char *getText() const { return Text
; }
115 /// \brief A C++ type name. Really just a strong typedef for 'const char*'.
119 TypeName(const char *Name
) : Name(Name
) {}
120 const char *getName() const { return Name
; }
123 enum class ErrorType
{
124 #define UBSAN_CHECK(Name, SummaryKind, FSanitizeFlagName) Name,
125 #include "ubsan_checks.inc"
129 /// \brief Representation of an in-flight diagnostic.
131 /// Temporary \c Diag instances are created by the handler routines to
132 /// accumulate arguments for a diagnostic. The destructor emits the diagnostic
135 /// The location at which the problem occurred.
138 /// The diagnostic level.
144 /// The message which will be emitted, with %0, %1, ... placeholders for
149 /// Kinds of arguments, corresponding to members of \c Arg's union.
151 AK_String
, ///< A string argument, displayed as-is.
152 AK_TypeName
,///< A C++ type name, possibly demangled before display.
153 AK_UInt
, ///< An unsigned integer argument.
154 AK_SInt
, ///< A signed integer argument.
155 AK_Float
, ///< A floating-point argument.
156 AK_Pointer
///< A pointer argument, displayed in hexadecimal.
159 /// An individual diagnostic message argument.
162 Arg(const char *String
) : Kind(AK_String
), String(String
) {}
163 Arg(TypeName TN
) : Kind(AK_TypeName
), String(TN
.getName()) {}
164 Arg(UIntMax UInt
) : Kind(AK_UInt
), UInt(UInt
) {}
165 Arg(SIntMax SInt
) : Kind(AK_SInt
), SInt(SInt
) {}
166 Arg(FloatMax Float
) : Kind(AK_Float
), Float(Float
) {}
167 Arg(const void *Pointer
) : Kind(AK_Pointer
), Pointer(Pointer
) {}
180 static const unsigned MaxArgs
= 8;
181 static const unsigned MaxRanges
= 1;
183 /// The arguments which have been added to this diagnostic so far.
187 /// The ranges which have been added to this diagnostic so far.
188 Range Ranges
[MaxRanges
];
191 Diag
&AddArg(Arg A
) {
192 CHECK(NumArgs
!= MaxArgs
);
197 Diag
&AddRange(Range A
) {
198 CHECK(NumRanges
!= MaxRanges
);
199 Ranges
[NumRanges
++] = A
;
203 /// \c Diag objects are not copyable.
204 Diag(const Diag
&); // NOT IMPLEMENTED
205 Diag
&operator=(const Diag
&);
208 Diag(Location Loc
, DiagLevel Level
, ErrorType ET
, const char *Message
)
209 : Loc(Loc
), Level(Level
), ET(ET
), Message(Message
), NumArgs(0),
213 Diag
&operator<<(const char *Str
) { return AddArg(Str
); }
214 Diag
&operator<<(TypeName TN
) { return AddArg(TN
); }
215 Diag
&operator<<(unsigned long long V
) { return AddArg(UIntMax(V
)); }
216 Diag
&operator<<(const void *V
) { return AddArg(V
); }
217 Diag
&operator<<(const TypeDescriptor
&V
);
218 Diag
&operator<<(const Value
&V
);
219 Diag
&operator<<(const Range
&R
) { return AddRange(R
); }
222 struct ReportOptions
{
223 // If FromUnrecoverableHandler is specified, UBSan runtime handler is not
224 // expected to return.
225 bool FromUnrecoverableHandler
;
226 /// pc/bp are used to unwind the stack trace.
231 bool ignoreReport(SourceLocation SLoc
, ReportOptions Opts
, ErrorType ET
);
233 #define GET_REPORT_OPTIONS(unrecoverable_handler) \
235 ReportOptions Opts = {unrecoverable_handler, pc, bp}
237 /// \brief Instantiate this class before printing diagnostics in the error
238 /// report. This class ensures that reports from different threads and from
239 /// different sanitizers won't be mixed.
244 Initializer initializer_
;
245 ScopedErrorReportLock report_lock_
;
252 ScopedReport(ReportOptions Opts
, Location SummaryLoc
, ErrorType Type
);
255 static void CheckLocked() { ScopedErrorReportLock::CheckLocked(); }
258 void InitializeSuppressions();
259 bool IsVptrCheckSuppressed(const char *TypeName
);
260 // Sometimes UBSan runtime can know filename from handlers arguments, even if
261 // debug info is missing.
262 bool IsPCSuppressed(ErrorType ET
, uptr PC
, const char *Filename
);
264 } // namespace __ubsan
266 #endif // UBSAN_DIAG_H