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: 3468d75effSDimitry Andric Decorator() : SanitizerCommonDecorator() { } 3568d75effSDimitry Andric const char *Origin() const { return Magenta(); } 3668d75effSDimitry Andric const char *Name() const { return Green(); } 3768d75effSDimitry Andric }; 3868d75effSDimitry Andric 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 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 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 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 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 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: 15668d75effSDimitry Andric OriginSet() : next_id_(0) {} 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 } 16668d75effSDimitry Andric int size() { return next_id_; } 16768d75effSDimitry Andric u32 get(int id) { return origins_[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 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 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