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