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
: public __sanitizer::SanitizerCommonDecorator
{
32 Decorator() : SanitizerCommonDecorator() { }
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(), sep
+ 1, d
.Origin(),
54 // For some reason function address in LLVM IR is 1 less then the address
55 // of the first instruction.
56 pc
= StackTrace::GetNextInstructionPc(pc
);
57 StackTrace(&pc
, 1).Print();
61 static void DescribeOrigin(u32 id
) {
62 VPrintf(1, " raw origin id: %d\n", id
);
64 Origin o
= Origin::FromRawId(id
);
65 while (o
.isChainedOrigin()) {
67 o
= o
.getNextChainedOrigin(&stack
);
68 Printf(" %sUninitialized value was stored to memory at%s\n", d
.Origin(),
72 if (o
.isStackOrigin()) {
74 const char *so
= GetStackOriginDescr(o
.getStackId(), &pc
);
75 DescribeStackOrigin(so
, pc
);
77 StackTrace stack
= o
.getStackTraceForHeapOrigin();
79 case StackTrace::TAG_ALLOC
:
80 Printf(" %sUninitialized value was created by a heap allocation%s\n",
83 case StackTrace::TAG_DEALLOC
:
84 Printf(" %sUninitialized value was created by a heap deallocation%s\n",
87 case STACK_TRACE_TAG_POISON
:
88 Printf(" %sMemory was marked as uninitialized%s\n", d
.Origin(),
92 Printf(" %sUninitialized value was created%s\n", d
.Origin(), d
.End());
99 void ReportUMR(StackTrace
*stack
, u32 origin
) {
100 if (!__msan::flags()->report_umrs
) return;
102 SpinMutexLock
l(&CommonSanitizerReportMutex
);
105 Printf("%s", d
.Warning());
106 Report("WARNING: MemorySanitizer: use-of-uninitialized-value\n");
107 Printf("%s", d
.End());
110 DescribeOrigin(origin
);
112 ReportErrorSummary("use-of-uninitialized-value", stack
);
115 void ReportExpectedUMRNotFound(StackTrace
*stack
) {
116 SpinMutexLock
l(&CommonSanitizerReportMutex
);
118 Printf("WARNING: Expected use of uninitialized value not found\n");
123 SpinMutexLock
l(&CommonSanitizerReportMutex
);
125 if (__msan_get_track_origins() > 0) {
126 StackDepotStats
*stack_depot_stats
= StackDepotGetStats();
127 // FIXME: we want this at normal exit, too!
128 // FIXME: but only with verbosity=1 or something
129 Printf("Unique heap origins: %zu\n", stack_depot_stats
->n_uniq_ids
);
130 Printf("Stack depot allocated bytes: %zu\n", stack_depot_stats
->allocated
);
132 StackDepotStats
*chained_origin_depot_stats
= ChainedOriginDepotGetStats();
133 Printf("Unique origin histories: %zu\n",
134 chained_origin_depot_stats
->n_uniq_ids
);
135 Printf("History depot allocated bytes: %zu\n",
136 chained_origin_depot_stats
->allocated
);
140 void ReportAtExitStatistics() {
141 SpinMutexLock
l(&CommonSanitizerReportMutex
);
143 if (msan_report_count
> 0) {
145 Printf("%s", d
.Warning());
146 Printf("MemorySanitizer: %d warnings reported.\n", msan_report_count
);
147 Printf("%s", d
.End());
153 OriginSet() : next_id_(0) {}
155 // Scan from the end for better locality.
156 for (int i
= next_id_
- 1; i
>= 0; --i
)
157 if (origins_
[i
] == o
) return i
;
158 if (next_id_
== kMaxSize_
) return OVERFLOW
;
163 int size() { return next_id_
; }
164 u32
get(int id
) { return origins_
[id
]; }
165 static char asChar(int id
) {
175 static const int OVERFLOW
= -1;
176 static const int MISSING
= -2;
179 static const int kMaxSize_
= 'Z' - 'A' + 1;
180 u32 origins_
[kMaxSize_
];
184 void DescribeMemoryRange(const void *x
, uptr size
) {
186 uptr start
= MEM_TO_SHADOW(x
);
187 uptr end
= start
+ size
;
188 // Scan limits: align start down to 4; align size up to 16.
189 uptr s
= start
& ~3UL;
191 size
= (size
+ 15) & ~15UL;
194 // Single letter names to origin id mapping.
195 OriginSet origin_set
;
197 uptr pos
= 0; // Offset from aligned start.
198 bool with_origins
= __msan_get_track_origins();
199 // True if there is at least 1 poisoned bit in the last 4-byte group.
200 bool last_quad_poisoned
;
201 int origin_ids
[4]; // Single letter origin ids for the current line.
204 Printf("%s", d
.Warning());
205 Printf("Shadow map of [%p, %p), %zu bytes:\n", start
, end
, end
- start
);
206 Printf("%s", d
.End());
210 for (int i
= 0; i
< 4; ++i
) origin_ids
[i
] = -1;
216 last_quad_poisoned
= false;
218 // Print shadow byte.
219 if (s
< start
|| s
>= end
) {
222 unsigned char v
= *(unsigned char *)s
;
223 if (v
) last_quad_poisoned
= true;
224 Printf("%x%x", v
>> 4, v
& 0xf);
227 if (pos
% 4 == 3 && with_origins
) {
228 int id
= OriginSet::MISSING
;
229 if (last_quad_poisoned
) {
230 u32 o
= *(u32
*)SHADOW_TO_ORIGIN(s
- 3);
231 id
= origin_set
.insert(o
);
233 origin_ids
[(pos
% 16) / 4] = id
;
236 if (pos
% 16 == 15) {
239 for (int i
= 0; i
< 4; ++i
) {
240 char c
= OriginSet::asChar(origin_ids
[i
]);
242 if (i
!= 3) Printf(" ");
255 for (int i
= 0; i
< origin_set
.size(); ++i
) {
256 u32 o
= origin_set
.get(i
);
257 Printf("Origin %c (origin_id %x):\n", OriginSet::asChar(i
), o
);
262 void ReportUMRInsideAddressRange(const char *what
, const void *start
, uptr size
,
265 Printf("%s", d
.Warning());
266 Printf("%sUninitialized bytes in %s%s%s at offset %zu inside [%p, %zu)%s\n",
267 d
.Warning(), d
.Name(), what
, d
.Warning(), offset
, start
, size
,
269 if (__sanitizer::Verbosity())
270 DescribeMemoryRange(start
, size
);
273 } // namespace __msan