blob: e4ca4e4afdc02c48496e4f73e22bf1890a7d4b30 [file] [log] [blame]
Richard Smith6ebe4512012-10-09 19:34:32 +00001//===-- 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"
Richard Smithf4932202012-11-13 23:42:05 +000015#include "sanitizer_common/sanitizer_common.h"
16#include "sanitizer_common/sanitizer_libc.h"
Alexey Samsonov8f72f7c2013-02-27 12:58:24 +000017#include "sanitizer_common/sanitizer_report_decorator.h"
Richard Smith5f116492012-12-18 04:23:18 +000018#include "sanitizer_common/sanitizer_stacktrace.h"
19#include "sanitizer_common/sanitizer_symbolizer.h"
Richard Smith6ebe4512012-10-09 19:34:32 +000020#include <stdio.h>
Richard Smith6ebe4512012-10-09 19:34:32 +000021
22using namespace __ubsan;
23
Richard Smith5f116492012-12-18 04:23:18 +000024Location __ubsan::getCallerLocation(uptr CallerLoc) {
25 if (!CallerLoc)
26 return Location();
27
Alexey Samsonovd2f08ff2012-12-18 09:57:34 +000028 uptr Loc = StackTrace::GetPreviousInstructionPc(CallerLoc);
Richard Smith5f116492012-12-18 04:23:18 +000029
30 AddressInfo Info;
Alexey Samsonov7847d772013-09-10 14:36:16 +000031 if (!getSymbolizer()->SymbolizeCode(Loc, &Info, 1) ||
32 !Info.module || !*Info.module)
Alexey Samsonovd2f08ff2012-12-18 09:57:34 +000033 return Location(Loc);
Richard Smith5f116492012-12-18 04:23:18 +000034
Alexey Samsonov7ed46ff2013-04-05 07:30:29 +000035 if (!Info.file)
Richard Smith5f116492012-12-18 04:23:18 +000036 return ModuleLocation(Info.module, Info.module_offset);
37
38 return SourceLocation(Info.file, Info.line, Info.column);
39}
40
Richard Smith6ebe4512012-10-09 19:34:32 +000041Diag &Diag::operator<<(const TypeDescriptor &V) {
42 return AddArg(V.getTypeName());
43}
44
45Diag &Diag::operator<<(const Value &V) {
46 if (V.getType().isSignedIntegerTy())
47 AddArg(V.getSIntValue());
48 else if (V.getType().isUnsignedIntegerTy())
49 AddArg(V.getUIntValue());
Richard Smith58561702012-10-12 22:57:15 +000050 else if (V.getType().isFloatTy())
51 AddArg(V.getFloatValue());
Richard Smith6ebe4512012-10-09 19:34:32 +000052 else
53 AddArg("<unknown>");
54 return *this;
55}
56
Richard Smith0ad23f72012-12-18 09:30:21 +000057/// Hexadecimal printing for numbers too large for Printf to handle directly.
Richard Smith6ebe4512012-10-09 19:34:32 +000058static void PrintHex(UIntMax Val) {
Chandler Carruthba3fde62012-10-13 02:30:10 +000059#if HAVE_INT128_T
Richard Smithf4932202012-11-13 23:42:05 +000060 Printf("0x%08x%08x%08x%08x",
Richard Smith6ebe4512012-10-09 19:34:32 +000061 (unsigned int)(Val >> 96),
62 (unsigned int)(Val >> 64),
63 (unsigned int)(Val >> 32),
64 (unsigned int)(Val));
65#else
66 UNREACHABLE("long long smaller than 64 bits?");
67#endif
68}
69
Richard Smith5f116492012-12-18 04:23:18 +000070static void renderLocation(Location Loc) {
71 switch (Loc.getKind()) {
72 case Location::LK_Source: {
73 SourceLocation SLoc = Loc.getSourceLocation();
74 if (SLoc.isInvalid())
Alexey Samsonov90b0f1e2013-10-04 08:55:03 +000075 Printf("<unknown>");
76 else
77 PrintSourceLocation(SLoc.getFilename(), SLoc.getLine(), SLoc.getColumn());
Richard Smith5f116492012-12-18 04:23:18 +000078 break;
79 }
80 case Location::LK_Module:
Alexey Samsonov90b0f1e2013-10-04 08:55:03 +000081 PrintModuleAndOffset(Loc.getModuleLocation().getModuleName(),
82 Loc.getModuleLocation().getOffset());
Richard Smith5f116492012-12-18 04:23:18 +000083 break;
84 case Location::LK_Memory:
Alexey Samsonov90b0f1e2013-10-04 08:55:03 +000085 Printf("%p", Loc.getMemoryLocation());
Richard Smith5f116492012-12-18 04:23:18 +000086 break;
87 case Location::LK_Null:
Alexey Samsonov90b0f1e2013-10-04 08:55:03 +000088 Printf("<unknown>");
Richard Smith25ee97f2012-12-18 06:30:32 +000089 break;
Richard Smith5f116492012-12-18 04:23:18 +000090 }
Alexey Samsonov90b0f1e2013-10-04 08:55:03 +000091 Printf(":");
Richard Smith5f116492012-12-18 04:23:18 +000092}
93
Richard Smith25ee97f2012-12-18 06:30:32 +000094static void renderText(const char *Message, const Diag::Arg *Args) {
Richard Smith6ebe4512012-10-09 19:34:32 +000095 for (const char *Msg = Message; *Msg; ++Msg) {
Richard Smithf4932202012-11-13 23:42:05 +000096 if (*Msg != '%') {
97 char Buffer[64];
98 unsigned I;
99 for (I = 0; Msg[I] && Msg[I] != '%' && I != 63; ++I)
100 Buffer[I] = Msg[I];
101 Buffer[I] = '\0';
Alexey Samsonov8f72f7c2013-02-27 12:58:24 +0000102 Printf(Buffer);
Richard Smithf4932202012-11-13 23:42:05 +0000103 Msg += I - 1;
104 } else {
Richard Smith25ee97f2012-12-18 06:30:32 +0000105 const Diag::Arg &A = Args[*++Msg - '0'];
Richard Smith6ebe4512012-10-09 19:34:32 +0000106 switch (A.Kind) {
Richard Smith25ee97f2012-12-18 06:30:32 +0000107 case Diag::AK_String:
Richard Smithf4932202012-11-13 23:42:05 +0000108 Printf("%s", A.String);
Richard Smith6ebe4512012-10-09 19:34:32 +0000109 break;
Richard Smith0ad23f72012-12-18 09:30:21 +0000110 case Diag::AK_Mangled: {
Alexey Samsonov7847d772013-09-10 14:36:16 +0000111 Printf("'%s'", getSymbolizer()->Demangle(A.String));
Richard Smith0ad23f72012-12-18 09:30:21 +0000112 break;
113 }
Richard Smith25ee97f2012-12-18 06:30:32 +0000114 case Diag::AK_SInt:
Richard Smith6ebe4512012-10-09 19:34:32 +0000115 // 'long long' is guaranteed to be at least 64 bits wide.
116 if (A.SInt >= INT64_MIN && A.SInt <= INT64_MAX)
Richard Smithf4932202012-11-13 23:42:05 +0000117 Printf("%lld", (long long)A.SInt);
Richard Smith6ebe4512012-10-09 19:34:32 +0000118 else
119 PrintHex(A.SInt);
120 break;
Richard Smith25ee97f2012-12-18 06:30:32 +0000121 case Diag::AK_UInt:
Richard Smith6ebe4512012-10-09 19:34:32 +0000122 if (A.UInt <= UINT64_MAX)
Richard Smithf4932202012-11-13 23:42:05 +0000123 Printf("%llu", (unsigned long long)A.UInt);
Richard Smith6ebe4512012-10-09 19:34:32 +0000124 else
125 PrintHex(A.UInt);
126 break;
Richard Smith25ee97f2012-12-18 06:30:32 +0000127 case Diag::AK_Float: {
Richard Smithf4932202012-11-13 23:42:05 +0000128 // FIXME: Support floating-point formatting in sanitizer_common's
129 // printf, and stop using snprintf here.
130 char Buffer[32];
131 snprintf(Buffer, sizeof(Buffer), "%Lg", (long double)A.Float);
132 Printf("%s", Buffer);
Richard Smith58561702012-10-12 22:57:15 +0000133 break;
Richard Smithf4932202012-11-13 23:42:05 +0000134 }
Richard Smith25ee97f2012-12-18 06:30:32 +0000135 case Diag::AK_Pointer:
Richard Smithc1939532013-01-10 22:39:40 +0000136 Printf("%p", A.Pointer);
Richard Smith6ebe4512012-10-09 19:34:32 +0000137 break;
138 }
139 }
140 }
Richard Smith25ee97f2012-12-18 06:30:32 +0000141}
142
143/// Find the earliest-starting range in Ranges which ends after Loc.
144static Range *upperBound(MemoryLocation Loc, Range *Ranges,
145 unsigned NumRanges) {
146 Range *Best = 0;
147 for (unsigned I = 0; I != NumRanges; ++I)
148 if (Ranges[I].getEnd().getMemoryLocation() > Loc &&
149 (!Best ||
150 Best->getStart().getMemoryLocation() >
151 Ranges[I].getStart().getMemoryLocation()))
152 Best = &Ranges[I];
153 return Best;
154}
155
156/// Render a snippet of the address space near a location.
Alexey Samsonov8f72f7c2013-02-27 12:58:24 +0000157static void renderMemorySnippet(const __sanitizer::AnsiColorDecorator &Decor,
158 MemoryLocation Loc,
Richard Smith25ee97f2012-12-18 06:30:32 +0000159 Range *Ranges, unsigned NumRanges,
160 const Diag::Arg *Args) {
161 const unsigned BytesToShow = 32;
162 const unsigned MinBytesNearLoc = 4;
163
164 // Show at least the 8 bytes surrounding Loc.
165 MemoryLocation Min = Loc - MinBytesNearLoc, Max = Loc + MinBytesNearLoc;
166 for (unsigned I = 0; I < NumRanges; ++I) {
167 Min = __sanitizer::Min(Ranges[I].getStart().getMemoryLocation(), Min);
168 Max = __sanitizer::Max(Ranges[I].getEnd().getMemoryLocation(), Max);
169 }
170
171 // If we have too many interesting bytes, prefer to show bytes after Loc.
172 if (Max - Min > BytesToShow)
173 Min = __sanitizer::Min(Max - BytesToShow, Loc - MinBytesNearLoc);
174 Max = Min + BytesToShow;
175
176 // Emit data.
177 for (uptr P = Min; P != Max; ++P) {
178 // FIXME: Check that the address is readable before printing it.
179 unsigned char C = *reinterpret_cast<const unsigned char*>(P);
180 Printf("%s%02x", (P % 8 == 0) ? " " : " ", C);
181 }
Alexey Samsonov8f72f7c2013-02-27 12:58:24 +0000182 Printf("\n");
Richard Smith25ee97f2012-12-18 06:30:32 +0000183
184 // Emit highlights.
Alexey Samsonov8f72f7c2013-02-27 12:58:24 +0000185 Printf(Decor.Green());
Richard Smith25ee97f2012-12-18 06:30:32 +0000186 Range *InRange = upperBound(Min, Ranges, NumRanges);
187 for (uptr P = Min; P != Max; ++P) {
188 char Pad = ' ', Byte = ' ';
189 if (InRange && InRange->getEnd().getMemoryLocation() == P)
190 InRange = upperBound(P, Ranges, NumRanges);
191 if (!InRange && P > Loc)
192 break;
193 if (InRange && InRange->getStart().getMemoryLocation() < P)
194 Pad = '~';
195 if (InRange && InRange->getStart().getMemoryLocation() <= P)
196 Byte = '~';
197 char Buffer[] = { Pad, Pad, P == Loc ? '^' : Byte, Byte, 0 };
Alexey Samsonov8f72f7c2013-02-27 12:58:24 +0000198 Printf((P % 8 == 0) ? Buffer : &Buffer[1]);
Richard Smith25ee97f2012-12-18 06:30:32 +0000199 }
Alexey Samsonov8f72f7c2013-02-27 12:58:24 +0000200 Printf("%s\n", Decor.Default());
Richard Smith25ee97f2012-12-18 06:30:32 +0000201
202 // Go over the line again, and print names for the ranges.
203 InRange = 0;
204 unsigned Spaces = 0;
205 for (uptr P = Min; P != Max; ++P) {
206 if (!InRange || InRange->getEnd().getMemoryLocation() == P)
207 InRange = upperBound(P, Ranges, NumRanges);
208 if (!InRange)
209 break;
210
211 Spaces += (P % 8) == 0 ? 2 : 1;
212
213 if (InRange && InRange->getStart().getMemoryLocation() == P) {
214 while (Spaces--)
Alexey Samsonov8f72f7c2013-02-27 12:58:24 +0000215 Printf(" ");
Richard Smith25ee97f2012-12-18 06:30:32 +0000216 renderText(InRange->getText(), Args);
Alexey Samsonov8f72f7c2013-02-27 12:58:24 +0000217 Printf("\n");
Richard Smith25ee97f2012-12-18 06:30:32 +0000218 // FIXME: We only support naming one range for now!
219 break;
220 }
221
222 Spaces += 2;
223 }
224
225 // FIXME: Print names for anything we can identify within the line:
226 //
227 // * If we can identify the memory itself as belonging to a particular
228 // global, stack variable, or dynamic allocation, then do so.
229 //
230 // * If we have a pointer-size, pointer-aligned range highlighted,
231 // determine whether the value of that range is a pointer to an
232 // entity which we can name, and if so, print that name.
233 //
234 // This needs an external symbolizer, or (preferably) ASan instrumentation.
235}
236
237Diag::~Diag() {
Alexey Samsonov8f72f7c2013-02-27 12:58:24 +0000238 __sanitizer::AnsiColorDecorator Decor(PrintsToTty());
Alexey Samsonov7ed46ff2013-04-05 07:30:29 +0000239 SpinMutexLock l(&CommonSanitizerReportMutex);
Alexey Samsonov8f72f7c2013-02-27 12:58:24 +0000240 Printf(Decor.Bold());
Richard Smith25ee97f2012-12-18 06:30:32 +0000241
242 renderLocation(Loc);
243
244 switch (Level) {
245 case DL_Error:
Alexey Samsonov8f72f7c2013-02-27 12:58:24 +0000246 Printf("%s runtime error: %s%s",
247 Decor.Red(), Decor.Default(), Decor.Bold());
Richard Smith25ee97f2012-12-18 06:30:32 +0000248 break;
249
250 case DL_Note:
Alexey Samsonov8f72f7c2013-02-27 12:58:24 +0000251 Printf("%s note: %s", Decor.Black(), Decor.Default());
Richard Smith25ee97f2012-12-18 06:30:32 +0000252 break;
253 }
254
255 renderText(Message, Args);
256
Alexey Samsonov8f72f7c2013-02-27 12:58:24 +0000257 Printf("%s\n", Decor.Default());
Richard Smith25ee97f2012-12-18 06:30:32 +0000258
259 if (Loc.isMemoryLocation())
Alexey Samsonov8f72f7c2013-02-27 12:58:24 +0000260 renderMemorySnippet(Decor, Loc.getMemoryLocation(), Ranges,
Richard Smithc2424462013-02-12 22:12:10 +0000261 NumRanges, Args);
Richard Smith6ebe4512012-10-09 19:34:32 +0000262}