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