168d75effSDimitry Andric //===-- msan_report.cpp ---------------------------------------------------===//
268d75effSDimitry Andric //
368d75effSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
468d75effSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
568d75effSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
668d75effSDimitry Andric //
768d75effSDimitry Andric //===----------------------------------------------------------------------===//
868d75effSDimitry Andric //
968d75effSDimitry Andric // This file is a part of MemorySanitizer.
1068d75effSDimitry Andric //
1168d75effSDimitry Andric // Error reporting.
1268d75effSDimitry Andric //===----------------------------------------------------------------------===//
1368d75effSDimitry Andric
1406c3fb27SDimitry Andric #include "msan_report.h"
1506c3fb27SDimitry Andric
1668d75effSDimitry Andric #include "msan.h"
1768d75effSDimitry Andric #include "msan_chained_origin_depot.h"
1868d75effSDimitry Andric #include "msan_origin.h"
1968d75effSDimitry Andric #include "sanitizer_common/sanitizer_allocator_internal.h"
2068d75effSDimitry Andric #include "sanitizer_common/sanitizer_common.h"
2168d75effSDimitry Andric #include "sanitizer_common/sanitizer_flags.h"
2268d75effSDimitry Andric #include "sanitizer_common/sanitizer_mutex.h"
2368d75effSDimitry Andric #include "sanitizer_common/sanitizer_report_decorator.h"
2468d75effSDimitry Andric #include "sanitizer_common/sanitizer_stackdepot.h"
2506c3fb27SDimitry Andric #include "sanitizer_common/sanitizer_stacktrace_printer.h"
2668d75effSDimitry Andric #include "sanitizer_common/sanitizer_symbolizer.h"
2768d75effSDimitry Andric
2868d75effSDimitry Andric using namespace __sanitizer;
2968d75effSDimitry Andric
3068d75effSDimitry Andric namespace __msan {
3168d75effSDimitry Andric
3268d75effSDimitry Andric class Decorator: public __sanitizer::SanitizerCommonDecorator {
3368d75effSDimitry Andric public:
Decorator()3468d75effSDimitry Andric Decorator() : SanitizerCommonDecorator() { }
Origin() const3568d75effSDimitry Andric const char *Origin() const { return Magenta(); }
Name() const3668d75effSDimitry Andric const char *Name() const { return Green(); }
3768d75effSDimitry Andric };
3868d75effSDimitry Andric
DescribeStackOrigin(const char * so,uptr pc)3968d75effSDimitry Andric static void DescribeStackOrigin(const char *so, uptr pc) {
4068d75effSDimitry Andric Decorator d;
4168d75effSDimitry Andric Printf("%s", d.Origin());
42bdd1243dSDimitry Andric if (so) {
4368d75effSDimitry Andric Printf(
4468d75effSDimitry Andric " %sUninitialized value was created by an allocation of '%s%s%s'"
45bdd1243dSDimitry Andric " in the stack frame%s\n",
46bdd1243dSDimitry Andric d.Origin(), d.Name(), so, d.Origin(), d.Default());
47bdd1243dSDimitry Andric } else {
48bdd1243dSDimitry Andric Printf(" %sUninitialized value was created in the stack frame%s\n",
49bdd1243dSDimitry Andric d.Origin(), d.Default());
5068d75effSDimitry Andric }
51bdd1243dSDimitry Andric
52bdd1243dSDimitry Andric if (pc)
53bdd1243dSDimitry Andric StackTrace(&pc, 1).Print();
5468d75effSDimitry Andric }
5568d75effSDimitry Andric
DescribeOrigin(u32 id)5668d75effSDimitry Andric static void DescribeOrigin(u32 id) {
5768d75effSDimitry Andric VPrintf(1, " raw origin id: %d\n", id);
5868d75effSDimitry Andric Decorator d;
5968d75effSDimitry Andric Origin o = Origin::FromRawId(id);
6068d75effSDimitry Andric while (o.isChainedOrigin()) {
6168d75effSDimitry Andric StackTrace stack;
6268d75effSDimitry Andric o = o.getNextChainedOrigin(&stack);
6368d75effSDimitry Andric Printf(" %sUninitialized value was stored to memory at%s\n", d.Origin(),
6468d75effSDimitry Andric d.Default());
6568d75effSDimitry Andric stack.Print();
6668d75effSDimitry Andric }
6768d75effSDimitry Andric if (o.isStackOrigin()) {
6868d75effSDimitry Andric uptr pc;
6968d75effSDimitry Andric const char *so = GetStackOriginDescr(o.getStackId(), &pc);
7068d75effSDimitry Andric DescribeStackOrigin(so, pc);
7168d75effSDimitry Andric } else {
7268d75effSDimitry Andric StackTrace stack = o.getStackTraceForHeapOrigin();
7368d75effSDimitry Andric switch (stack.tag) {
7468d75effSDimitry Andric case StackTrace::TAG_ALLOC:
7568d75effSDimitry Andric Printf(" %sUninitialized value was created by a heap allocation%s\n",
7668d75effSDimitry Andric d.Origin(), d.Default());
7768d75effSDimitry Andric break;
7868d75effSDimitry Andric case StackTrace::TAG_DEALLOC:
7968d75effSDimitry Andric Printf(" %sUninitialized value was created by a heap deallocation%s\n",
8068d75effSDimitry Andric d.Origin(), d.Default());
8168d75effSDimitry Andric break;
8268d75effSDimitry Andric case STACK_TRACE_TAG_POISON:
8368d75effSDimitry Andric Printf(" %sMemory was marked as uninitialized%s\n", d.Origin(),
8468d75effSDimitry Andric d.Default());
8568d75effSDimitry Andric break;
86bdd1243dSDimitry Andric case STACK_TRACE_TAG_FIELDS:
87bdd1243dSDimitry Andric Printf(" %sMember fields were destroyed%s\n", d.Origin(), d.Default());
88bdd1243dSDimitry Andric break;
89bdd1243dSDimitry Andric case STACK_TRACE_TAG_VPTR:
90bdd1243dSDimitry Andric Printf(" %sVirtual table ptr was destroyed%s\n", d.Origin(),
91bdd1243dSDimitry Andric d.Default());
92bdd1243dSDimitry Andric break;
9368d75effSDimitry Andric default:
9468d75effSDimitry Andric Printf(" %sUninitialized value was created%s\n", d.Origin(),
9568d75effSDimitry Andric d.Default());
9668d75effSDimitry Andric break;
9768d75effSDimitry Andric }
9868d75effSDimitry Andric stack.Print();
9968d75effSDimitry Andric }
10068d75effSDimitry Andric }
10168d75effSDimitry Andric
ReportUMR(StackTrace * stack,u32 origin)10268d75effSDimitry Andric void ReportUMR(StackTrace *stack, u32 origin) {
10368d75effSDimitry Andric if (!__msan::flags()->report_umrs) return;
10468d75effSDimitry Andric
10568d75effSDimitry Andric ScopedErrorReportLock l;
10668d75effSDimitry Andric
10768d75effSDimitry Andric Decorator d;
10868d75effSDimitry Andric Printf("%s", d.Warning());
10968d75effSDimitry Andric Report("WARNING: MemorySanitizer: use-of-uninitialized-value\n");
11068d75effSDimitry Andric Printf("%s", d.Default());
11168d75effSDimitry Andric stack->Print();
11268d75effSDimitry Andric if (origin) {
11368d75effSDimitry Andric DescribeOrigin(origin);
11468d75effSDimitry Andric }
11568d75effSDimitry Andric ReportErrorSummary("use-of-uninitialized-value", stack);
11668d75effSDimitry Andric }
11768d75effSDimitry Andric
ReportExpectedUMRNotFound(StackTrace * stack)11868d75effSDimitry Andric void ReportExpectedUMRNotFound(StackTrace *stack) {
11968d75effSDimitry Andric ScopedErrorReportLock l;
12068d75effSDimitry Andric
12168d75effSDimitry Andric Printf("WARNING: Expected use of uninitialized value not found\n");
12268d75effSDimitry Andric stack->Print();
12368d75effSDimitry Andric }
12468d75effSDimitry Andric
ReportStats()12568d75effSDimitry Andric void ReportStats() {
12668d75effSDimitry Andric ScopedErrorReportLock l;
12768d75effSDimitry Andric
12868d75effSDimitry Andric if (__msan_get_track_origins() > 0) {
129349cc55cSDimitry Andric StackDepotStats stack_depot_stats = StackDepotGetStats();
13068d75effSDimitry Andric // FIXME: we want this at normal exit, too!
13168d75effSDimitry Andric // FIXME: but only with verbosity=1 or something
132349cc55cSDimitry Andric Printf("Unique heap origins: %zu\n", stack_depot_stats.n_uniq_ids);
133349cc55cSDimitry Andric Printf("Stack depot allocated bytes: %zu\n", stack_depot_stats.allocated);
13468d75effSDimitry Andric
135349cc55cSDimitry Andric StackDepotStats chained_origin_depot_stats = ChainedOriginDepotGetStats();
13668d75effSDimitry Andric Printf("Unique origin histories: %zu\n",
137349cc55cSDimitry Andric chained_origin_depot_stats.n_uniq_ids);
13868d75effSDimitry Andric Printf("History depot allocated bytes: %zu\n",
139349cc55cSDimitry Andric chained_origin_depot_stats.allocated);
14068d75effSDimitry Andric }
14168d75effSDimitry Andric }
14268d75effSDimitry Andric
ReportAtExitStatistics()14368d75effSDimitry Andric void ReportAtExitStatistics() {
14468d75effSDimitry Andric ScopedErrorReportLock l;
14568d75effSDimitry Andric
14668d75effSDimitry Andric if (msan_report_count > 0) {
14768d75effSDimitry Andric Decorator d;
14868d75effSDimitry Andric Printf("%s", d.Warning());
14968d75effSDimitry Andric Printf("MemorySanitizer: %d warnings reported.\n", msan_report_count);
15068d75effSDimitry Andric Printf("%s", d.Default());
15168d75effSDimitry Andric }
15268d75effSDimitry Andric }
15368d75effSDimitry Andric
15468d75effSDimitry Andric class OriginSet {
15568d75effSDimitry Andric public:
OriginSet()15668d75effSDimitry Andric OriginSet() : next_id_(0) {}
insert(u32 o)15768d75effSDimitry Andric int insert(u32 o) {
15868d75effSDimitry Andric // Scan from the end for better locality.
15968d75effSDimitry Andric for (int i = next_id_ - 1; i >= 0; --i)
16068d75effSDimitry Andric if (origins_[i] == o) return i;
16168d75effSDimitry Andric if (next_id_ == kMaxSize_) return OVERFLOW;
16268d75effSDimitry Andric int id = next_id_++;
16368d75effSDimitry Andric origins_[id] = o;
16468d75effSDimitry Andric return id;
16568d75effSDimitry Andric }
size()16668d75effSDimitry Andric int size() { return next_id_; }
get(int id)16768d75effSDimitry Andric u32 get(int id) { return origins_[id]; }
asChar(int id)16868d75effSDimitry Andric static char asChar(int id) {
16968d75effSDimitry Andric switch (id) {
17068d75effSDimitry Andric case MISSING:
17168d75effSDimitry Andric return '.';
17268d75effSDimitry Andric case OVERFLOW:
17368d75effSDimitry Andric return '*';
17468d75effSDimitry Andric default:
17568d75effSDimitry Andric return 'A' + id;
17668d75effSDimitry Andric }
17768d75effSDimitry Andric }
17868d75effSDimitry Andric static const int OVERFLOW = -1;
17968d75effSDimitry Andric static const int MISSING = -2;
18068d75effSDimitry Andric
18168d75effSDimitry Andric private:
18268d75effSDimitry Andric static const int kMaxSize_ = 'Z' - 'A' + 1;
18368d75effSDimitry Andric u32 origins_[kMaxSize_];
18468d75effSDimitry Andric int next_id_;
18568d75effSDimitry Andric };
18668d75effSDimitry Andric
DescribeMemoryRange(const void * x,uptr size)18768d75effSDimitry Andric void DescribeMemoryRange(const void *x, uptr size) {
18868d75effSDimitry Andric // Real limits.
18968d75effSDimitry Andric uptr start = MEM_TO_SHADOW(x);
19068d75effSDimitry Andric uptr end = start + size;
19168d75effSDimitry Andric // Scan limits: align start down to 4; align size up to 16.
19268d75effSDimitry Andric uptr s = start & ~3UL;
19368d75effSDimitry Andric size = end - s;
19468d75effSDimitry Andric size = (size + 15) & ~15UL;
19568d75effSDimitry Andric uptr e = s + size;
19668d75effSDimitry Andric
19768d75effSDimitry Andric // Single letter names to origin id mapping.
19868d75effSDimitry Andric OriginSet origin_set;
19968d75effSDimitry Andric
20068d75effSDimitry Andric uptr pos = 0; // Offset from aligned start.
20168d75effSDimitry Andric bool with_origins = __msan_get_track_origins();
20268d75effSDimitry Andric // True if there is at least 1 poisoned bit in the last 4-byte group.
20368d75effSDimitry Andric bool last_quad_poisoned;
20468d75effSDimitry Andric int origin_ids[4]; // Single letter origin ids for the current line.
20568d75effSDimitry Andric
20668d75effSDimitry Andric Decorator d;
20768d75effSDimitry Andric Printf("%s", d.Warning());
208349cc55cSDimitry Andric uptr start_x = reinterpret_cast<uptr>(x);
209349cc55cSDimitry Andric Printf("Shadow map [%p, %p) of [%p, %p), %zu bytes:\n",
210349cc55cSDimitry Andric reinterpret_cast<void *>(start), reinterpret_cast<void *>(end),
211349cc55cSDimitry Andric reinterpret_cast<void *>(start_x),
212349cc55cSDimitry Andric reinterpret_cast<void *>(start_x + end - start), end - start);
21368d75effSDimitry Andric Printf("%s", d.Default());
21468d75effSDimitry Andric while (s < e) {
21568d75effSDimitry Andric // Line start.
21668d75effSDimitry Andric if (pos % 16 == 0) {
21768d75effSDimitry Andric for (int i = 0; i < 4; ++i) origin_ids[i] = -1;
218349cc55cSDimitry Andric Printf("%p[%p]:", reinterpret_cast<void *>(s),
219349cc55cSDimitry Andric reinterpret_cast<void *>(start_x - start + s));
22068d75effSDimitry Andric }
22168d75effSDimitry Andric // Group start.
22268d75effSDimitry Andric if (pos % 4 == 0) {
22368d75effSDimitry Andric Printf(" ");
22468d75effSDimitry Andric last_quad_poisoned = false;
22568d75effSDimitry Andric }
22668d75effSDimitry Andric // Print shadow byte.
22768d75effSDimitry Andric if (s < start || s >= end) {
22868d75effSDimitry Andric Printf("..");
22968d75effSDimitry Andric } else {
23068d75effSDimitry Andric unsigned char v = *(unsigned char *)s;
23168d75effSDimitry Andric if (v) last_quad_poisoned = true;
23268d75effSDimitry Andric Printf("%x%x", v >> 4, v & 0xf);
23368d75effSDimitry Andric }
23468d75effSDimitry Andric // Group end.
23568d75effSDimitry Andric if (pos % 4 == 3 && with_origins) {
23668d75effSDimitry Andric int id = OriginSet::MISSING;
23768d75effSDimitry Andric if (last_quad_poisoned) {
23868d75effSDimitry Andric u32 o = *(u32 *)SHADOW_TO_ORIGIN(s - 3);
23968d75effSDimitry Andric id = origin_set.insert(o);
24068d75effSDimitry Andric }
24168d75effSDimitry Andric origin_ids[(pos % 16) / 4] = id;
24268d75effSDimitry Andric }
24368d75effSDimitry Andric // Line end.
24468d75effSDimitry Andric if (pos % 16 == 15) {
24568d75effSDimitry Andric if (with_origins) {
24668d75effSDimitry Andric Printf(" |");
24768d75effSDimitry Andric for (int i = 0; i < 4; ++i) {
24868d75effSDimitry Andric char c = OriginSet::asChar(origin_ids[i]);
24968d75effSDimitry Andric Printf("%c", c);
25068d75effSDimitry Andric if (i != 3) Printf(" ");
25168d75effSDimitry Andric }
25268d75effSDimitry Andric Printf("|");
25368d75effSDimitry Andric }
25468d75effSDimitry Andric Printf("\n");
25568d75effSDimitry Andric }
25668d75effSDimitry Andric size--;
25768d75effSDimitry Andric s++;
25868d75effSDimitry Andric pos++;
25968d75effSDimitry Andric }
26068d75effSDimitry Andric
26168d75effSDimitry Andric Printf("\n");
26268d75effSDimitry Andric
26368d75effSDimitry Andric for (int i = 0; i < origin_set.size(); ++i) {
26468d75effSDimitry Andric u32 o = origin_set.get(i);
26568d75effSDimitry Andric Printf("Origin %c (origin_id %x):\n", OriginSet::asChar(i), o);
26668d75effSDimitry Andric DescribeOrigin(o);
26768d75effSDimitry Andric }
26868d75effSDimitry Andric }
26968d75effSDimitry Andric
ReportUMRInsideAddressRange(const char * function,const void * start,uptr size,uptr offset)27006c3fb27SDimitry Andric void ReportUMRInsideAddressRange(const char *function, const void *start,
27106c3fb27SDimitry Andric uptr size, uptr offset) {
272*5f757f3fSDimitry Andric function = StackTracePrinter::GetOrInit()->StripFunctionName(function);
27368d75effSDimitry Andric Decorator d;
27468d75effSDimitry Andric Printf("%s", d.Warning());
27568d75effSDimitry Andric Printf("%sUninitialized bytes in %s%s%s at offset %zu inside [%p, %zu)%s\n",
27606c3fb27SDimitry Andric d.Warning(), d.Name(), function, d.Warning(), offset, start, size,
27768d75effSDimitry Andric d.Default());
27868d75effSDimitry Andric if (__sanitizer::Verbosity())
27968d75effSDimitry Andric DescribeMemoryRange(start, size);
28068d75effSDimitry Andric }
28168d75effSDimitry Andric
28268d75effSDimitry Andric } // namespace __msan
283