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(), 50 Symbolizer::Get()->Demangle(sep + 1), d.Origin(), 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 += 1; 57 StackTrace::PrintStack(&pc, 1); 58 } 59 } 60 61 static void DescribeOrigin(u32 id) { 62 VPrintf(1, " raw origin id: %d\n", id); 63 Decorator d; 64 while (true) { 65 Origin o(id); 66 if (!o.isValid()) { 67 Printf(" %sinvalid origin id(%d)%s\n", d.Warning(), id, d.End()); 68 break; 69 } 70 u32 prev_id; 71 u32 stack_id = ChainedOriginDepotGet(o.id(), &prev_id); 72 Origin prev_o(prev_id); 73 74 if (prev_o.isStackRoot()) { 75 uptr pc; 76 const char *so = GetStackOriginDescr(stack_id, &pc); 77 DescribeStackOrigin(so, pc); 78 break; 79 } else if (prev_o.isHeapRoot()) { 80 uptr size = 0; 81 const uptr *trace = StackDepotGet(stack_id, &size); 82 Printf(" %sUninitialized value was created by a heap allocation%s\n", 83 d.Origin(), d.End()); 84 StackTrace::PrintStack(trace, size); 85 break; 86 } else { 87 // chained origin 88 uptr size = 0; 89 const uptr *trace = StackDepotGet(stack_id, &size); 90 // FIXME: copied? modified? passed through? observed? 91 Printf(" %sUninitialized value was stored to memory at%s\n", d.Origin(), 92 d.End()); 93 StackTrace::PrintStack(trace, size); 94 id = prev_id; 95 } 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 #if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__ 225 Printf("%x%x", v & 0xf, v >> 4); 226 #else 227 Printf("%x%x", v >> 4, v & 0xf); 228 #endif 229 } 230 // Group end. 231 if (pos % 4 == 3 && with_origins) { 232 int id = OriginSet::MISSING; 233 if (last_quad_poisoned) { 234 u32 o = *(u32 *)SHADOW_TO_ORIGIN(s - 3); 235 id = origin_set.insert(o); 236 } 237 origin_ids[(pos % 16) / 4] = id; 238 } 239 // Line end. 240 if (pos % 16 == 15) { 241 if (with_origins) { 242 Printf(" |"); 243 for (int i = 0; i < 4; ++i) { 244 char c = OriginSet::asChar(origin_ids[i]); 245 Printf("%c", c); 246 if (i != 3) Printf(" "); 247 } 248 Printf("|"); 249 } 250 Printf("\n"); 251 } 252 size--; 253 s++; 254 pos++; 255 } 256 257 Printf("\n"); 258 259 for (int i = 0; i < origin_set.size(); ++i) { 260 u32 o = origin_set.get(i); 261 Printf("Origin %c (origin_id %x):\n", OriginSet::asChar(i), o); 262 DescribeOrigin(o); 263 } 264 } 265 266 void ReportUMRInsideAddressRange(const char *what, const void *start, uptr size, 267 uptr offset) { 268 Decorator d; 269 Printf("%s", d.Warning()); 270 Printf("%sUninitialized bytes in %s%s%s at offset %zu inside [%p, %zu)%s\n", 271 d.Warning(), d.Name(), what, d.Warning(), offset, start, size, 272 d.End()); 273 if (__sanitizer::common_flags()->verbosity > 0) 274 DescribeMemoryRange(start, size); 275 } 276 277 } // namespace __msan 278