Path: blob/main/contrib/llvm-project/compiler-rt/lib/msan/msan_report.cpp
35262 views
//===-- msan_report.cpp ---------------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file is a part of MemorySanitizer.9//10// Error reporting.11//===----------------------------------------------------------------------===//1213#include "msan_report.h"1415#include "msan.h"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_stacktrace_printer.h"25#include "sanitizer_common/sanitizer_symbolizer.h"2627using namespace __sanitizer;2829namespace __msan {3031class Decorator: public __sanitizer::SanitizerCommonDecorator {32public:33Decorator() : SanitizerCommonDecorator() { }34const char *Origin() const { return Magenta(); }35const char *Name() const { return Green(); }36};3738static void DescribeStackOrigin(const char *so, uptr pc) {39Decorator d;40Printf("%s", d.Origin());41if (so) {42Printf(43" %sUninitialized value was created by an allocation of '%s%s%s'"44" in the stack frame%s\n",45d.Origin(), d.Name(), so, d.Origin(), d.Default());46} else {47Printf(" %sUninitialized value was created in the stack frame%s\n",48d.Origin(), d.Default());49}5051if (pc)52StackTrace(&pc, 1).Print();53}5455static void DescribeOrigin(u32 id) {56VPrintf(1, " raw origin id: %d\n", id);57Decorator d;58Origin o = Origin::FromRawId(id);59while (o.isChainedOrigin()) {60StackTrace stack;61o = o.getNextChainedOrigin(&stack);62Printf(" %sUninitialized value was stored to memory at%s\n", d.Origin(),63d.Default());64stack.Print();65}66if (o.isStackOrigin()) {67uptr pc;68const char *so = GetStackOriginDescr(o.getStackId(), &pc);69DescribeStackOrigin(so, pc);70} else {71StackTrace stack = o.getStackTraceForHeapOrigin();72switch (stack.tag) {73case StackTrace::TAG_ALLOC:74Printf(" %sUninitialized value was created by a heap allocation%s\n",75d.Origin(), d.Default());76break;77case StackTrace::TAG_DEALLOC:78Printf(" %sUninitialized value was created by a heap deallocation%s\n",79d.Origin(), d.Default());80break;81case STACK_TRACE_TAG_POISON:82Printf(" %sMemory was marked as uninitialized%s\n", d.Origin(),83d.Default());84break;85case STACK_TRACE_TAG_FIELDS:86Printf(" %sMember fields were destroyed%s\n", d.Origin(), d.Default());87break;88case STACK_TRACE_TAG_VPTR:89Printf(" %sVirtual table ptr was destroyed%s\n", d.Origin(),90d.Default());91break;92default:93Printf(" %sUninitialized value was created%s\n", d.Origin(),94d.Default());95break;96}97stack.Print();98}99}100101void ReportUMR(StackTrace *stack, u32 origin) {102if (!__msan::flags()->report_umrs) return;103104ScopedErrorReportLock l;105106Decorator d;107Printf("%s", d.Warning());108Report("WARNING: MemorySanitizer: use-of-uninitialized-value\n");109Printf("%s", d.Default());110stack->Print();111if (origin) {112DescribeOrigin(origin);113}114ReportErrorSummary("use-of-uninitialized-value", stack);115}116117void ReportExpectedUMRNotFound(StackTrace *stack) {118ScopedErrorReportLock l;119120Printf("WARNING: Expected use of uninitialized value not found\n");121stack->Print();122}123124void ReportStats() {125ScopedErrorReportLock l;126127if (__msan_get_track_origins() > 0) {128StackDepotStats stack_depot_stats = StackDepotGetStats();129// FIXME: we want this at normal exit, too!130// FIXME: but only with verbosity=1 or something131Printf("Unique heap origins: %zu\n", stack_depot_stats.n_uniq_ids);132Printf("Stack depot allocated bytes: %zu\n", stack_depot_stats.allocated);133134StackDepotStats chained_origin_depot_stats = ChainedOriginDepotGetStats();135Printf("Unique origin histories: %zu\n",136chained_origin_depot_stats.n_uniq_ids);137Printf("History depot allocated bytes: %zu\n",138chained_origin_depot_stats.allocated);139}140}141142void ReportAtExitStatistics() {143ScopedErrorReportLock l;144145if (msan_report_count > 0) {146Decorator d;147Printf("%s", d.Warning());148Printf("MemorySanitizer: %d warnings reported.\n", msan_report_count);149Printf("%s", d.Default());150}151}152153class OriginSet {154public:155OriginSet() : next_id_(0) {}156int insert(u32 o) {157// Scan from the end for better locality.158for (int i = next_id_ - 1; i >= 0; --i)159if (origins_[i] == o) return i;160if (next_id_ == kMaxSize_) return OVERFLOW;161int id = next_id_++;162origins_[id] = o;163return id;164}165int size() { return next_id_; }166u32 get(int id) { return origins_[id]; }167static char asChar(int id) {168switch (id) {169case MISSING:170return '.';171case OVERFLOW:172return '*';173default:174return 'A' + id;175}176}177static const int OVERFLOW = -1;178static const int MISSING = -2;179180private:181static const int kMaxSize_ = 'Z' - 'A' + 1;182u32 origins_[kMaxSize_];183int next_id_;184};185186void DescribeMemoryRange(const void *x, uptr size) {187// Real limits.188uptr start = MEM_TO_SHADOW(x);189uptr end = start + size;190// Scan limits: align start down to 4; align size up to 16.191uptr s = start & ~3UL;192size = end - s;193size = (size + 15) & ~15UL;194uptr e = s + size;195196// Single letter names to origin id mapping.197OriginSet origin_set;198199uptr pos = 0; // Offset from aligned start.200bool with_origins = __msan_get_track_origins();201// True if there is at least 1 poisoned bit in the last 4-byte group.202bool last_quad_poisoned;203int origin_ids[4]; // Single letter origin ids for the current line.204205Decorator d;206Printf("%s", d.Warning());207uptr start_x = reinterpret_cast<uptr>(x);208Printf("Shadow map [%p, %p) of [%p, %p), %zu bytes:\n",209reinterpret_cast<void *>(start), reinterpret_cast<void *>(end),210reinterpret_cast<void *>(start_x),211reinterpret_cast<void *>(start_x + end - start), end - start);212Printf("%s", d.Default());213while (s < e) {214// Line start.215if (pos % 16 == 0) {216for (int i = 0; i < 4; ++i) origin_ids[i] = -1;217Printf("%p[%p]:", reinterpret_cast<void *>(s),218reinterpret_cast<void *>(start_x - start + s));219}220// Group start.221if (pos % 4 == 0) {222Printf(" ");223last_quad_poisoned = false;224}225// Print shadow byte.226if (s < start || s >= end) {227Printf("..");228} else {229unsigned char v = *(unsigned char *)s;230if (v) last_quad_poisoned = true;231Printf("%x%x", v >> 4, v & 0xf);232}233// Group end.234if (pos % 4 == 3 && with_origins) {235int id = OriginSet::MISSING;236if (last_quad_poisoned) {237u32 o = *(u32 *)SHADOW_TO_ORIGIN(s - 3);238id = origin_set.insert(o);239}240origin_ids[(pos % 16) / 4] = id;241}242// Line end.243if (pos % 16 == 15) {244if (with_origins) {245Printf(" |");246for (int i = 0; i < 4; ++i) {247char c = OriginSet::asChar(origin_ids[i]);248Printf("%c", c);249if (i != 3) Printf(" ");250}251Printf("|");252}253Printf("\n");254}255size--;256s++;257pos++;258}259260Printf("\n");261262for (int i = 0; i < origin_set.size(); ++i) {263u32 o = origin_set.get(i);264Printf("Origin %c (origin_id %x):\n", OriginSet::asChar(i), o);265DescribeOrigin(o);266}267}268269void ReportUMRInsideAddressRange(const char *function, const void *start,270uptr size, uptr offset) {271function = StackTracePrinter::GetOrInit()->StripFunctionName(function);272Decorator d;273Printf("%s", d.Warning());274Printf("%sUninitialized bytes in %s%s%s at offset %zu inside [%p, %zu)%s\n",275d.Warning(), d.Name(), function, d.Warning(), offset, start, size,276d.Default());277if (__sanitizer::Verbosity())278DescribeMemoryRange(start, size);279}280281} // namespace __msan282283284