1 //===-- msan_report.cpp ---------------------------------------------------===//
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7 //===----------------------------------------------------------------------===//
9 // This file is a part of MemorySanitizer.
12 //===----------------------------------------------------------------------===//
15 #include "msan_chained_origin_depot.h"
16 #include "msan_origin.h"
17 #include "msan_report.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 *Origin() const { return Magenta(); }
34 const char *Name() const { return Green(); }
37 static void DescribeStackOrigin(const char *so
, uptr pc
) {
39 char *s
= internal_strdup(so
);
40 char *sep
= internal_strchr(s
, '@');
43 Printf("%s", d
.Origin());
45 " %sUninitialized value was created by an allocation of '%s%s%s'"
46 " in the stack frame of function '%s%s%s'%s\n",
47 d
.Origin(), d
.Name(), s
, d
.Origin(), d
.Name(), sep
+ 1, d
.Origin(),
52 // For some reason function address in LLVM IR is 1 less then the address
53 // of the first instruction.
54 pc
= StackTrace::GetNextInstructionPc(pc
);
55 StackTrace(&pc
, 1).Print();
59 static void DescribeOrigin(u32 id
) {
60 VPrintf(1, " raw origin id: %d\n", id
);
62 Origin o
= Origin::FromRawId(id
);
63 while (o
.isChainedOrigin()) {
65 o
= o
.getNextChainedOrigin(&stack
);
66 Printf(" %sUninitialized value was stored to memory at%s\n", d
.Origin(),
70 if (o
.isStackOrigin()) {
72 const char *so
= GetStackOriginDescr(o
.getStackId(), &pc
);
73 DescribeStackOrigin(so
, pc
);
75 StackTrace stack
= o
.getStackTraceForHeapOrigin();
77 case StackTrace::TAG_ALLOC
:
78 Printf(" %sUninitialized value was created by a heap allocation%s\n",
79 d
.Origin(), d
.Default());
81 case StackTrace::TAG_DEALLOC
:
82 Printf(" %sUninitialized value was created by a heap deallocation%s\n",
83 d
.Origin(), d
.Default());
85 case STACK_TRACE_TAG_POISON
:
86 Printf(" %sMemory was marked as uninitialized%s\n", d
.Origin(),
90 Printf(" %sUninitialized value was created%s\n", d
.Origin(),
98 void ReportUMR(StackTrace
*stack
, u32 origin
) {
99 if (!__msan::flags()->report_umrs
) return;
101 ScopedErrorReportLock l
;
104 Printf("%s", d
.Warning());
105 Report("WARNING: MemorySanitizer: use-of-uninitialized-value\n");
106 Printf("%s", d
.Default());
109 DescribeOrigin(origin
);
111 ReportErrorSummary("use-of-uninitialized-value", stack
);
114 void ReportExpectedUMRNotFound(StackTrace
*stack
) {
115 ScopedErrorReportLock l
;
117 Printf("WARNING: Expected use of uninitialized value not found\n");
122 ScopedErrorReportLock l
;
124 if (__msan_get_track_origins() > 0) {
125 StackDepotStats
*stack_depot_stats
= StackDepotGetStats();
126 // FIXME: we want this at normal exit, too!
127 // FIXME: but only with verbosity=1 or something
128 Printf("Unique heap origins: %zu\n", stack_depot_stats
->n_uniq_ids
);
129 Printf("Stack depot allocated bytes: %zu\n", stack_depot_stats
->allocated
);
131 StackDepotStats
*chained_origin_depot_stats
= ChainedOriginDepotGetStats();
132 Printf("Unique origin histories: %zu\n",
133 chained_origin_depot_stats
->n_uniq_ids
);
134 Printf("History depot allocated bytes: %zu\n",
135 chained_origin_depot_stats
->allocated
);
139 void ReportAtExitStatistics() {
140 ScopedErrorReportLock l
;
142 if (msan_report_count
> 0) {
144 Printf("%s", d
.Warning());
145 Printf("MemorySanitizer: %d warnings reported.\n", msan_report_count
);
146 Printf("%s", d
.Default());
152 OriginSet() : next_id_(0) {}
154 // Scan from the end for better locality.
155 for (int i
= next_id_
- 1; i
>= 0; --i
)
156 if (origins_
[i
] == o
) return i
;
157 if (next_id_
== kMaxSize_
) return OVERFLOW
;
162 int size() { return next_id_
; }
163 u32
get(int id
) { return origins_
[id
]; }
164 static char asChar(int id
) {
174 static const int OVERFLOW
= -1;
175 static const int MISSING
= -2;
178 static const int kMaxSize_
= 'Z' - 'A' + 1;
179 u32 origins_
[kMaxSize_
];
183 void DescribeMemoryRange(const void *x
, uptr size
) {
185 uptr start
= MEM_TO_SHADOW(x
);
186 uptr end
= start
+ size
;
187 // Scan limits: align start down to 4; align size up to 16.
188 uptr s
= start
& ~3UL;
190 size
= (size
+ 15) & ~15UL;
193 // Single letter names to origin id mapping.
194 OriginSet origin_set
;
196 uptr pos
= 0; // Offset from aligned start.
197 bool with_origins
= __msan_get_track_origins();
198 // True if there is at least 1 poisoned bit in the last 4-byte group.
199 bool last_quad_poisoned
;
200 int origin_ids
[4]; // Single letter origin ids for the current line.
203 Printf("%s", d
.Warning());
204 Printf("Shadow map of [%p, %p), %zu bytes:\n", start
, end
, end
- start
);
205 Printf("%s", d
.Default());
209 for (int i
= 0; i
< 4; ++i
) origin_ids
[i
] = -1;
215 last_quad_poisoned
= false;
217 // Print shadow byte.
218 if (s
< start
|| s
>= end
) {
221 unsigned char v
= *(unsigned char *)s
;
222 if (v
) last_quad_poisoned
= true;
223 Printf("%x%x", v
>> 4, v
& 0xf);
226 if (pos
% 4 == 3 && with_origins
) {
227 int id
= OriginSet::MISSING
;
228 if (last_quad_poisoned
) {
229 u32 o
= *(u32
*)SHADOW_TO_ORIGIN(s
- 3);
230 id
= origin_set
.insert(o
);
232 origin_ids
[(pos
% 16) / 4] = id
;
235 if (pos
% 16 == 15) {
238 for (int i
= 0; i
< 4; ++i
) {
239 char c
= OriginSet::asChar(origin_ids
[i
]);
241 if (i
!= 3) Printf(" ");
254 for (int i
= 0; i
< origin_set
.size(); ++i
) {
255 u32 o
= origin_set
.get(i
);
256 Printf("Origin %c (origin_id %x):\n", OriginSet::asChar(i
), o
);
261 void ReportUMRInsideAddressRange(const char *what
, const void *start
, uptr size
,
264 Printf("%s", d
.Warning());
265 Printf("%sUninitialized bytes in %s%s%s at offset %zu inside [%p, %zu)%s\n",
266 d
.Warning(), d
.Name(), what
, d
.Warning(), offset
, start
, size
,
268 if (__sanitizer::Verbosity())
269 DescribeMemoryRange(start
, size
);
272 } // namespace __msan