1 //===-- msan_report.cc ----------------------------------------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This file is a part of MemorySanitizer.
13 //===----------------------------------------------------------------------===//
16 #include "msan_chained_origin_depot.h"
17 #include "msan_origin.h"
18 #include "sanitizer_common/sanitizer_allocator_internal.h"
19 #include "sanitizer_common/sanitizer_common.h"
20 #include "sanitizer_common/sanitizer_flags.h"
21 #include "sanitizer_common/sanitizer_mutex.h"
22 #include "sanitizer_common/sanitizer_report_decorator.h"
23 #include "sanitizer_common/sanitizer_stackdepot.h"
24 #include "sanitizer_common/sanitizer_symbolizer.h"
26 using namespace __sanitizer
;
30 class Decorator
: private __sanitizer::AnsiColorDecorator
{
32 Decorator() : __sanitizer::AnsiColorDecorator(PrintsToTtyCached()) { }
33 const char *Warning() { return Red(); }
34 const char *Origin() { return Magenta(); }
35 const char *Name() { return Green(); }
36 const char *End() { return Default(); }
39 static void DescribeStackOrigin(const char *so
, uptr pc
) {
41 char *s
= internal_strdup(so
);
42 char *sep
= internal_strchr(s
, '@');
45 Printf("%s", d
.Origin());
47 " %sUninitialized value was created by an allocation of '%s%s%s'"
48 " in the stack frame of function '%s%s%s'%s\n",
49 d
.Origin(), d
.Name(), s
, d
.Origin(), d
.Name(),
50 Symbolizer::Get()->Demangle(sep
+ 1), d
.Origin(), d
.End());
54 // For some reason function address in LLVM IR is 1 less then the address
55 // of the first instruction.
57 StackTrace::PrintStack(&pc
, 1);
61 static void DescribeOrigin(u32 id
) {
62 VPrintf(1, " raw origin id: %d\n", id
);
67 u32 stack_id
= ChainedOriginDepotGet(o
.id(), &prev_id
);
68 Origin
prev_o(prev_id
);
70 if (prev_o
.isStackRoot()) {
72 const char *so
= GetStackOriginDescr(stack_id
, &pc
);
73 DescribeStackOrigin(so
, pc
);
75 } else if (prev_o
.isHeapRoot()) {
77 const uptr
*trace
= StackDepotGet(stack_id
, &size
);
78 Printf(" %sUninitialized value was created by a heap allocation%s\n",
80 StackTrace::PrintStack(trace
, size
);
85 const uptr
*trace
= StackDepotGet(stack_id
, &size
);
86 // FIXME: copied? modified? passed through? observed?
87 Printf(" %sUninitialized value was stored to memory at%s\n", d
.Origin(),
89 StackTrace::PrintStack(trace
, size
- 1);
95 void ReportUMR(StackTrace
*stack
, u32 origin
) {
96 if (!__msan::flags()->report_umrs
) return;
98 SpinMutexLock
l(&CommonSanitizerReportMutex
);
101 Printf("%s", d
.Warning());
102 Report(" WARNING: MemorySanitizer: use-of-uninitialized-value\n");
103 Printf("%s", d
.End());
106 DescribeOrigin(origin
);
108 ReportErrorSummary("use-of-uninitialized-value", stack
);
111 void ReportExpectedUMRNotFound(StackTrace
*stack
) {
112 SpinMutexLock
l(&CommonSanitizerReportMutex
);
114 Printf(" WARNING: Expected use of uninitialized value not found\n");
119 SpinMutexLock
l(&CommonSanitizerReportMutex
);
121 if (__msan_get_track_origins() > 0) {
122 StackDepotStats
*stack_depot_stats
= StackDepotGetStats();
123 // FIXME: we want this at normal exit, too!
124 // FIXME: but only with verbosity=1 or something
125 Printf("Unique heap origins: %zu\n", stack_depot_stats
->n_uniq_ids
);
126 Printf("Stack depot allocated bytes: %zu\n", stack_depot_stats
->allocated
);
128 StackDepotStats
*chained_origin_depot_stats
= ChainedOriginDepotGetStats();
129 Printf("Unique origin histories: %zu\n",
130 chained_origin_depot_stats
->n_uniq_ids
);
131 Printf("History depot allocated bytes: %zu\n",
132 chained_origin_depot_stats
->allocated
);
136 void ReportAtExitStatistics() {
137 SpinMutexLock
l(&CommonSanitizerReportMutex
);
139 if (msan_report_count
> 0) {
141 Printf("%s", d
.Warning());
142 Printf("MemorySanitizer: %d warnings reported.\n", msan_report_count
);
143 Printf("%s", d
.End());
149 OriginSet() : next_id_(0) {}
151 // Scan from the end for better locality.
152 for (int i
= next_id_
- 1; i
>= 0; --i
)
153 if (origins_
[i
] == o
) return i
;
154 if (next_id_
== kMaxSize_
) return OVERFLOW
;
159 int size() { return next_id_
; }
160 u32
get(int id
) { return origins_
[id
]; }
161 static char asChar(int id
) {
171 static const int OVERFLOW
= -1;
172 static const int MISSING
= -2;
175 static const int kMaxSize_
= 'Z' - 'A' + 1;
176 u32 origins_
[kMaxSize_
];
180 void DescribeMemoryRange(const void *x
, uptr size
) {
182 uptr start
= MEM_TO_SHADOW(x
);
183 uptr end
= start
+ size
;
184 // Scan limits: align start down to 4; align size up to 16.
185 uptr s
= start
& ~3UL;
187 size
= (size
+ 15) & ~15UL;
190 // Single letter names to origin id mapping.
191 OriginSet origin_set
;
193 uptr pos
= 0; // Offset from aligned start.
194 bool with_origins
= __msan_get_track_origins();
195 // True if there is at least 1 poisoned bit in the last 4-byte group.
196 bool last_quad_poisoned
;
197 int origin_ids
[4]; // Single letter origin ids for the current line.
200 Printf("%s", d
.Warning());
201 Printf("Shadow map of [%p, %p), %zu bytes:\n", start
, end
, end
- start
);
202 Printf("%s", d
.End());
206 for (int i
= 0; i
< 4; ++i
) origin_ids
[i
] = -1;
212 last_quad_poisoned
= false;
214 // Print shadow byte.
215 if (s
< start
|| s
>= end
) {
218 unsigned char v
= *(unsigned char *)s
;
219 if (v
) last_quad_poisoned
= true;
223 if (pos
% 4 == 3 && with_origins
) {
224 int id
= OriginSet::MISSING
;
225 if (last_quad_poisoned
) {
226 u32 o
= *(u32
*)SHADOW_TO_ORIGIN(s
- 3);
227 id
= origin_set
.insert(o
);
229 origin_ids
[(pos
% 16) / 4] = id
;
232 if (pos
% 16 == 15) {
235 for (int i
= 0; i
< 4; ++i
) {
236 char c
= OriginSet::asChar(origin_ids
[i
]);
238 if (i
!= 3) Printf(" ");
251 for (int i
= 0; i
< origin_set
.size(); ++i
) {
252 u32 o
= origin_set
.get(i
);
253 Printf("Origin %c (origin_id %x):\n", OriginSet::asChar(i
), o
);
258 void ReportUMRInsideAddressRange(const char *what
, const void *start
, uptr size
,
261 Printf("%s", d
.Warning());
262 Printf("%sUninitialized bytes in %s%s%s at offset %zu inside [%p, %zu)%s\n",
263 d
.Warning(), d
.Name(), what
, d
.Warning(), offset
, start
, size
,
265 if (__sanitizer::common_flags()->verbosity
> 0)
266 DescribeMemoryRange(start
, size
);
269 } // namespace __msan