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