287 lines · cpp
1//===-- msan_report.cpp ---------------------------------------------------===//2//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-exception6//7//===----------------------------------------------------------------------===//8//9// This file is a part of MemorySanitizer.10//11// Error reporting.12//===----------------------------------------------------------------------===//13 14#include "msan_report.h"15 16#include "msan.h"17#include "msan_chained_origin_depot.h"18#include "msan_origin.h"19#include "sanitizer_common/sanitizer_allocator_internal.h"20#include "sanitizer_common/sanitizer_common.h"21#include "sanitizer_common/sanitizer_flags.h"22#include "sanitizer_common/sanitizer_mutex.h"23#include "sanitizer_common/sanitizer_report_decorator.h"24#include "sanitizer_common/sanitizer_stackdepot.h"25#include "sanitizer_common/sanitizer_stacktrace_printer.h"26#include "sanitizer_common/sanitizer_symbolizer.h"27 28using namespace __sanitizer;29 30namespace __msan {31 32class Decorator: public __sanitizer::SanitizerCommonDecorator {33 public:34 Decorator() : SanitizerCommonDecorator() { }35 const char *Origin() const { return Magenta(); }36 const char *Name() const { return Green(); }37};38 39static void DescribeStackOrigin(const char *so, uptr pc) {40 Decorator d;41 Printf("%s", d.Origin());42 if (so) {43 Printf(44 " %sUninitialized value was created by an allocation of '%s%s%s'"45 " in the stack frame%s\n",46 d.Origin(), d.Name(), so, d.Origin(), d.Default());47 } else {48 Printf(" %sUninitialized value was created in the stack frame%s\n",49 d.Origin(), d.Default());50 }51 52 if (pc)53 StackTrace(&pc, 1).Print();54}55 56static void DescribeOrigin(u32 id) {57 VPrintf(1, " raw origin id: %d\n", id);58 Decorator d;59 Origin o = Origin::FromRawId(id);60 while (o.isChainedOrigin()) {61 StackTrace stack;62 o = o.getNextChainedOrigin(&stack);63 Printf(" %sUninitialized value was stored to memory at%s\n", d.Origin(),64 d.Default());65 stack.Print();66 }67 if (o.isStackOrigin()) {68 uptr pc;69 const char *so = GetStackOriginDescr(o.getStackId(), &pc);70 DescribeStackOrigin(so, pc);71 } else {72 StackTrace stack = o.getStackTraceForHeapOrigin();73 switch (stack.tag) {74 case StackTrace::TAG_ALLOC:75 Printf(" %sUninitialized value was created by a heap allocation%s\n",76 d.Origin(), d.Default());77 break;78 case StackTrace::TAG_DEALLOC:79 Printf(" %sUninitialized value was created by a heap deallocation%s\n",80 d.Origin(), d.Default());81 break;82 case STACK_TRACE_TAG_POISON:83 Printf(" %sMemory was marked as uninitialized%s\n", d.Origin(),84 d.Default());85 break;86 case STACK_TRACE_TAG_FIELDS:87 Printf(" %sMember fields were destroyed%s\n", d.Origin(), d.Default());88 break;89 case STACK_TRACE_TAG_VPTR:90 Printf(" %sVirtual table ptr was destroyed%s\n", d.Origin(),91 d.Default());92 break;93 case STACK_TRACE_TAG_ALLOC_PADDING:94 Printf(" %sUninitialized value is outside of heap allocation%s\n",95 d.Origin(), d.Default());96 break;97 default:98 Printf(" %sUninitialized value was created%s\n", d.Origin(),99 d.Default());100 break;101 }102 stack.Print();103 }104}105 106void ReportUMR(StackTrace *stack, u32 origin) {107 if (!__msan::flags()->report_umrs) return;108 109 ScopedErrorReportLock l;110 111 Decorator d;112 Printf("%s", d.Warning());113 Report("WARNING: MemorySanitizer: use-of-uninitialized-value\n");114 Printf("%s", d.Default());115 stack->Print();116 if (origin) {117 DescribeOrigin(origin);118 }119 ReportErrorSummary("use-of-uninitialized-value", stack);120}121 122void ReportExpectedUMRNotFound(StackTrace *stack) {123 ScopedErrorReportLock l;124 125 Printf("WARNING: Expected use of uninitialized value not found\n");126 stack->Print();127}128 129void ReportStats() {130 ScopedErrorReportLock l;131 132 if (__msan_get_track_origins() > 0) {133 StackDepotStats stack_depot_stats = StackDepotGetStats();134 // FIXME: we want this at normal exit, too!135 // FIXME: but only with verbosity=1 or something136 Printf("Unique heap origins: %zu\n", stack_depot_stats.n_uniq_ids);137 Printf("Stack depot allocated bytes: %zu\n", stack_depot_stats.allocated);138 139 StackDepotStats chained_origin_depot_stats = ChainedOriginDepotGetStats();140 Printf("Unique origin histories: %zu\n",141 chained_origin_depot_stats.n_uniq_ids);142 Printf("History depot allocated bytes: %zu\n",143 chained_origin_depot_stats.allocated);144 }145}146 147void ReportAtExitStatistics() {148 ScopedErrorReportLock l;149 150 if (msan_report_count > 0) {151 Decorator d;152 Printf("%s", d.Warning());153 Printf("MemorySanitizer: %d warnings reported.\n", msan_report_count);154 Printf("%s", d.Default());155 }156}157 158class OriginSet {159 public:160 OriginSet() : next_id_(0) {}161 int insert(u32 o) {162 // Scan from the end for better locality.163 for (int i = next_id_ - 1; i >= 0; --i)164 if (origins_[i] == o) return i;165 if (next_id_ == kMaxSize_) return OVERFLOW;166 int id = next_id_++;167 origins_[id] = o;168 return id;169 }170 int size() { return next_id_; }171 u32 get(int id) { return origins_[id]; }172 static char asChar(int id) {173 switch (id) {174 case MISSING:175 return '.';176 case OVERFLOW:177 return '*';178 default:179 return 'A' + id;180 }181 }182 static const int OVERFLOW = -1;183 static const int MISSING = -2;184 185 private:186 static const int kMaxSize_ = 'Z' - 'A' + 1;187 u32 origins_[kMaxSize_];188 int next_id_;189};190 191void DescribeMemoryRange(const void *x, uptr size) {192 // Real limits.193 uptr start = MEM_TO_SHADOW(x);194 uptr end = start + size;195 // Scan limits: align start down to 4; align size up to 16.196 uptr s = start & ~3UL;197 size = end - s;198 size = (size + 15) & ~15UL;199 uptr e = s + size;200 201 // Single letter names to origin id mapping.202 OriginSet origin_set;203 204 uptr pos = 0; // Offset from aligned start.205 bool with_origins = __msan_get_track_origins();206 // True if there is at least 1 poisoned bit in the last 4-byte group.207 bool last_quad_poisoned;208 int origin_ids[4]; // Single letter origin ids for the current line.209 210 Decorator d;211 Printf("%s", d.Warning());212 uptr start_x = reinterpret_cast<uptr>(x);213 Printf("Shadow map [%p, %p) of [%p, %p), %zu bytes:\n",214 reinterpret_cast<void *>(start), reinterpret_cast<void *>(end),215 reinterpret_cast<void *>(start_x),216 reinterpret_cast<void *>(start_x + end - start), end - start);217 Printf("%s", d.Default());218 while (s < e) {219 // Line start.220 if (pos % 16 == 0) {221 for (int i = 0; i < 4; ++i) origin_ids[i] = -1;222 Printf("%p[%p]:", reinterpret_cast<void *>(s),223 reinterpret_cast<void *>(start_x - start + s));224 }225 // Group start.226 if (pos % 4 == 0) {227 Printf(" ");228 last_quad_poisoned = false;229 }230 // Print shadow byte.231 if (s < start || s >= end) {232 Printf("..");233 } else {234 unsigned char v = *(unsigned char *)s;235 if (v) last_quad_poisoned = true;236 Printf("%x%x", v >> 4, v & 0xf);237 }238 // Group end.239 if (pos % 4 == 3 && with_origins) {240 int id = OriginSet::MISSING;241 if (last_quad_poisoned) {242 u32 o = *(u32 *)SHADOW_TO_ORIGIN(s - 3);243 id = origin_set.insert(o);244 }245 origin_ids[(pos % 16) / 4] = id;246 }247 // Line end.248 if (pos % 16 == 15) {249 if (with_origins) {250 Printf(" |");251 for (int i = 0; i < 4; ++i) {252 char c = OriginSet::asChar(origin_ids[i]);253 Printf("%c", c);254 if (i != 3) Printf(" ");255 }256 Printf("|");257 }258 Printf("\n");259 }260 size--;261 s++;262 pos++;263 }264 265 Printf("\n");266 267 for (int i = 0; i < origin_set.size(); ++i) {268 u32 o = origin_set.get(i);269 Printf("Origin %c (origin_id %x):\n", OriginSet::asChar(i), o);270 DescribeOrigin(o);271 }272}273 274void ReportUMRInsideAddressRange(const char *function, const void *start,275 uptr size, uptr offset) {276 function = StackTracePrinter::GetOrInit()->StripFunctionName(function);277 Decorator d;278 Printf("%s", d.Warning());279 Printf("%sUninitialized bytes in %s%s%s at offset %zu inside [%p, %zu)%s\n",280 d.Warning(), d.Name(), function, d.Warning(), offset, start, size,281 d.Default());282 if (__sanitizer::Verbosity())283 DescribeMemoryRange(start, size);284}285 286} // namespace __msan287