xref: /aosp_15_r20/external/compiler-rt/lib/msan/msan_report.cc (revision 7c3d14c8b49c529e04be81a3ce6f5cc23712e4c6)
1*7c3d14c8STreehugger Robot //===-- msan_report.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 // This file is a part of MemorySanitizer.
11*7c3d14c8STreehugger Robot //
12*7c3d14c8STreehugger Robot // Error reporting.
13*7c3d14c8STreehugger Robot //===----------------------------------------------------------------------===//
14*7c3d14c8STreehugger Robot 
15*7c3d14c8STreehugger Robot #include "msan.h"
16*7c3d14c8STreehugger Robot #include "msan_chained_origin_depot.h"
17*7c3d14c8STreehugger Robot #include "msan_origin.h"
18*7c3d14c8STreehugger Robot #include "sanitizer_common/sanitizer_allocator_internal.h"
19*7c3d14c8STreehugger Robot #include "sanitizer_common/sanitizer_common.h"
20*7c3d14c8STreehugger Robot #include "sanitizer_common/sanitizer_flags.h"
21*7c3d14c8STreehugger Robot #include "sanitizer_common/sanitizer_mutex.h"
22*7c3d14c8STreehugger Robot #include "sanitizer_common/sanitizer_report_decorator.h"
23*7c3d14c8STreehugger Robot #include "sanitizer_common/sanitizer_stackdepot.h"
24*7c3d14c8STreehugger Robot #include "sanitizer_common/sanitizer_symbolizer.h"
25*7c3d14c8STreehugger Robot 
26*7c3d14c8STreehugger Robot using namespace __sanitizer;
27*7c3d14c8STreehugger Robot 
28*7c3d14c8STreehugger Robot namespace __msan {
29*7c3d14c8STreehugger Robot 
30*7c3d14c8STreehugger Robot class Decorator: public __sanitizer::SanitizerCommonDecorator {
31*7c3d14c8STreehugger Robot  public:
Decorator()32*7c3d14c8STreehugger Robot   Decorator() : SanitizerCommonDecorator() { }
Warning()33*7c3d14c8STreehugger Robot   const char *Warning()    { return Red(); }
Origin()34*7c3d14c8STreehugger Robot   const char *Origin()     { return Magenta(); }
Name()35*7c3d14c8STreehugger Robot   const char *Name()   { return Green(); }
End()36*7c3d14c8STreehugger Robot   const char *End()    { return Default(); }
37*7c3d14c8STreehugger Robot };
38*7c3d14c8STreehugger Robot 
DescribeStackOrigin(const char * so,uptr pc)39*7c3d14c8STreehugger Robot static void DescribeStackOrigin(const char *so, uptr pc) {
40*7c3d14c8STreehugger Robot   Decorator d;
41*7c3d14c8STreehugger Robot   char *s = internal_strdup(so);
42*7c3d14c8STreehugger Robot   char *sep = internal_strchr(s, '@');
43*7c3d14c8STreehugger Robot   CHECK(sep);
44*7c3d14c8STreehugger Robot   *sep = '\0';
45*7c3d14c8STreehugger Robot   Printf("%s", d.Origin());
46*7c3d14c8STreehugger Robot   Printf(
47*7c3d14c8STreehugger Robot       "  %sUninitialized value was created by an allocation of '%s%s%s'"
48*7c3d14c8STreehugger Robot       " in the stack frame of function '%s%s%s'%s\n",
49*7c3d14c8STreehugger Robot       d.Origin(), d.Name(), s, d.Origin(), d.Name(), sep + 1, d.Origin(),
50*7c3d14c8STreehugger Robot       d.End());
51*7c3d14c8STreehugger Robot   InternalFree(s);
52*7c3d14c8STreehugger Robot 
53*7c3d14c8STreehugger Robot   if (pc) {
54*7c3d14c8STreehugger Robot     // For some reason function address in LLVM IR is 1 less then the address
55*7c3d14c8STreehugger Robot     // of the first instruction.
56*7c3d14c8STreehugger Robot     pc = StackTrace::GetNextInstructionPc(pc);
57*7c3d14c8STreehugger Robot     StackTrace(&pc, 1).Print();
58*7c3d14c8STreehugger Robot   }
59*7c3d14c8STreehugger Robot }
60*7c3d14c8STreehugger Robot 
DescribeOrigin(u32 id)61*7c3d14c8STreehugger Robot static void DescribeOrigin(u32 id) {
62*7c3d14c8STreehugger Robot   VPrintf(1, "  raw origin id: %d\n", id);
63*7c3d14c8STreehugger Robot   Decorator d;
64*7c3d14c8STreehugger Robot   Origin o = Origin::FromRawId(id);
65*7c3d14c8STreehugger Robot   while (o.isChainedOrigin()) {
66*7c3d14c8STreehugger Robot     StackTrace stack;
67*7c3d14c8STreehugger Robot     o = o.getNextChainedOrigin(&stack);
68*7c3d14c8STreehugger Robot     Printf("  %sUninitialized value was stored to memory at%s\n", d.Origin(),
69*7c3d14c8STreehugger Robot         d.End());
70*7c3d14c8STreehugger Robot     stack.Print();
71*7c3d14c8STreehugger Robot   }
72*7c3d14c8STreehugger Robot   if (o.isStackOrigin()) {
73*7c3d14c8STreehugger Robot     uptr pc;
74*7c3d14c8STreehugger Robot     const char *so = GetStackOriginDescr(o.getStackId(), &pc);
75*7c3d14c8STreehugger Robot     DescribeStackOrigin(so, pc);
76*7c3d14c8STreehugger Robot   } else {
77*7c3d14c8STreehugger Robot     StackTrace stack = o.getStackTraceForHeapOrigin();
78*7c3d14c8STreehugger Robot     switch (stack.tag) {
79*7c3d14c8STreehugger Robot       case StackTrace::TAG_ALLOC:
80*7c3d14c8STreehugger Robot         Printf("  %sUninitialized value was created by a heap allocation%s\n",
81*7c3d14c8STreehugger Robot                d.Origin(), d.End());
82*7c3d14c8STreehugger Robot         break;
83*7c3d14c8STreehugger Robot       case StackTrace::TAG_DEALLOC:
84*7c3d14c8STreehugger Robot         Printf("  %sUninitialized value was created by a heap deallocation%s\n",
85*7c3d14c8STreehugger Robot                d.Origin(), d.End());
86*7c3d14c8STreehugger Robot         break;
87*7c3d14c8STreehugger Robot       case STACK_TRACE_TAG_POISON:
88*7c3d14c8STreehugger Robot         Printf("  %sMemory was marked as uninitialized%s\n", d.Origin(),
89*7c3d14c8STreehugger Robot                d.End());
90*7c3d14c8STreehugger Robot         break;
91*7c3d14c8STreehugger Robot       default:
92*7c3d14c8STreehugger Robot         Printf("  %sUninitialized value was created%s\n", d.Origin(), d.End());
93*7c3d14c8STreehugger Robot         break;
94*7c3d14c8STreehugger Robot     }
95*7c3d14c8STreehugger Robot     stack.Print();
96*7c3d14c8STreehugger Robot   }
97*7c3d14c8STreehugger Robot }
98*7c3d14c8STreehugger Robot 
ReportUMR(StackTrace * stack,u32 origin)99*7c3d14c8STreehugger Robot void ReportUMR(StackTrace *stack, u32 origin) {
100*7c3d14c8STreehugger Robot   if (!__msan::flags()->report_umrs) return;
101*7c3d14c8STreehugger Robot 
102*7c3d14c8STreehugger Robot   SpinMutexLock l(&CommonSanitizerReportMutex);
103*7c3d14c8STreehugger Robot 
104*7c3d14c8STreehugger Robot   Decorator d;
105*7c3d14c8STreehugger Robot   Printf("%s", d.Warning());
106*7c3d14c8STreehugger Robot   Report("WARNING: MemorySanitizer: use-of-uninitialized-value\n");
107*7c3d14c8STreehugger Robot   Printf("%s", d.End());
108*7c3d14c8STreehugger Robot   stack->Print();
109*7c3d14c8STreehugger Robot   if (origin) {
110*7c3d14c8STreehugger Robot     DescribeOrigin(origin);
111*7c3d14c8STreehugger Robot   }
112*7c3d14c8STreehugger Robot   ReportErrorSummary("use-of-uninitialized-value", stack);
113*7c3d14c8STreehugger Robot }
114*7c3d14c8STreehugger Robot 
ReportExpectedUMRNotFound(StackTrace * stack)115*7c3d14c8STreehugger Robot void ReportExpectedUMRNotFound(StackTrace *stack) {
116*7c3d14c8STreehugger Robot   SpinMutexLock l(&CommonSanitizerReportMutex);
117*7c3d14c8STreehugger Robot 
118*7c3d14c8STreehugger Robot   Printf("WARNING: Expected use of uninitialized value not found\n");
119*7c3d14c8STreehugger Robot   stack->Print();
120*7c3d14c8STreehugger Robot }
121*7c3d14c8STreehugger Robot 
ReportStats()122*7c3d14c8STreehugger Robot void ReportStats() {
123*7c3d14c8STreehugger Robot   SpinMutexLock l(&CommonSanitizerReportMutex);
124*7c3d14c8STreehugger Robot 
125*7c3d14c8STreehugger Robot   if (__msan_get_track_origins() > 0) {
126*7c3d14c8STreehugger Robot     StackDepotStats *stack_depot_stats = StackDepotGetStats();
127*7c3d14c8STreehugger Robot     // FIXME: we want this at normal exit, too!
128*7c3d14c8STreehugger Robot     // FIXME: but only with verbosity=1 or something
129*7c3d14c8STreehugger Robot     Printf("Unique heap origins: %zu\n", stack_depot_stats->n_uniq_ids);
130*7c3d14c8STreehugger Robot     Printf("Stack depot allocated bytes: %zu\n", stack_depot_stats->allocated);
131*7c3d14c8STreehugger Robot 
132*7c3d14c8STreehugger Robot     StackDepotStats *chained_origin_depot_stats = ChainedOriginDepotGetStats();
133*7c3d14c8STreehugger Robot     Printf("Unique origin histories: %zu\n",
134*7c3d14c8STreehugger Robot            chained_origin_depot_stats->n_uniq_ids);
135*7c3d14c8STreehugger Robot     Printf("History depot allocated bytes: %zu\n",
136*7c3d14c8STreehugger Robot            chained_origin_depot_stats->allocated);
137*7c3d14c8STreehugger Robot   }
138*7c3d14c8STreehugger Robot }
139*7c3d14c8STreehugger Robot 
ReportAtExitStatistics()140*7c3d14c8STreehugger Robot void ReportAtExitStatistics() {
141*7c3d14c8STreehugger Robot   SpinMutexLock l(&CommonSanitizerReportMutex);
142*7c3d14c8STreehugger Robot 
143*7c3d14c8STreehugger Robot   if (msan_report_count > 0) {
144*7c3d14c8STreehugger Robot     Decorator d;
145*7c3d14c8STreehugger Robot     Printf("%s", d.Warning());
146*7c3d14c8STreehugger Robot     Printf("MemorySanitizer: %d warnings reported.\n", msan_report_count);
147*7c3d14c8STreehugger Robot     Printf("%s", d.End());
148*7c3d14c8STreehugger Robot   }
149*7c3d14c8STreehugger Robot }
150*7c3d14c8STreehugger Robot 
151*7c3d14c8STreehugger Robot class OriginSet {
152*7c3d14c8STreehugger Robot  public:
OriginSet()153*7c3d14c8STreehugger Robot   OriginSet() : next_id_(0) {}
insert(u32 o)154*7c3d14c8STreehugger Robot   int insert(u32 o) {
155*7c3d14c8STreehugger Robot     // Scan from the end for better locality.
156*7c3d14c8STreehugger Robot     for (int i = next_id_ - 1; i >= 0; --i)
157*7c3d14c8STreehugger Robot       if (origins_[i] == o) return i;
158*7c3d14c8STreehugger Robot     if (next_id_ == kMaxSize_) return OVERFLOW;
159*7c3d14c8STreehugger Robot     int id = next_id_++;
160*7c3d14c8STreehugger Robot     origins_[id] = o;
161*7c3d14c8STreehugger Robot     return id;
162*7c3d14c8STreehugger Robot   }
size()163*7c3d14c8STreehugger Robot   int size() { return next_id_; }
get(int id)164*7c3d14c8STreehugger Robot   u32 get(int id) { return origins_[id]; }
asChar(int id)165*7c3d14c8STreehugger Robot   static char asChar(int id) {
166*7c3d14c8STreehugger Robot     switch (id) {
167*7c3d14c8STreehugger Robot       case MISSING:
168*7c3d14c8STreehugger Robot         return '.';
169*7c3d14c8STreehugger Robot       case OVERFLOW:
170*7c3d14c8STreehugger Robot         return '*';
171*7c3d14c8STreehugger Robot       default:
172*7c3d14c8STreehugger Robot         return 'A' + id;
173*7c3d14c8STreehugger Robot     }
174*7c3d14c8STreehugger Robot   }
175*7c3d14c8STreehugger Robot   static const int OVERFLOW = -1;
176*7c3d14c8STreehugger Robot   static const int MISSING = -2;
177*7c3d14c8STreehugger Robot 
178*7c3d14c8STreehugger Robot  private:
179*7c3d14c8STreehugger Robot   static const int kMaxSize_ = 'Z' - 'A' + 1;
180*7c3d14c8STreehugger Robot   u32 origins_[kMaxSize_];
181*7c3d14c8STreehugger Robot   int next_id_;
182*7c3d14c8STreehugger Robot };
183*7c3d14c8STreehugger Robot 
DescribeMemoryRange(const void * x,uptr size)184*7c3d14c8STreehugger Robot void DescribeMemoryRange(const void *x, uptr size) {
185*7c3d14c8STreehugger Robot   // Real limits.
186*7c3d14c8STreehugger Robot   uptr start = MEM_TO_SHADOW(x);
187*7c3d14c8STreehugger Robot   uptr end = start + size;
188*7c3d14c8STreehugger Robot   // Scan limits: align start down to 4; align size up to 16.
189*7c3d14c8STreehugger Robot   uptr s = start & ~3UL;
190*7c3d14c8STreehugger Robot   size = end - s;
191*7c3d14c8STreehugger Robot   size = (size + 15) & ~15UL;
192*7c3d14c8STreehugger Robot   uptr e = s + size;
193*7c3d14c8STreehugger Robot 
194*7c3d14c8STreehugger Robot   // Single letter names to origin id mapping.
195*7c3d14c8STreehugger Robot   OriginSet origin_set;
196*7c3d14c8STreehugger Robot 
197*7c3d14c8STreehugger Robot   uptr pos = 0;  // Offset from aligned start.
198*7c3d14c8STreehugger Robot   bool with_origins = __msan_get_track_origins();
199*7c3d14c8STreehugger Robot   // True if there is at least 1 poisoned bit in the last 4-byte group.
200*7c3d14c8STreehugger Robot   bool last_quad_poisoned;
201*7c3d14c8STreehugger Robot   int origin_ids[4];  // Single letter origin ids for the current line.
202*7c3d14c8STreehugger Robot 
203*7c3d14c8STreehugger Robot   Decorator d;
204*7c3d14c8STreehugger Robot   Printf("%s", d.Warning());
205*7c3d14c8STreehugger Robot   Printf("Shadow map of [%p, %p), %zu bytes:\n", start, end, end - start);
206*7c3d14c8STreehugger Robot   Printf("%s", d.End());
207*7c3d14c8STreehugger Robot   while (s < e) {
208*7c3d14c8STreehugger Robot     // Line start.
209*7c3d14c8STreehugger Robot     if (pos % 16 == 0) {
210*7c3d14c8STreehugger Robot       for (int i = 0; i < 4; ++i) origin_ids[i] = -1;
211*7c3d14c8STreehugger Robot       Printf("%p:", s);
212*7c3d14c8STreehugger Robot     }
213*7c3d14c8STreehugger Robot     // Group start.
214*7c3d14c8STreehugger Robot     if (pos % 4 == 0) {
215*7c3d14c8STreehugger Robot       Printf(" ");
216*7c3d14c8STreehugger Robot       last_quad_poisoned = false;
217*7c3d14c8STreehugger Robot     }
218*7c3d14c8STreehugger Robot     // Print shadow byte.
219*7c3d14c8STreehugger Robot     if (s < start || s >= end) {
220*7c3d14c8STreehugger Robot       Printf("..");
221*7c3d14c8STreehugger Robot     } else {
222*7c3d14c8STreehugger Robot       unsigned char v = *(unsigned char *)s;
223*7c3d14c8STreehugger Robot       if (v) last_quad_poisoned = true;
224*7c3d14c8STreehugger Robot       Printf("%x%x", v >> 4, v & 0xf);
225*7c3d14c8STreehugger Robot     }
226*7c3d14c8STreehugger Robot     // Group end.
227*7c3d14c8STreehugger Robot     if (pos % 4 == 3 && with_origins) {
228*7c3d14c8STreehugger Robot       int id = OriginSet::MISSING;
229*7c3d14c8STreehugger Robot       if (last_quad_poisoned) {
230*7c3d14c8STreehugger Robot         u32 o = *(u32 *)SHADOW_TO_ORIGIN(s - 3);
231*7c3d14c8STreehugger Robot         id = origin_set.insert(o);
232*7c3d14c8STreehugger Robot       }
233*7c3d14c8STreehugger Robot       origin_ids[(pos % 16) / 4] = id;
234*7c3d14c8STreehugger Robot     }
235*7c3d14c8STreehugger Robot     // Line end.
236*7c3d14c8STreehugger Robot     if (pos % 16 == 15) {
237*7c3d14c8STreehugger Robot       if (with_origins) {
238*7c3d14c8STreehugger Robot         Printf("  |");
239*7c3d14c8STreehugger Robot         for (int i = 0; i < 4; ++i) {
240*7c3d14c8STreehugger Robot           char c = OriginSet::asChar(origin_ids[i]);
241*7c3d14c8STreehugger Robot           Printf("%c", c);
242*7c3d14c8STreehugger Robot           if (i != 3) Printf(" ");
243*7c3d14c8STreehugger Robot         }
244*7c3d14c8STreehugger Robot         Printf("|");
245*7c3d14c8STreehugger Robot       }
246*7c3d14c8STreehugger Robot       Printf("\n");
247*7c3d14c8STreehugger Robot     }
248*7c3d14c8STreehugger Robot     size--;
249*7c3d14c8STreehugger Robot     s++;
250*7c3d14c8STreehugger Robot     pos++;
251*7c3d14c8STreehugger Robot   }
252*7c3d14c8STreehugger Robot 
253*7c3d14c8STreehugger Robot   Printf("\n");
254*7c3d14c8STreehugger Robot 
255*7c3d14c8STreehugger Robot   for (int i = 0; i < origin_set.size(); ++i) {
256*7c3d14c8STreehugger Robot     u32 o = origin_set.get(i);
257*7c3d14c8STreehugger Robot     Printf("Origin %c (origin_id %x):\n", OriginSet::asChar(i), o);
258*7c3d14c8STreehugger Robot     DescribeOrigin(o);
259*7c3d14c8STreehugger Robot   }
260*7c3d14c8STreehugger Robot }
261*7c3d14c8STreehugger Robot 
ReportUMRInsideAddressRange(const char * what,const void * start,uptr size,uptr offset)262*7c3d14c8STreehugger Robot void ReportUMRInsideAddressRange(const char *what, const void *start, uptr size,
263*7c3d14c8STreehugger Robot                                  uptr offset) {
264*7c3d14c8STreehugger Robot   Decorator d;
265*7c3d14c8STreehugger Robot   Printf("%s", d.Warning());
266*7c3d14c8STreehugger Robot   Printf("%sUninitialized bytes in %s%s%s at offset %zu inside [%p, %zu)%s\n",
267*7c3d14c8STreehugger Robot          d.Warning(), d.Name(), what, d.Warning(), offset, start, size,
268*7c3d14c8STreehugger Robot          d.End());
269*7c3d14c8STreehugger Robot   if (__sanitizer::Verbosity())
270*7c3d14c8STreehugger Robot     DescribeMemoryRange(start, size);
271*7c3d14c8STreehugger Robot }
272*7c3d14c8STreehugger Robot 
273*7c3d14c8STreehugger Robot }  // namespace __msan
274