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-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file is a part of MemorySanitizer. 10 // 11 // Error reporting. 12 //===----------------------------------------------------------------------===// 13 14 #include "msan.h" 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" 25 26 using namespace __sanitizer; 27 28 namespace __msan { 29 30 class Decorator: public __sanitizer::SanitizerCommonDecorator { 31 public: 32 Decorator() : SanitizerCommonDecorator() { } 33 const char *Origin() const { return Magenta(); } 34 const char *Name() const { return Green(); } 35 }; 36 37 static void DescribeStackOrigin(const char *so, uptr pc) { 38 Decorator d; 39 Printf("%s", d.Origin()); 40 if (so) { 41 Printf( 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()); 45 } else { 46 Printf(" %sUninitialized value was created in the stack frame%s\n", 47 d.Origin(), d.Default()); 48 } 49 50 if (pc) 51 StackTrace(&pc, 1).Print(); 52 } 53 54 static void DescribeOrigin(u32 id) { 55 VPrintf(1, " raw origin id: %d\n", id); 56 Decorator d; 57 Origin o = Origin::FromRawId(id); 58 while (o.isChainedOrigin()) { 59 StackTrace stack; 60 o = o.getNextChainedOrigin(&stack); 61 Printf(" %sUninitialized value was stored to memory at%s\n", d.Origin(), 62 d.Default()); 63 stack.Print(); 64 } 65 if (o.isStackOrigin()) { 66 uptr pc; 67 const char *so = GetStackOriginDescr(o.getStackId(), &pc); 68 DescribeStackOrigin(so, pc); 69 } else { 70 StackTrace stack = o.getStackTraceForHeapOrigin(); 71 switch (stack.tag) { 72 case StackTrace::TAG_ALLOC: 73 Printf(" %sUninitialized value was created by a heap allocation%s\n", 74 d.Origin(), d.Default()); 75 break; 76 case StackTrace::TAG_DEALLOC: 77 Printf(" %sUninitialized value was created by a heap deallocation%s\n", 78 d.Origin(), d.Default()); 79 break; 80 case STACK_TRACE_TAG_POISON: 81 Printf(" %sMemory was marked as uninitialized%s\n", d.Origin(), 82 d.Default()); 83 break; 84 case STACK_TRACE_TAG_FIELDS: 85 Printf(" %sMember fields were destroyed%s\n", d.Origin(), d.Default()); 86 break; 87 case STACK_TRACE_TAG_VPTR: 88 Printf(" %sVirtual table ptr was destroyed%s\n", d.Origin(), 89 d.Default()); 90 break; 91 default: 92 Printf(" %sUninitialized value was created%s\n", d.Origin(), 93 d.Default()); 94 break; 95 } 96 stack.Print(); 97 } 98 } 99 100 void ReportUMR(StackTrace *stack, u32 origin) { 101 if (!__msan::flags()->report_umrs) return; 102 103 ScopedErrorReportLock l; 104 105 Decorator d; 106 Printf("%s", d.Warning()); 107 Report("WARNING: MemorySanitizer: use-of-uninitialized-value\n"); 108 Printf("%s", d.Default()); 109 stack->Print(); 110 if (origin) { 111 DescribeOrigin(origin); 112 } 113 ReportErrorSummary("use-of-uninitialized-value", stack); 114 } 115 116 void ReportExpectedUMRNotFound(StackTrace *stack) { 117 ScopedErrorReportLock l; 118 119 Printf("WARNING: Expected use of uninitialized value not found\n"); 120 stack->Print(); 121 } 122 123 void ReportStats() { 124 ScopedErrorReportLock l; 125 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); 132 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); 138 } 139 } 140 141 void ReportAtExitStatistics() { 142 ScopedErrorReportLock l; 143 144 if (msan_report_count > 0) { 145 Decorator d; 146 Printf("%s", d.Warning()); 147 Printf("MemorySanitizer: %d warnings reported.\n", msan_report_count); 148 Printf("%s", d.Default()); 149 } 150 } 151 152 class OriginSet { 153 public: 154 OriginSet() : next_id_(0) {} 155 int insert(u32 o) { 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; 160 int id = next_id_++; 161 origins_[id] = o; 162 return id; 163 } 164 int size() { return next_id_; } 165 u32 get(int id) { return origins_[id]; } 166 static char asChar(int id) { 167 switch (id) { 168 case MISSING: 169 return '.'; 170 case OVERFLOW: 171 return '*'; 172 default: 173 return 'A' + id; 174 } 175 } 176 static const int OVERFLOW = -1; 177 static const int MISSING = -2; 178 179 private: 180 static const int kMaxSize_ = 'Z' - 'A' + 1; 181 u32 origins_[kMaxSize_]; 182 int next_id_; 183 }; 184 185 void DescribeMemoryRange(const void *x, uptr size) { 186 // Real limits. 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; 191 size = end - s; 192 size = (size + 15) & ~15UL; 193 uptr e = s + size; 194 195 // Single letter names to origin id mapping. 196 OriginSet origin_set; 197 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. 203 204 Decorator d; 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()); 212 while (s < e) { 213 // Line start. 214 if (pos % 16 == 0) { 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)); 218 } 219 // Group start. 220 if (pos % 4 == 0) { 221 Printf(" "); 222 last_quad_poisoned = false; 223 } 224 // Print shadow byte. 225 if (s < start || s >= end) { 226 Printf(".."); 227 } else { 228 unsigned char v = *(unsigned char *)s; 229 if (v) last_quad_poisoned = true; 230 Printf("%x%x", v >> 4, v & 0xf); 231 } 232 // Group end. 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); 238 } 239 origin_ids[(pos % 16) / 4] = id; 240 } 241 // Line end. 242 if (pos % 16 == 15) { 243 if (with_origins) { 244 Printf(" |"); 245 for (int i = 0; i < 4; ++i) { 246 char c = OriginSet::asChar(origin_ids[i]); 247 Printf("%c", c); 248 if (i != 3) Printf(" "); 249 } 250 Printf("|"); 251 } 252 Printf("\n"); 253 } 254 size--; 255 s++; 256 pos++; 257 } 258 259 Printf("\n"); 260 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); 264 DescribeOrigin(o); 265 } 266 } 267 268 void ReportUMRInsideAddressRange(const char *what, const void *start, uptr size, 269 uptr offset) { 270 Decorator d; 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, 274 d.Default()); 275 if (__sanitizer::Verbosity()) 276 DescribeMemoryRange(start, size); 277 } 278 279 } // namespace __msan 280