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 Printf("%s", d
.Origin());
42 " %sUninitialized value was created by an allocation of '%s%s%s'"
43 " in the stack frame%s\n",
44 d
.Origin(), d
.Name(), so
, d
.Origin(), d
.Default());
46 Printf(" %sUninitialized value was created in the stack frame%s\n",
47 d
.Origin(), d
.Default());
51 StackTrace(&pc
, 1).Print();
54 static void DescribeOrigin(u32 id
) {
55 VPrintf(1, " raw origin id: %d\n", id
);
57 Origin o
= Origin::FromRawId(id
);
58 while (o
.isChainedOrigin()) {
60 o
= o
.getNextChainedOrigin(&stack
);
61 Printf(" %sUninitialized value was stored to memory at%s\n", d
.Origin(),
65 if (o
.isStackOrigin()) {
67 const char *so
= GetStackOriginDescr(o
.getStackId(), &pc
);
68 DescribeStackOrigin(so
, pc
);
70 StackTrace stack
= o
.getStackTraceForHeapOrigin();
72 case StackTrace::TAG_ALLOC
:
73 Printf(" %sUninitialized value was created by a heap allocation%s\n",
74 d
.Origin(), d
.Default());
76 case StackTrace::TAG_DEALLOC
:
77 Printf(" %sUninitialized value was created by a heap deallocation%s\n",
78 d
.Origin(), d
.Default());
80 case STACK_TRACE_TAG_POISON
:
81 Printf(" %sMemory was marked as uninitialized%s\n", d
.Origin(),
84 case STACK_TRACE_TAG_FIELDS
:
85 Printf(" %sMember fields were destroyed%s\n", d
.Origin(), d
.Default());
87 case STACK_TRACE_TAG_VPTR
:
88 Printf(" %sVirtual table ptr was destroyed%s\n", d
.Origin(),
92 Printf(" %sUninitialized value was created%s\n", d
.Origin(),
100 void ReportUMR(StackTrace
*stack
, u32 origin
) {
101 if (!__msan::flags()->report_umrs
) return;
103 ScopedErrorReportLock l
;
106 Printf("%s", d
.Warning());
107 Report("WARNING: MemorySanitizer: use-of-uninitialized-value\n");
108 Printf("%s", d
.Default());
111 DescribeOrigin(origin
);
113 ReportErrorSummary("use-of-uninitialized-value", stack
);
116 void ReportExpectedUMRNotFound(StackTrace
*stack
) {
117 ScopedErrorReportLock l
;
119 Printf("WARNING: Expected use of uninitialized value not found\n");
124 ScopedErrorReportLock l
;
126 if (__msan_get_track_origins() > 0) {
127 StackDepotStats stack_depot_stats
= StackDepotGetStats();
128 // FIXME: we want this at normal exit, too!
129 // FIXME: but only with verbosity=1 or something
130 Printf("Unique heap origins: %zu\n", stack_depot_stats
.n_uniq_ids
);
131 Printf("Stack depot allocated bytes: %zu\n", stack_depot_stats
.allocated
);
133 StackDepotStats chained_origin_depot_stats
= ChainedOriginDepotGetStats();
134 Printf("Unique origin histories: %zu\n",
135 chained_origin_depot_stats
.n_uniq_ids
);
136 Printf("History depot allocated bytes: %zu\n",
137 chained_origin_depot_stats
.allocated
);
141 void ReportAtExitStatistics() {
142 ScopedErrorReportLock l
;
144 if (msan_report_count
> 0) {
146 Printf("%s", d
.Warning());
147 Printf("MemorySanitizer: %d warnings reported.\n", msan_report_count
);
148 Printf("%s", d
.Default());
154 OriginSet() : next_id_(0) {}
156 // Scan from the end for better locality.
157 for (int i
= next_id_
- 1; i
>= 0; --i
)
158 if (origins_
[i
] == o
) return i
;
159 if (next_id_
== kMaxSize_
) return OVERFLOW
;
164 int size() { return next_id_
; }
165 u32
get(int id
) { return origins_
[id
]; }
166 static char asChar(int id
) {
176 static const int OVERFLOW
= -1;
177 static const int MISSING
= -2;
180 static const int kMaxSize_
= 'Z' - 'A' + 1;
181 u32 origins_
[kMaxSize_
];
185 void DescribeMemoryRange(const void *x
, uptr size
) {
187 uptr start
= MEM_TO_SHADOW(x
);
188 uptr end
= start
+ size
;
189 // Scan limits: align start down to 4; align size up to 16.
190 uptr s
= start
& ~3UL;
192 size
= (size
+ 15) & ~15UL;
195 // Single letter names to origin id mapping.
196 OriginSet origin_set
;
198 uptr pos
= 0; // Offset from aligned start.
199 bool with_origins
= __msan_get_track_origins();
200 // True if there is at least 1 poisoned bit in the last 4-byte group.
201 bool last_quad_poisoned
;
202 int origin_ids
[4]; // Single letter origin ids for the current line.
205 Printf("%s", d
.Warning());
206 uptr start_x
= reinterpret_cast<uptr
>(x
);
207 Printf("Shadow map [%p, %p) of [%p, %p), %zu bytes:\n",
208 reinterpret_cast<void *>(start
), reinterpret_cast<void *>(end
),
209 reinterpret_cast<void *>(start_x
),
210 reinterpret_cast<void *>(start_x
+ end
- start
), end
- start
);
211 Printf("%s", d
.Default());
215 for (int i
= 0; i
< 4; ++i
) origin_ids
[i
] = -1;
216 Printf("%p[%p]:", reinterpret_cast<void *>(s
),
217 reinterpret_cast<void *>(start_x
- start
+ s
));
222 last_quad_poisoned
= false;
224 // Print shadow byte.
225 if (s
< start
|| s
>= end
) {
228 unsigned char v
= *(unsigned char *)s
;
229 if (v
) last_quad_poisoned
= true;
230 Printf("%x%x", v
>> 4, v
& 0xf);
233 if (pos
% 4 == 3 && with_origins
) {
234 int id
= OriginSet::MISSING
;
235 if (last_quad_poisoned
) {
236 u32 o
= *(u32
*)SHADOW_TO_ORIGIN(s
- 3);
237 id
= origin_set
.insert(o
);
239 origin_ids
[(pos
% 16) / 4] = id
;
242 if (pos
% 16 == 15) {
245 for (int i
= 0; i
< 4; ++i
) {
246 char c
= OriginSet::asChar(origin_ids
[i
]);
248 if (i
!= 3) Printf(" ");
261 for (int i
= 0; i
< origin_set
.size(); ++i
) {
262 u32 o
= origin_set
.get(i
);
263 Printf("Origin %c (origin_id %x):\n", OriginSet::asChar(i
), o
);
268 void ReportUMRInsideAddressRange(const char *what
, const void *start
, uptr size
,
271 Printf("%s", d
.Warning());
272 Printf("%sUninitialized bytes in %s%s%s at offset %zu inside [%p, %zu)%s\n",
273 d
.Warning(), d
.Name(), what
, d
.Warning(), offset
, start
, size
,
275 if (__sanitizer::Verbosity())
276 DescribeMemoryRange(start
, size
);
279 } // namespace __msan