| Kostya Serebryany | 4a42cf6 | 2012-12-27 14:09:19 +0000 | [diff] [blame] | 1 | //===-- msan_report.cc ----------------------------------------------------===// | 
| Evgeniy Stepanov | 367dc64 | 2012-12-26 09:32:05 +0000 | [diff] [blame] | 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" | 
| Evgeniy Stepanov | 208aae8 | 2014-05-21 09:02:13 +0000 | [diff] [blame] | 16 | #include "msan_chained_origin_depot.h" | 
|  | 17 | #include "msan_origin.h" | 
| Alexey Samsonov | c30e2d6 | 2013-05-29 09:15:39 +0000 | [diff] [blame] | 18 | #include "sanitizer_common/sanitizer_allocator_internal.h" | 
| Evgeniy Stepanov | 367dc64 | 2012-12-26 09:32:05 +0000 | [diff] [blame] | 19 | #include "sanitizer_common/sanitizer_common.h" | 
| Sergey Matveev | 6eff11e | 2013-05-06 13:15:14 +0000 | [diff] [blame] | 20 | #include "sanitizer_common/sanitizer_flags.h" | 
| Evgeniy Stepanov | 367dc64 | 2012-12-26 09:32:05 +0000 | [diff] [blame] | 21 | #include "sanitizer_common/sanitizer_mutex.h" | 
| Evgeniy Stepanov | fee82c6 | 2012-12-26 10:16:45 +0000 | [diff] [blame] | 22 | #include "sanitizer_common/sanitizer_report_decorator.h" | 
| Evgeniy Stepanov | 367dc64 | 2012-12-26 09:32:05 +0000 | [diff] [blame] | 23 | #include "sanitizer_common/sanitizer_stackdepot.h" | 
| Kostya Serebryany | 7b0b9b3 | 2013-02-07 08:04:56 +0000 | [diff] [blame] | 24 | #include "sanitizer_common/sanitizer_symbolizer.h" | 
| Evgeniy Stepanov | 367dc64 | 2012-12-26 09:32:05 +0000 | [diff] [blame] | 25 |  | 
|  | 26 | using namespace __sanitizer; | 
|  | 27 |  | 
| Evgeniy Stepanov | 367dc64 | 2012-12-26 09:32:05 +0000 | [diff] [blame] | 28 | namespace __msan { | 
|  | 29 |  | 
| Sergey Matveev | dcd9bba | 2014-06-04 16:57:03 +0000 | [diff] [blame] | 30 | class Decorator: public __sanitizer::SanitizerCommonDecorator { | 
| Evgeniy Stepanov | fee82c6 | 2012-12-26 10:16:45 +0000 | [diff] [blame] | 31 | public: | 
| Sergey Matveev | dcd9bba | 2014-06-04 16:57:03 +0000 | [diff] [blame] | 32 | Decorator() : SanitizerCommonDecorator() { } | 
| Evgeniy Stepanov | fee82c6 | 2012-12-26 10:16:45 +0000 | [diff] [blame] | 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 |  | 
| Evgeniy Stepanov | 412d973 | 2014-03-18 13:45:19 +0000 | [diff] [blame] | 39 | static void DescribeStackOrigin(const char *so, uptr pc) { | 
| Evgeniy Stepanov | fee82c6 | 2012-12-26 10:16:45 +0000 | [diff] [blame] | 40 | Decorator d; | 
| Evgeniy Stepanov | 412d973 | 2014-03-18 13:45:19 +0000 | [diff] [blame] | 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", | 
| Evgeniy Stepanov | 465466e | 2014-07-14 09:35:27 +0000 | [diff] [blame] | 49 | d.Origin(), d.Name(), s, d.Origin(), d.Name(), sep + 1, d.Origin(), | 
|  | 50 | d.End()); | 
| Evgeniy Stepanov | 412d973 | 2014-03-18 13:45:19 +0000 | [diff] [blame] | 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. | 
| Alexey Samsonov | de13018 | 2014-11-19 21:42:33 +0000 | [diff] [blame] | 56 | pc = StackTrace::GetNextInstructionPc(pc); | 
| Alexey Samsonov | 9c85927 | 2014-10-26 03:35:14 +0000 | [diff] [blame] | 57 | StackTrace(&pc, 1).Print(); | 
| Evgeniy Stepanov | 412d973 | 2014-03-18 13:45:19 +0000 | [diff] [blame] | 58 | } | 
|  | 59 | } | 
|  | 60 |  | 
| Evgeniy Stepanov | 208aae8 | 2014-05-21 09:02:13 +0000 | [diff] [blame] | 61 | static void DescribeOrigin(u32 id) { | 
|  | 62 | VPrintf(1, "  raw origin id: %d\n", id); | 
|  | 63 | Decorator d; | 
| Evgeniy Stepanov | 7395cae | 2014-12-03 13:58:40 +0000 | [diff] [blame] | 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(); | 
| Evgeniy Stepanov | d38af30 | 2015-01-22 13:33:16 +0000 | [diff] [blame] | 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 | } | 
| Evgeniy Stepanov | 7395cae | 2014-12-03 13:58:40 +0000 | [diff] [blame] | 95 | stack.Print(); | 
| Evgeniy Stepanov | 367dc64 | 2012-12-26 09:32:05 +0000 | [diff] [blame] | 96 | } | 
|  | 97 | } | 
|  | 98 |  | 
|  | 99 | void ReportUMR(StackTrace *stack, u32 origin) { | 
|  | 100 | if (!__msan::flags()->report_umrs) return; | 
|  | 101 |  | 
| Alexey Samsonov | 734aab4 | 2013-04-05 07:30:29 +0000 | [diff] [blame] | 102 | SpinMutexLock l(&CommonSanitizerReportMutex); | 
| Evgeniy Stepanov | 367dc64 | 2012-12-26 09:32:05 +0000 | [diff] [blame] | 103 |  | 
| Evgeniy Stepanov | fee82c6 | 2012-12-26 10:16:45 +0000 | [diff] [blame] | 104 | Decorator d; | 
|  | 105 | Printf("%s", d.Warning()); | 
| Evgeniy Stepanov | dd0780f | 2013-05-28 14:27:30 +0000 | [diff] [blame] | 106 | Report(" WARNING: MemorySanitizer: use-of-uninitialized-value\n"); | 
| Evgeniy Stepanov | fee82c6 | 2012-12-26 10:16:45 +0000 | [diff] [blame] | 107 | Printf("%s", d.End()); | 
| Alexey Samsonov | f2c7659 | 2013-12-19 11:25:05 +0000 | [diff] [blame] | 108 | stack->Print(); | 
| Evgeniy Stepanov | 367dc64 | 2012-12-26 09:32:05 +0000 | [diff] [blame] | 109 | if (origin) { | 
|  | 110 | DescribeOrigin(origin); | 
|  | 111 | } | 
| Alexey Samsonov | 5dc6cff | 2013-11-01 17:02:14 +0000 | [diff] [blame] | 112 | ReportErrorSummary("use-of-uninitialized-value", stack); | 
| Evgeniy Stepanov | 367dc64 | 2012-12-26 09:32:05 +0000 | [diff] [blame] | 113 | } | 
|  | 114 |  | 
|  | 115 | void ReportExpectedUMRNotFound(StackTrace *stack) { | 
| Alexey Samsonov | 734aab4 | 2013-04-05 07:30:29 +0000 | [diff] [blame] | 116 | SpinMutexLock l(&CommonSanitizerReportMutex); | 
| Evgeniy Stepanov | 367dc64 | 2012-12-26 09:32:05 +0000 | [diff] [blame] | 117 |  | 
|  | 118 | Printf(" WARNING: Expected use of uninitialized value not found\n"); | 
| Alexey Samsonov | f2c7659 | 2013-12-19 11:25:05 +0000 | [diff] [blame] | 119 | stack->Print(); | 
| Evgeniy Stepanov | 367dc64 | 2012-12-26 09:32:05 +0000 | [diff] [blame] | 120 | } | 
|  | 121 |  | 
| Evgeniy Stepanov | bce21ac | 2014-05-21 09:56:28 +0000 | [diff] [blame] | 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 |  | 
| Evgeniy Stepanov | 9b52ce9 | 2013-01-10 11:17:55 +0000 | [diff] [blame] | 140 | void ReportAtExitStatistics() { | 
| Alexey Samsonov | 734aab4 | 2013-04-05 07:30:29 +0000 | [diff] [blame] | 141 | SpinMutexLock l(&CommonSanitizerReportMutex); | 
|  | 142 |  | 
| Evgeniy Stepanov | 412d973 | 2014-03-18 13:45:19 +0000 | [diff] [blame] | 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 | } | 
| Evgeniy Stepanov | 9b52ce9 | 2013-01-10 11:17:55 +0000 | [diff] [blame] | 149 | } | 
|  | 150 |  | 
| Evgeniy Stepanov | fe250b0 | 2014-04-30 09:50:30 +0000 | [diff] [blame] | 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; | 
| Evgeniy Stepanov | ee98fb1 | 2014-06-06 14:06:14 +0000 | [diff] [blame] | 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 | 
| Evgeniy Stepanov | fe250b0 | 2014-04-30 09:50:30 +0000 | [diff] [blame] | 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 |  | 
| Evgeniy Stepanov | 8dd62dc | 2014-05-07 11:50:14 +0000 | [diff] [blame] | 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()); | 
| Evgeniy Stepanov | f074b3c | 2015-01-20 13:21:20 +0000 | [diff] [blame] | 273 | if (__sanitizer::Verbosity()) | 
| Evgeniy Stepanov | 8dd62dc | 2014-05-07 11:50:14 +0000 | [diff] [blame] | 274 | DescribeMemoryRange(start, size); | 
|  | 275 | } | 
|  | 276 |  | 
| Alexey Samsonov | 49a32c1 | 2013-01-30 07:45:58 +0000 | [diff] [blame] | 277 | }  // namespace __msan |