xref: /aosp_15_r20/external/compiler-rt/lib/ubsan/ubsan_diag.cc (revision 7c3d14c8b49c529e04be81a3ce6f5cc23712e4c6)
1*7c3d14c8STreehugger Robot //===-- ubsan_diag.cc -----------------------------------------------------===//
2*7c3d14c8STreehugger Robot //
3*7c3d14c8STreehugger Robot //                     The LLVM Compiler Infrastructure
4*7c3d14c8STreehugger Robot //
5*7c3d14c8STreehugger Robot // This file is distributed under the University of Illinois Open Source
6*7c3d14c8STreehugger Robot // License. See LICENSE.TXT for details.
7*7c3d14c8STreehugger Robot //
8*7c3d14c8STreehugger Robot //===----------------------------------------------------------------------===//
9*7c3d14c8STreehugger Robot //
10*7c3d14c8STreehugger Robot // Diagnostic reporting for the UBSan runtime.
11*7c3d14c8STreehugger Robot //
12*7c3d14c8STreehugger Robot //===----------------------------------------------------------------------===//
13*7c3d14c8STreehugger Robot 
14*7c3d14c8STreehugger Robot #include "ubsan_platform.h"
15*7c3d14c8STreehugger Robot #if CAN_SANITIZE_UB
16*7c3d14c8STreehugger Robot #include "ubsan_diag.h"
17*7c3d14c8STreehugger Robot #include "ubsan_init.h"
18*7c3d14c8STreehugger Robot #include "ubsan_flags.h"
19*7c3d14c8STreehugger Robot #include "sanitizer_common/sanitizer_placement_new.h"
20*7c3d14c8STreehugger Robot #include "sanitizer_common/sanitizer_report_decorator.h"
21*7c3d14c8STreehugger Robot #include "sanitizer_common/sanitizer_stacktrace.h"
22*7c3d14c8STreehugger Robot #include "sanitizer_common/sanitizer_stacktrace_printer.h"
23*7c3d14c8STreehugger Robot #include "sanitizer_common/sanitizer_suppressions.h"
24*7c3d14c8STreehugger Robot #include "sanitizer_common/sanitizer_symbolizer.h"
25*7c3d14c8STreehugger Robot #include <stdio.h>
26*7c3d14c8STreehugger Robot 
27*7c3d14c8STreehugger Robot using namespace __ubsan;
28*7c3d14c8STreehugger Robot 
MaybePrintStackTrace(uptr pc,uptr bp)29*7c3d14c8STreehugger Robot static void MaybePrintStackTrace(uptr pc, uptr bp) {
30*7c3d14c8STreehugger Robot   // We assume that flags are already parsed, as UBSan runtime
31*7c3d14c8STreehugger Robot   // will definitely be called when we print the first diagnostics message.
32*7c3d14c8STreehugger Robot   if (!flags()->print_stacktrace)
33*7c3d14c8STreehugger Robot     return;
34*7c3d14c8STreehugger Robot   // We can only use slow unwind, as we don't have any information about stack
35*7c3d14c8STreehugger Robot   // top/bottom.
36*7c3d14c8STreehugger Robot   // FIXME: It's better to respect "fast_unwind_on_fatal" runtime flag and
37*7c3d14c8STreehugger Robot   // fetch stack top/bottom information if we have it (e.g. if we're running
38*7c3d14c8STreehugger Robot   // under ASan).
39*7c3d14c8STreehugger Robot   if (StackTrace::WillUseFastUnwind(false))
40*7c3d14c8STreehugger Robot     return;
41*7c3d14c8STreehugger Robot   BufferedStackTrace stack;
42*7c3d14c8STreehugger Robot   stack.Unwind(kStackTraceMax, pc, bp, 0, 0, 0, false);
43*7c3d14c8STreehugger Robot   stack.Print();
44*7c3d14c8STreehugger Robot }
45*7c3d14c8STreehugger Robot 
ConvertTypeToString(ErrorType Type)46*7c3d14c8STreehugger Robot static const char *ConvertTypeToString(ErrorType Type) {
47*7c3d14c8STreehugger Robot   switch (Type) {
48*7c3d14c8STreehugger Robot #define UBSAN_CHECK(Name, SummaryKind, FSanitizeFlagName)                      \
49*7c3d14c8STreehugger Robot   case ErrorType::Name:                                                        \
50*7c3d14c8STreehugger Robot     return SummaryKind;
51*7c3d14c8STreehugger Robot #include "ubsan_checks.inc"
52*7c3d14c8STreehugger Robot #undef UBSAN_CHECK
53*7c3d14c8STreehugger Robot   }
54*7c3d14c8STreehugger Robot   UNREACHABLE("unknown ErrorType!");
55*7c3d14c8STreehugger Robot }
56*7c3d14c8STreehugger Robot 
ConvertTypeToFlagName(ErrorType Type)57*7c3d14c8STreehugger Robot static const char *ConvertTypeToFlagName(ErrorType Type) {
58*7c3d14c8STreehugger Robot   switch (Type) {
59*7c3d14c8STreehugger Robot #define UBSAN_CHECK(Name, SummaryKind, FSanitizeFlagName)                      \
60*7c3d14c8STreehugger Robot   case ErrorType::Name:                                                        \
61*7c3d14c8STreehugger Robot     return FSanitizeFlagName;
62*7c3d14c8STreehugger Robot #include "ubsan_checks.inc"
63*7c3d14c8STreehugger Robot #undef UBSAN_CHECK
64*7c3d14c8STreehugger Robot   }
65*7c3d14c8STreehugger Robot   UNREACHABLE("unknown ErrorType!");
66*7c3d14c8STreehugger Robot }
67*7c3d14c8STreehugger Robot 
MaybeReportErrorSummary(Location Loc,ErrorType Type)68*7c3d14c8STreehugger Robot static void MaybeReportErrorSummary(Location Loc, ErrorType Type) {
69*7c3d14c8STreehugger Robot   if (!common_flags()->print_summary)
70*7c3d14c8STreehugger Robot     return;
71*7c3d14c8STreehugger Robot   if (!flags()->report_error_type)
72*7c3d14c8STreehugger Robot     Type = ErrorType::GenericUB;
73*7c3d14c8STreehugger Robot   const char *ErrorKind = ConvertTypeToString(Type);
74*7c3d14c8STreehugger Robot   if (Loc.isSourceLocation()) {
75*7c3d14c8STreehugger Robot     SourceLocation SLoc = Loc.getSourceLocation();
76*7c3d14c8STreehugger Robot     if (!SLoc.isInvalid()) {
77*7c3d14c8STreehugger Robot       AddressInfo AI;
78*7c3d14c8STreehugger Robot       AI.file = internal_strdup(SLoc.getFilename());
79*7c3d14c8STreehugger Robot       AI.line = SLoc.getLine();
80*7c3d14c8STreehugger Robot       AI.column = SLoc.getColumn();
81*7c3d14c8STreehugger Robot       AI.function = internal_strdup("");  // Avoid printing ?? as function name.
82*7c3d14c8STreehugger Robot       ReportErrorSummary(ErrorKind, AI);
83*7c3d14c8STreehugger Robot       AI.Clear();
84*7c3d14c8STreehugger Robot       return;
85*7c3d14c8STreehugger Robot     }
86*7c3d14c8STreehugger Robot   } else if (Loc.isSymbolizedStack()) {
87*7c3d14c8STreehugger Robot     const AddressInfo &AI = Loc.getSymbolizedStack()->info;
88*7c3d14c8STreehugger Robot     ReportErrorSummary(ErrorKind, AI);
89*7c3d14c8STreehugger Robot     return;
90*7c3d14c8STreehugger Robot   }
91*7c3d14c8STreehugger Robot   ReportErrorSummary(ErrorKind);
92*7c3d14c8STreehugger Robot }
93*7c3d14c8STreehugger Robot 
94*7c3d14c8STreehugger Robot namespace {
95*7c3d14c8STreehugger Robot class Decorator : public SanitizerCommonDecorator {
96*7c3d14c8STreehugger Robot  public:
Decorator()97*7c3d14c8STreehugger Robot   Decorator() : SanitizerCommonDecorator() {}
Highlight() const98*7c3d14c8STreehugger Robot   const char *Highlight() const { return Green(); }
EndHighlight() const99*7c3d14c8STreehugger Robot   const char *EndHighlight() const { return Default(); }
Note() const100*7c3d14c8STreehugger Robot   const char *Note() const { return Black(); }
EndNote() const101*7c3d14c8STreehugger Robot   const char *EndNote() const { return Default(); }
102*7c3d14c8STreehugger Robot };
103*7c3d14c8STreehugger Robot }
104*7c3d14c8STreehugger Robot 
getSymbolizedLocation(uptr PC)105*7c3d14c8STreehugger Robot SymbolizedStack *__ubsan::getSymbolizedLocation(uptr PC) {
106*7c3d14c8STreehugger Robot   InitAsStandaloneIfNecessary();
107*7c3d14c8STreehugger Robot   return Symbolizer::GetOrInit()->SymbolizePC(PC);
108*7c3d14c8STreehugger Robot }
109*7c3d14c8STreehugger Robot 
operator <<(const TypeDescriptor & V)110*7c3d14c8STreehugger Robot Diag &Diag::operator<<(const TypeDescriptor &V) {
111*7c3d14c8STreehugger Robot   return AddArg(V.getTypeName());
112*7c3d14c8STreehugger Robot }
113*7c3d14c8STreehugger Robot 
operator <<(const Value & V)114*7c3d14c8STreehugger Robot Diag &Diag::operator<<(const Value &V) {
115*7c3d14c8STreehugger Robot   if (V.getType().isSignedIntegerTy())
116*7c3d14c8STreehugger Robot     AddArg(V.getSIntValue());
117*7c3d14c8STreehugger Robot   else if (V.getType().isUnsignedIntegerTy())
118*7c3d14c8STreehugger Robot     AddArg(V.getUIntValue());
119*7c3d14c8STreehugger Robot   else if (V.getType().isFloatTy())
120*7c3d14c8STreehugger Robot     AddArg(V.getFloatValue());
121*7c3d14c8STreehugger Robot   else
122*7c3d14c8STreehugger Robot     AddArg("<unknown>");
123*7c3d14c8STreehugger Robot   return *this;
124*7c3d14c8STreehugger Robot }
125*7c3d14c8STreehugger Robot 
126*7c3d14c8STreehugger Robot /// Hexadecimal printing for numbers too large for Printf to handle directly.
RenderHex(InternalScopedString * Buffer,UIntMax Val)127*7c3d14c8STreehugger Robot static void RenderHex(InternalScopedString *Buffer, UIntMax Val) {
128*7c3d14c8STreehugger Robot #if HAVE_INT128_T
129*7c3d14c8STreehugger Robot   Buffer->append("0x%08x%08x%08x%08x", (unsigned int)(Val >> 96),
130*7c3d14c8STreehugger Robot                  (unsigned int)(Val >> 64), (unsigned int)(Val >> 32),
131*7c3d14c8STreehugger Robot                  (unsigned int)(Val));
132*7c3d14c8STreehugger Robot #else
133*7c3d14c8STreehugger Robot   UNREACHABLE("long long smaller than 64 bits?");
134*7c3d14c8STreehugger Robot #endif
135*7c3d14c8STreehugger Robot }
136*7c3d14c8STreehugger Robot 
RenderLocation(InternalScopedString * Buffer,Location Loc)137*7c3d14c8STreehugger Robot static void RenderLocation(InternalScopedString *Buffer, Location Loc) {
138*7c3d14c8STreehugger Robot   switch (Loc.getKind()) {
139*7c3d14c8STreehugger Robot   case Location::LK_Source: {
140*7c3d14c8STreehugger Robot     SourceLocation SLoc = Loc.getSourceLocation();
141*7c3d14c8STreehugger Robot     if (SLoc.isInvalid())
142*7c3d14c8STreehugger Robot       Buffer->append("<unknown>");
143*7c3d14c8STreehugger Robot     else
144*7c3d14c8STreehugger Robot       RenderSourceLocation(Buffer, SLoc.getFilename(), SLoc.getLine(),
145*7c3d14c8STreehugger Robot                            SLoc.getColumn(), common_flags()->symbolize_vs_style,
146*7c3d14c8STreehugger Robot                            common_flags()->strip_path_prefix);
147*7c3d14c8STreehugger Robot     return;
148*7c3d14c8STreehugger Robot   }
149*7c3d14c8STreehugger Robot   case Location::LK_Memory:
150*7c3d14c8STreehugger Robot     Buffer->append("%p", Loc.getMemoryLocation());
151*7c3d14c8STreehugger Robot     return;
152*7c3d14c8STreehugger Robot   case Location::LK_Symbolized: {
153*7c3d14c8STreehugger Robot     const AddressInfo &Info = Loc.getSymbolizedStack()->info;
154*7c3d14c8STreehugger Robot     if (Info.file)
155*7c3d14c8STreehugger Robot       RenderSourceLocation(Buffer, Info.file, Info.line, Info.column,
156*7c3d14c8STreehugger Robot                            common_flags()->symbolize_vs_style,
157*7c3d14c8STreehugger Robot                            common_flags()->strip_path_prefix);
158*7c3d14c8STreehugger Robot     else if (Info.module)
159*7c3d14c8STreehugger Robot       RenderModuleLocation(Buffer, Info.module, Info.module_offset,
160*7c3d14c8STreehugger Robot                            common_flags()->strip_path_prefix);
161*7c3d14c8STreehugger Robot     else
162*7c3d14c8STreehugger Robot       Buffer->append("%p", Info.address);
163*7c3d14c8STreehugger Robot     return;
164*7c3d14c8STreehugger Robot   }
165*7c3d14c8STreehugger Robot   case Location::LK_Null:
166*7c3d14c8STreehugger Robot     Buffer->append("<unknown>");
167*7c3d14c8STreehugger Robot     return;
168*7c3d14c8STreehugger Robot   }
169*7c3d14c8STreehugger Robot }
170*7c3d14c8STreehugger Robot 
RenderText(InternalScopedString * Buffer,const char * Message,const Diag::Arg * Args)171*7c3d14c8STreehugger Robot static void RenderText(InternalScopedString *Buffer, const char *Message,
172*7c3d14c8STreehugger Robot                        const Diag::Arg *Args) {
173*7c3d14c8STreehugger Robot   for (const char *Msg = Message; *Msg; ++Msg) {
174*7c3d14c8STreehugger Robot     if (*Msg != '%') {
175*7c3d14c8STreehugger Robot       Buffer->append("%c", *Msg);
176*7c3d14c8STreehugger Robot       continue;
177*7c3d14c8STreehugger Robot     }
178*7c3d14c8STreehugger Robot     const Diag::Arg &A = Args[*++Msg - '0'];
179*7c3d14c8STreehugger Robot     switch (A.Kind) {
180*7c3d14c8STreehugger Robot     case Diag::AK_String:
181*7c3d14c8STreehugger Robot       Buffer->append("%s", A.String);
182*7c3d14c8STreehugger Robot       break;
183*7c3d14c8STreehugger Robot     case Diag::AK_TypeName: {
184*7c3d14c8STreehugger Robot       if (SANITIZER_WINDOWS)
185*7c3d14c8STreehugger Robot         // The Windows implementation demangles names early.
186*7c3d14c8STreehugger Robot         Buffer->append("'%s'", A.String);
187*7c3d14c8STreehugger Robot       else
188*7c3d14c8STreehugger Robot         Buffer->append("'%s'", Symbolizer::GetOrInit()->Demangle(A.String));
189*7c3d14c8STreehugger Robot       break;
190*7c3d14c8STreehugger Robot     }
191*7c3d14c8STreehugger Robot     case Diag::AK_SInt:
192*7c3d14c8STreehugger Robot       // 'long long' is guaranteed to be at least 64 bits wide.
193*7c3d14c8STreehugger Robot       if (A.SInt >= INT64_MIN && A.SInt <= INT64_MAX)
194*7c3d14c8STreehugger Robot         Buffer->append("%lld", (long long)A.SInt);
195*7c3d14c8STreehugger Robot       else
196*7c3d14c8STreehugger Robot         RenderHex(Buffer, A.SInt);
197*7c3d14c8STreehugger Robot       break;
198*7c3d14c8STreehugger Robot     case Diag::AK_UInt:
199*7c3d14c8STreehugger Robot       if (A.UInt <= UINT64_MAX)
200*7c3d14c8STreehugger Robot         Buffer->append("%llu", (unsigned long long)A.UInt);
201*7c3d14c8STreehugger Robot       else
202*7c3d14c8STreehugger Robot         RenderHex(Buffer, A.UInt);
203*7c3d14c8STreehugger Robot       break;
204*7c3d14c8STreehugger Robot     case Diag::AK_Float: {
205*7c3d14c8STreehugger Robot       // FIXME: Support floating-point formatting in sanitizer_common's
206*7c3d14c8STreehugger Robot       //        printf, and stop using snprintf here.
207*7c3d14c8STreehugger Robot       char FloatBuffer[32];
208*7c3d14c8STreehugger Robot #if SANITIZER_WINDOWS
209*7c3d14c8STreehugger Robot       sprintf_s(FloatBuffer, sizeof(FloatBuffer), "%Lg", (long double)A.Float);
210*7c3d14c8STreehugger Robot #else
211*7c3d14c8STreehugger Robot       snprintf(FloatBuffer, sizeof(FloatBuffer), "%Lg", (long double)A.Float);
212*7c3d14c8STreehugger Robot #endif
213*7c3d14c8STreehugger Robot       Buffer->append("%s", FloatBuffer);
214*7c3d14c8STreehugger Robot       break;
215*7c3d14c8STreehugger Robot     }
216*7c3d14c8STreehugger Robot     case Diag::AK_Pointer:
217*7c3d14c8STreehugger Robot       Buffer->append("%p", A.Pointer);
218*7c3d14c8STreehugger Robot       break;
219*7c3d14c8STreehugger Robot     }
220*7c3d14c8STreehugger Robot   }
221*7c3d14c8STreehugger Robot }
222*7c3d14c8STreehugger Robot 
223*7c3d14c8STreehugger Robot /// Find the earliest-starting range in Ranges which ends after Loc.
upperBound(MemoryLocation Loc,Range * Ranges,unsigned NumRanges)224*7c3d14c8STreehugger Robot static Range *upperBound(MemoryLocation Loc, Range *Ranges,
225*7c3d14c8STreehugger Robot                          unsigned NumRanges) {
226*7c3d14c8STreehugger Robot   Range *Best = 0;
227*7c3d14c8STreehugger Robot   for (unsigned I = 0; I != NumRanges; ++I)
228*7c3d14c8STreehugger Robot     if (Ranges[I].getEnd().getMemoryLocation() > Loc &&
229*7c3d14c8STreehugger Robot         (!Best ||
230*7c3d14c8STreehugger Robot          Best->getStart().getMemoryLocation() >
231*7c3d14c8STreehugger Robot          Ranges[I].getStart().getMemoryLocation()))
232*7c3d14c8STreehugger Robot       Best = &Ranges[I];
233*7c3d14c8STreehugger Robot   return Best;
234*7c3d14c8STreehugger Robot }
235*7c3d14c8STreehugger Robot 
subtractNoOverflow(uptr LHS,uptr RHS)236*7c3d14c8STreehugger Robot static inline uptr subtractNoOverflow(uptr LHS, uptr RHS) {
237*7c3d14c8STreehugger Robot   return (LHS < RHS) ? 0 : LHS - RHS;
238*7c3d14c8STreehugger Robot }
239*7c3d14c8STreehugger Robot 
addNoOverflow(uptr LHS,uptr RHS)240*7c3d14c8STreehugger Robot static inline uptr addNoOverflow(uptr LHS, uptr RHS) {
241*7c3d14c8STreehugger Robot   const uptr Limit = (uptr)-1;
242*7c3d14c8STreehugger Robot   return (LHS > Limit - RHS) ? Limit : LHS + RHS;
243*7c3d14c8STreehugger Robot }
244*7c3d14c8STreehugger Robot 
245*7c3d14c8STreehugger Robot /// Render a snippet of the address space near a location.
PrintMemorySnippet(const Decorator & Decor,MemoryLocation Loc,Range * Ranges,unsigned NumRanges,const Diag::Arg * Args)246*7c3d14c8STreehugger Robot static void PrintMemorySnippet(const Decorator &Decor, MemoryLocation Loc,
247*7c3d14c8STreehugger Robot                                Range *Ranges, unsigned NumRanges,
248*7c3d14c8STreehugger Robot                                const Diag::Arg *Args) {
249*7c3d14c8STreehugger Robot   // Show at least the 8 bytes surrounding Loc.
250*7c3d14c8STreehugger Robot   const unsigned MinBytesNearLoc = 4;
251*7c3d14c8STreehugger Robot   MemoryLocation Min = subtractNoOverflow(Loc, MinBytesNearLoc);
252*7c3d14c8STreehugger Robot   MemoryLocation Max = addNoOverflow(Loc, MinBytesNearLoc);
253*7c3d14c8STreehugger Robot   MemoryLocation OrigMin = Min;
254*7c3d14c8STreehugger Robot   for (unsigned I = 0; I < NumRanges; ++I) {
255*7c3d14c8STreehugger Robot     Min = __sanitizer::Min(Ranges[I].getStart().getMemoryLocation(), Min);
256*7c3d14c8STreehugger Robot     Max = __sanitizer::Max(Ranges[I].getEnd().getMemoryLocation(), Max);
257*7c3d14c8STreehugger Robot   }
258*7c3d14c8STreehugger Robot 
259*7c3d14c8STreehugger Robot   // If we have too many interesting bytes, prefer to show bytes after Loc.
260*7c3d14c8STreehugger Robot   const unsigned BytesToShow = 32;
261*7c3d14c8STreehugger Robot   if (Max - Min > BytesToShow)
262*7c3d14c8STreehugger Robot     Min = __sanitizer::Min(Max - BytesToShow, OrigMin);
263*7c3d14c8STreehugger Robot   Max = addNoOverflow(Min, BytesToShow);
264*7c3d14c8STreehugger Robot 
265*7c3d14c8STreehugger Robot   if (!IsAccessibleMemoryRange(Min, Max - Min)) {
266*7c3d14c8STreehugger Robot     Printf("<memory cannot be printed>\n");
267*7c3d14c8STreehugger Robot     return;
268*7c3d14c8STreehugger Robot   }
269*7c3d14c8STreehugger Robot 
270*7c3d14c8STreehugger Robot   // Emit data.
271*7c3d14c8STreehugger Robot   InternalScopedString Buffer(1024);
272*7c3d14c8STreehugger Robot   for (uptr P = Min; P != Max; ++P) {
273*7c3d14c8STreehugger Robot     unsigned char C = *reinterpret_cast<const unsigned char*>(P);
274*7c3d14c8STreehugger Robot     Buffer.append("%s%02x", (P % 8 == 0) ? "  " : " ", C);
275*7c3d14c8STreehugger Robot   }
276*7c3d14c8STreehugger Robot   Buffer.append("\n");
277*7c3d14c8STreehugger Robot 
278*7c3d14c8STreehugger Robot   // Emit highlights.
279*7c3d14c8STreehugger Robot   Buffer.append(Decor.Highlight());
280*7c3d14c8STreehugger Robot   Range *InRange = upperBound(Min, Ranges, NumRanges);
281*7c3d14c8STreehugger Robot   for (uptr P = Min; P != Max; ++P) {
282*7c3d14c8STreehugger Robot     char Pad = ' ', Byte = ' ';
283*7c3d14c8STreehugger Robot     if (InRange && InRange->getEnd().getMemoryLocation() == P)
284*7c3d14c8STreehugger Robot       InRange = upperBound(P, Ranges, NumRanges);
285*7c3d14c8STreehugger Robot     if (!InRange && P > Loc)
286*7c3d14c8STreehugger Robot       break;
287*7c3d14c8STreehugger Robot     if (InRange && InRange->getStart().getMemoryLocation() < P)
288*7c3d14c8STreehugger Robot       Pad = '~';
289*7c3d14c8STreehugger Robot     if (InRange && InRange->getStart().getMemoryLocation() <= P)
290*7c3d14c8STreehugger Robot       Byte = '~';
291*7c3d14c8STreehugger Robot     if (P % 8 == 0)
292*7c3d14c8STreehugger Robot       Buffer.append("%c", Pad);
293*7c3d14c8STreehugger Robot     Buffer.append("%c", Pad);
294*7c3d14c8STreehugger Robot     Buffer.append("%c", P == Loc ? '^' : Byte);
295*7c3d14c8STreehugger Robot     Buffer.append("%c", Byte);
296*7c3d14c8STreehugger Robot   }
297*7c3d14c8STreehugger Robot   Buffer.append("%s\n", Decor.EndHighlight());
298*7c3d14c8STreehugger Robot 
299*7c3d14c8STreehugger Robot   // Go over the line again, and print names for the ranges.
300*7c3d14c8STreehugger Robot   InRange = 0;
301*7c3d14c8STreehugger Robot   unsigned Spaces = 0;
302*7c3d14c8STreehugger Robot   for (uptr P = Min; P != Max; ++P) {
303*7c3d14c8STreehugger Robot     if (!InRange || InRange->getEnd().getMemoryLocation() == P)
304*7c3d14c8STreehugger Robot       InRange = upperBound(P, Ranges, NumRanges);
305*7c3d14c8STreehugger Robot     if (!InRange)
306*7c3d14c8STreehugger Robot       break;
307*7c3d14c8STreehugger Robot 
308*7c3d14c8STreehugger Robot     Spaces += (P % 8) == 0 ? 2 : 1;
309*7c3d14c8STreehugger Robot 
310*7c3d14c8STreehugger Robot     if (InRange && InRange->getStart().getMemoryLocation() == P) {
311*7c3d14c8STreehugger Robot       while (Spaces--)
312*7c3d14c8STreehugger Robot         Buffer.append(" ");
313*7c3d14c8STreehugger Robot       RenderText(&Buffer, InRange->getText(), Args);
314*7c3d14c8STreehugger Robot       Buffer.append("\n");
315*7c3d14c8STreehugger Robot       // FIXME: We only support naming one range for now!
316*7c3d14c8STreehugger Robot       break;
317*7c3d14c8STreehugger Robot     }
318*7c3d14c8STreehugger Robot 
319*7c3d14c8STreehugger Robot     Spaces += 2;
320*7c3d14c8STreehugger Robot   }
321*7c3d14c8STreehugger Robot 
322*7c3d14c8STreehugger Robot   Printf("%s", Buffer.data());
323*7c3d14c8STreehugger Robot   // FIXME: Print names for anything we can identify within the line:
324*7c3d14c8STreehugger Robot   //
325*7c3d14c8STreehugger Robot   //  * If we can identify the memory itself as belonging to a particular
326*7c3d14c8STreehugger Robot   //    global, stack variable, or dynamic allocation, then do so.
327*7c3d14c8STreehugger Robot   //
328*7c3d14c8STreehugger Robot   //  * If we have a pointer-size, pointer-aligned range highlighted,
329*7c3d14c8STreehugger Robot   //    determine whether the value of that range is a pointer to an
330*7c3d14c8STreehugger Robot   //    entity which we can name, and if so, print that name.
331*7c3d14c8STreehugger Robot   //
332*7c3d14c8STreehugger Robot   // This needs an external symbolizer, or (preferably) ASan instrumentation.
333*7c3d14c8STreehugger Robot }
334*7c3d14c8STreehugger Robot 
~Diag()335*7c3d14c8STreehugger Robot Diag::~Diag() {
336*7c3d14c8STreehugger Robot   // All diagnostics should be printed under report mutex.
337*7c3d14c8STreehugger Robot   CommonSanitizerReportMutex.CheckLocked();
338*7c3d14c8STreehugger Robot   Decorator Decor;
339*7c3d14c8STreehugger Robot   InternalScopedString Buffer(1024);
340*7c3d14c8STreehugger Robot 
341*7c3d14c8STreehugger Robot   Buffer.append(Decor.Bold());
342*7c3d14c8STreehugger Robot   RenderLocation(&Buffer, Loc);
343*7c3d14c8STreehugger Robot   Buffer.append(":");
344*7c3d14c8STreehugger Robot 
345*7c3d14c8STreehugger Robot   switch (Level) {
346*7c3d14c8STreehugger Robot   case DL_Error:
347*7c3d14c8STreehugger Robot     Buffer.append("%s runtime error: %s%s", Decor.Warning(), Decor.EndWarning(),
348*7c3d14c8STreehugger Robot                   Decor.Bold());
349*7c3d14c8STreehugger Robot     break;
350*7c3d14c8STreehugger Robot 
351*7c3d14c8STreehugger Robot   case DL_Note:
352*7c3d14c8STreehugger Robot     Buffer.append("%s note: %s", Decor.Note(), Decor.EndNote());
353*7c3d14c8STreehugger Robot     break;
354*7c3d14c8STreehugger Robot   }
355*7c3d14c8STreehugger Robot 
356*7c3d14c8STreehugger Robot   RenderText(&Buffer, Message, Args);
357*7c3d14c8STreehugger Robot 
358*7c3d14c8STreehugger Robot   Buffer.append("%s\n", Decor.Default());
359*7c3d14c8STreehugger Robot   Printf("%s", Buffer.data());
360*7c3d14c8STreehugger Robot 
361*7c3d14c8STreehugger Robot   if (Loc.isMemoryLocation())
362*7c3d14c8STreehugger Robot     PrintMemorySnippet(Decor, Loc.getMemoryLocation(), Ranges, NumRanges, Args);
363*7c3d14c8STreehugger Robot }
364*7c3d14c8STreehugger Robot 
ScopedReport(ReportOptions Opts,Location SummaryLoc,ErrorType Type)365*7c3d14c8STreehugger Robot ScopedReport::ScopedReport(ReportOptions Opts, Location SummaryLoc,
366*7c3d14c8STreehugger Robot                            ErrorType Type)
367*7c3d14c8STreehugger Robot     : Opts(Opts), SummaryLoc(SummaryLoc), Type(Type) {
368*7c3d14c8STreehugger Robot   InitAsStandaloneIfNecessary();
369*7c3d14c8STreehugger Robot   CommonSanitizerReportMutex.Lock();
370*7c3d14c8STreehugger Robot }
371*7c3d14c8STreehugger Robot 
~ScopedReport()372*7c3d14c8STreehugger Robot ScopedReport::~ScopedReport() {
373*7c3d14c8STreehugger Robot   MaybePrintStackTrace(Opts.pc, Opts.bp);
374*7c3d14c8STreehugger Robot   MaybeReportErrorSummary(SummaryLoc, Type);
375*7c3d14c8STreehugger Robot   CommonSanitizerReportMutex.Unlock();
376*7c3d14c8STreehugger Robot   if (flags()->halt_on_error)
377*7c3d14c8STreehugger Robot     Die();
378*7c3d14c8STreehugger Robot }
379*7c3d14c8STreehugger Robot 
380*7c3d14c8STreehugger Robot ALIGNED(64) static char suppression_placeholder[sizeof(SuppressionContext)];
381*7c3d14c8STreehugger Robot static SuppressionContext *suppression_ctx = nullptr;
382*7c3d14c8STreehugger Robot static const char kVptrCheck[] = "vptr_check";
383*7c3d14c8STreehugger Robot static const char *kSuppressionTypes[] = {
384*7c3d14c8STreehugger Robot #define UBSAN_CHECK(Name, SummaryKind, FSanitizeFlagName) FSanitizeFlagName,
385*7c3d14c8STreehugger Robot #include "ubsan_checks.inc"
386*7c3d14c8STreehugger Robot #undef UBSAN_CHECK
387*7c3d14c8STreehugger Robot     kVptrCheck,
388*7c3d14c8STreehugger Robot };
389*7c3d14c8STreehugger Robot 
InitializeSuppressions()390*7c3d14c8STreehugger Robot void __ubsan::InitializeSuppressions() {
391*7c3d14c8STreehugger Robot   CHECK_EQ(nullptr, suppression_ctx);
392*7c3d14c8STreehugger Robot   suppression_ctx = new (suppression_placeholder) // NOLINT
393*7c3d14c8STreehugger Robot       SuppressionContext(kSuppressionTypes, ARRAY_SIZE(kSuppressionTypes));
394*7c3d14c8STreehugger Robot   suppression_ctx->ParseFromFile(flags()->suppressions);
395*7c3d14c8STreehugger Robot }
396*7c3d14c8STreehugger Robot 
IsVptrCheckSuppressed(const char * TypeName)397*7c3d14c8STreehugger Robot bool __ubsan::IsVptrCheckSuppressed(const char *TypeName) {
398*7c3d14c8STreehugger Robot   InitAsStandaloneIfNecessary();
399*7c3d14c8STreehugger Robot   CHECK(suppression_ctx);
400*7c3d14c8STreehugger Robot   Suppression *s;
401*7c3d14c8STreehugger Robot   return suppression_ctx->Match(TypeName, kVptrCheck, &s);
402*7c3d14c8STreehugger Robot }
403*7c3d14c8STreehugger Robot 
IsPCSuppressed(ErrorType ET,uptr PC,const char * Filename)404*7c3d14c8STreehugger Robot bool __ubsan::IsPCSuppressed(ErrorType ET, uptr PC, const char *Filename) {
405*7c3d14c8STreehugger Robot   InitAsStandaloneIfNecessary();
406*7c3d14c8STreehugger Robot   CHECK(suppression_ctx);
407*7c3d14c8STreehugger Robot   const char *SuppType = ConvertTypeToFlagName(ET);
408*7c3d14c8STreehugger Robot   // Fast path: don't symbolize PC if there is no suppressions for given UB
409*7c3d14c8STreehugger Robot   // type.
410*7c3d14c8STreehugger Robot   if (!suppression_ctx->HasSuppressionType(SuppType))
411*7c3d14c8STreehugger Robot     return false;
412*7c3d14c8STreehugger Robot   Suppression *s = nullptr;
413*7c3d14c8STreehugger Robot   // Suppress by file name known to runtime.
414*7c3d14c8STreehugger Robot   if (Filename != nullptr && suppression_ctx->Match(Filename, SuppType, &s))
415*7c3d14c8STreehugger Robot     return true;
416*7c3d14c8STreehugger Robot   // Suppress by module name.
417*7c3d14c8STreehugger Robot   if (const char *Module = Symbolizer::GetOrInit()->GetModuleNameForPc(PC)) {
418*7c3d14c8STreehugger Robot     if (suppression_ctx->Match(Module, SuppType, &s))
419*7c3d14c8STreehugger Robot       return true;
420*7c3d14c8STreehugger Robot   }
421*7c3d14c8STreehugger Robot   // Suppress by function or source file name from debug info.
422*7c3d14c8STreehugger Robot   SymbolizedStackHolder Stack(Symbolizer::GetOrInit()->SymbolizePC(PC));
423*7c3d14c8STreehugger Robot   const AddressInfo &AI = Stack.get()->info;
424*7c3d14c8STreehugger Robot   return suppression_ctx->Match(AI.function, SuppType, &s) ||
425*7c3d14c8STreehugger Robot          suppression_ctx->Match(AI.file, SuppType, &s);
426*7c3d14c8STreehugger Robot }
427*7c3d14c8STreehugger Robot 
428*7c3d14c8STreehugger Robot #endif  // CAN_SANITIZE_UB
429