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