• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 "sanitizer_common/sanitizer_common.h"
16 #include "sanitizer_common/sanitizer_libc.h"
17 #include "sanitizer_common/sanitizer_report_decorator.h"
18 #include "sanitizer_common/sanitizer_stacktrace.h"
19 #include "sanitizer_common/sanitizer_symbolizer.h"
20 #include <stdio.h>
21 
22 using namespace __ubsan;
23 
getCallerLocation(uptr CallerLoc)24 Location __ubsan::getCallerLocation(uptr CallerLoc) {
25   if (!CallerLoc)
26     return Location();
27 
28   uptr Loc = StackTrace::GetPreviousInstructionPc(CallerLoc);
29 
30   AddressInfo Info;
31   if (!SymbolizeCode(Loc, &Info, 1) || !Info.module || !*Info.module)
32     return Location(Loc);
33 
34   if (!Info.file)
35     return ModuleLocation(Info.module, Info.module_offset);
36 
37   return SourceLocation(Info.file, Info.line, Info.column);
38 }
39 
operator <<(const TypeDescriptor & V)40 Diag &Diag::operator<<(const TypeDescriptor &V) {
41   return AddArg(V.getTypeName());
42 }
43 
operator <<(const Value & V)44 Diag &Diag::operator<<(const Value &V) {
45   if (V.getType().isSignedIntegerTy())
46     AddArg(V.getSIntValue());
47   else if (V.getType().isUnsignedIntegerTy())
48     AddArg(V.getUIntValue());
49   else if (V.getType().isFloatTy())
50     AddArg(V.getFloatValue());
51   else
52     AddArg("<unknown>");
53   return *this;
54 }
55 
56 /// Hexadecimal printing for numbers too large for Printf to handle directly.
PrintHex(UIntMax Val)57 static void PrintHex(UIntMax Val) {
58 #if HAVE_INT128_T
59   Printf("0x%08x%08x%08x%08x",
60           (unsigned int)(Val >> 96),
61           (unsigned int)(Val >> 64),
62           (unsigned int)(Val >> 32),
63           (unsigned int)(Val));
64 #else
65   UNREACHABLE("long long smaller than 64 bits?");
66 #endif
67 }
68 
renderLocation(Location Loc)69 static void renderLocation(Location Loc) {
70   switch (Loc.getKind()) {
71   case Location::LK_Source: {
72     SourceLocation SLoc = Loc.getSourceLocation();
73     if (SLoc.isInvalid())
74       Printf("<unknown>:");
75     else {
76       Printf("%s:%d:", SLoc.getFilename(), SLoc.getLine());
77       if (SLoc.getColumn())
78         Printf("%d:", SLoc.getColumn());
79     }
80     break;
81   }
82   case Location::LK_Module:
83     Printf("%s:0x%zx:", Loc.getModuleLocation().getModuleName(),
84            Loc.getModuleLocation().getOffset());
85     break;
86   case Location::LK_Memory:
87     Printf("%p:", Loc.getMemoryLocation());
88     break;
89   case Location::LK_Null:
90     Printf("<unknown>:");
91     break;
92   }
93 }
94 
renderText(const char * Message,const Diag::Arg * Args)95 static void renderText(const char *Message, const Diag::Arg *Args) {
96   for (const char *Msg = Message; *Msg; ++Msg) {
97     if (*Msg != '%') {
98       char Buffer[64];
99       unsigned I;
100       for (I = 0; Msg[I] && Msg[I] != '%' && I != 63; ++I)
101         Buffer[I] = Msg[I];
102       Buffer[I] = '\0';
103       Printf(Buffer);
104       Msg += I - 1;
105     } else {
106       const Diag::Arg &A = Args[*++Msg - '0'];
107       switch (A.Kind) {
108       case Diag::AK_String:
109         Printf("%s", A.String);
110         break;
111       case Diag::AK_Mangled: {
112         Printf("'%s'", Demangle(A.String));
113         break;
114       }
115       case Diag::AK_SInt:
116         // 'long long' is guaranteed to be at least 64 bits wide.
117         if (A.SInt >= INT64_MIN && A.SInt <= INT64_MAX)
118           Printf("%lld", (long long)A.SInt);
119         else
120           PrintHex(A.SInt);
121         break;
122       case Diag::AK_UInt:
123         if (A.UInt <= UINT64_MAX)
124           Printf("%llu", (unsigned long long)A.UInt);
125         else
126           PrintHex(A.UInt);
127         break;
128       case Diag::AK_Float: {
129         // FIXME: Support floating-point formatting in sanitizer_common's
130         //        printf, and stop using snprintf here.
131         char Buffer[32];
132         snprintf(Buffer, sizeof(Buffer), "%Lg", (long double)A.Float);
133         Printf("%s", Buffer);
134         break;
135       }
136       case Diag::AK_Pointer:
137         Printf("%p", A.Pointer);
138         break;
139       }
140     }
141   }
142 }
143 
144 /// Find the earliest-starting range in Ranges which ends after Loc.
upperBound(MemoryLocation Loc,Range * Ranges,unsigned NumRanges)145 static Range *upperBound(MemoryLocation Loc, Range *Ranges,
146                          unsigned NumRanges) {
147   Range *Best = 0;
148   for (unsigned I = 0; I != NumRanges; ++I)
149     if (Ranges[I].getEnd().getMemoryLocation() > Loc &&
150         (!Best ||
151          Best->getStart().getMemoryLocation() >
152          Ranges[I].getStart().getMemoryLocation()))
153       Best = &Ranges[I];
154   return Best;
155 }
156 
157 /// Render a snippet of the address space near a location.
renderMemorySnippet(const __sanitizer::AnsiColorDecorator & Decor,MemoryLocation Loc,Range * Ranges,unsigned NumRanges,const Diag::Arg * Args)158 static void renderMemorySnippet(const __sanitizer::AnsiColorDecorator &Decor,
159                                 MemoryLocation Loc,
160                                 Range *Ranges, unsigned NumRanges,
161                                 const Diag::Arg *Args) {
162   const unsigned BytesToShow = 32;
163   const unsigned MinBytesNearLoc = 4;
164 
165   // Show at least the 8 bytes surrounding Loc.
166   MemoryLocation Min = Loc - MinBytesNearLoc, Max = Loc + MinBytesNearLoc;
167   for (unsigned I = 0; I < NumRanges; ++I) {
168     Min = __sanitizer::Min(Ranges[I].getStart().getMemoryLocation(), Min);
169     Max = __sanitizer::Max(Ranges[I].getEnd().getMemoryLocation(), Max);
170   }
171 
172   // If we have too many interesting bytes, prefer to show bytes after Loc.
173   if (Max - Min > BytesToShow)
174     Min = __sanitizer::Min(Max - BytesToShow, Loc - MinBytesNearLoc);
175   Max = Min + BytesToShow;
176 
177   // Emit data.
178   for (uptr P = Min; P != Max; ++P) {
179     // FIXME: Check that the address is readable before printing it.
180     unsigned char C = *reinterpret_cast<const unsigned char*>(P);
181     Printf("%s%02x", (P % 8 == 0) ? "  " : " ", C);
182   }
183   Printf("\n");
184 
185   // Emit highlights.
186   Printf(Decor.Green());
187   Range *InRange = upperBound(Min, Ranges, NumRanges);
188   for (uptr P = Min; P != Max; ++P) {
189     char Pad = ' ', Byte = ' ';
190     if (InRange && InRange->getEnd().getMemoryLocation() == P)
191       InRange = upperBound(P, Ranges, NumRanges);
192     if (!InRange && P > Loc)
193       break;
194     if (InRange && InRange->getStart().getMemoryLocation() < P)
195       Pad = '~';
196     if (InRange && InRange->getStart().getMemoryLocation() <= P)
197       Byte = '~';
198     char Buffer[] = { Pad, Pad, P == Loc ? '^' : Byte, Byte, 0 };
199     Printf((P % 8 == 0) ? Buffer : &Buffer[1]);
200   }
201   Printf("%s\n", Decor.Default());
202 
203   // Go over the line again, and print names for the ranges.
204   InRange = 0;
205   unsigned Spaces = 0;
206   for (uptr P = Min; P != Max; ++P) {
207     if (!InRange || InRange->getEnd().getMemoryLocation() == P)
208       InRange = upperBound(P, Ranges, NumRanges);
209     if (!InRange)
210       break;
211 
212     Spaces += (P % 8) == 0 ? 2 : 1;
213 
214     if (InRange && InRange->getStart().getMemoryLocation() == P) {
215       while (Spaces--)
216         Printf(" ");
217       renderText(InRange->getText(), Args);
218       Printf("\n");
219       // FIXME: We only support naming one range for now!
220       break;
221     }
222 
223     Spaces += 2;
224   }
225 
226   // FIXME: Print names for anything we can identify within the line:
227   //
228   //  * If we can identify the memory itself as belonging to a particular
229   //    global, stack variable, or dynamic allocation, then do so.
230   //
231   //  * If we have a pointer-size, pointer-aligned range highlighted,
232   //    determine whether the value of that range is a pointer to an
233   //    entity which we can name, and if so, print that name.
234   //
235   // This needs an external symbolizer, or (preferably) ASan instrumentation.
236 }
237 
~Diag()238 Diag::~Diag() {
239   __sanitizer::AnsiColorDecorator Decor(PrintsToTty());
240   SpinMutexLock l(&CommonSanitizerReportMutex);
241   Printf(Decor.Bold());
242 
243   renderLocation(Loc);
244 
245   switch (Level) {
246   case DL_Error:
247     Printf("%s runtime error: %s%s",
248            Decor.Red(), Decor.Default(), Decor.Bold());
249     break;
250 
251   case DL_Note:
252     Printf("%s note: %s", Decor.Black(), Decor.Default());
253     break;
254   }
255 
256   renderText(Message, Args);
257 
258   Printf("%s\n", Decor.Default());
259 
260   if (Loc.isMemoryLocation())
261     renderMemorySnippet(Decor, Loc.getMemoryLocation(), Ranges,
262                         NumRanges, Args);
263 }
264