diff --git a/compiler-rt/include/sanitizer/msan_interface.h b/compiler-rt/include/sanitizer/msan_interface.h index de5fc96dfa80..badb33472224 100644 --- a/compiler-rt/include/sanitizer/msan_interface.h +++ b/compiler-rt/include/sanitizer/msan_interface.h @@ -78,6 +78,10 @@ extern "C" { format. */ void __msan_print_shadow(const volatile void *x, size_t size); + /* Print shadow for the memory range to stderr in a minimalistic + human-readable format. */ + void __msan_dump_shadow(const volatile void *x, size_t size); + /* Returns true if running under a dynamic tool (DynamoRio-based). */ int __msan_has_dynamic_component(); diff --git a/compiler-rt/lib/msan/msan.cc b/compiler-rt/lib/msan/msan.cc index 8bf7c48acc7a..1df4fb8df7fd 100644 --- a/compiler-rt/lib/msan/msan.cc +++ b/compiler-rt/lib/msan/msan.cc @@ -383,18 +383,21 @@ void __msan_print_shadow(const void *x, uptr size) { Printf("Not a valid application address: %p\n", x); return; } + + DescribeMemoryRange(x, size); +} + +void __msan_dump_shadow(const void *x, uptr size) { + if (!MEM_IS_APP(x)) { + Printf("Not a valid application address: %p\n", x); + return; + } + unsigned char *s = (unsigned char*)MEM_TO_SHADOW(x); - u32 *o = (u32*)MEM_TO_ORIGIN(x); for (uptr i = 0; i < size; i++) { Printf("%x%x ", s[i] >> 4, s[i] & 0xf); } Printf("\n"); - if (__msan_get_track_origins()) { - for (uptr i = 0; i < size / 4; i++) { - Printf(" o: %x ", o[i]); - } - Printf("\n"); - } } sptr __msan_test_shadow(const void *x, uptr size) { diff --git a/compiler-rt/lib/msan/msan.h b/compiler-rt/lib/msan/msan.h index 7e16b324ea78..74fd76ed0c21 100644 --- a/compiler-rt/lib/msan/msan.h +++ b/compiler-rt/lib/msan/msan.h @@ -83,6 +83,7 @@ void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp, void ReportUMR(StackTrace *stack, u32 origin); void ReportExpectedUMRNotFound(StackTrace *stack); void ReportAtExitStatistics(); +void DescribeMemoryRange(const void *x, uptr size); // Unpoison first n function arguments. void UnpoisonParam(uptr n); diff --git a/compiler-rt/lib/msan/msan_interface_internal.h b/compiler-rt/lib/msan/msan_interface_internal.h index a5fc3a43b779..955288dc9b47 100644 --- a/compiler-rt/lib/msan/msan_interface_internal.h +++ b/compiler-rt/lib/msan/msan_interface_internal.h @@ -118,6 +118,8 @@ void __msan_set_expect_umr(int expect_umr); SANITIZER_INTERFACE_ATTRIBUTE void __msan_print_shadow(const void *x, uptr size); SANITIZER_INTERFACE_ATTRIBUTE +void __msan_dump_shadow(const void *x, uptr size); +SANITIZER_INTERFACE_ATTRIBUTE int __msan_has_dynamic_component(); // Returns x such that %fs:x is the first byte of __msan_retval_tls. diff --git a/compiler-rt/lib/msan/msan_report.cc b/compiler-rt/lib/msan/msan_report.cc index 7e709f879995..12bac2e8c064 100644 --- a/compiler-rt/lib/msan/msan_report.cc +++ b/compiler-rt/lib/msan/msan_report.cc @@ -124,4 +124,115 @@ void ReportAtExitStatistics() { Printf("Stack depot mapped bytes: %zu\n", stack_depot_stats->mapped); } +class OriginSet { + public: + OriginSet() : next_id_(0) {} + int insert(u32 o) { + // Scan from the end for better locality. + for (int i = next_id_ - 1; i >= 0; --i) + if (origins_[i] == o) return i; + if (next_id_ == kMaxSize_) return OVERFLOW; + int id = next_id_++; + origins_[id] = o; + return id; + } + int size() { return next_id_; } + u32 get(int id) { return origins_[id]; } + static char asChar(int id) { + switch (id) { + case MISSING: + return '.'; + case OVERFLOW: + return '*'; + default: + return 'A' + id; + } + } + static const int OVERFLOW = -1; + static const int MISSING = -2; + + private: + static const int kMaxSize_ = 'Z' - 'A' + 1; + u32 origins_[kMaxSize_]; + int next_id_; +}; + +void DescribeMemoryRange(const void *x, uptr size) { + // Real limits. + uptr start = MEM_TO_SHADOW(x); + uptr end = start + size; + // Scan limits: align start down to 4; align size up to 16. + uptr s = start & ~3UL; + size = end - s; + size = (size + 15) & ~15UL; + uptr e = s + size; + + // Single letter names to origin id mapping. + OriginSet origin_set; + + uptr pos = 0; // Offset from aligned start. + bool with_origins = __msan_get_track_origins(); + // True if there is at least 1 poisoned bit in the last 4-byte group. + bool last_quad_poisoned; + int origin_ids[4]; // Single letter origin ids for the current line. + + Decorator d; + Printf("%s", d.Warning()); + Printf("Shadow map of [%p, %p), %zu bytes:\n", start, end, end - start); + Printf("%s", d.End()); + while (s < e) { + // Line start. + if (pos % 16 == 0) { + for (int i = 0; i < 4; ++i) origin_ids[i] = -1; + Printf("%p:", s); + } + // Group start. + if (pos % 4 == 0) { + Printf(" "); + last_quad_poisoned = false; + } + // Print shadow byte. + if (s < start || s >= end) { + Printf(".."); + } else { + unsigned char v = *(unsigned char *)s; + if (v) last_quad_poisoned = true; + Printf("%02x", v); + } + // Group end. + if (pos % 4 == 3 && with_origins) { + int id = OriginSet::MISSING; + if (last_quad_poisoned) { + u32 o = *(u32 *)SHADOW_TO_ORIGIN(s - 3); + id = origin_set.insert(o); + } + origin_ids[(pos % 16) / 4] = id; + } + // Line end. + if (pos % 16 == 15) { + if (with_origins) { + Printf(" |"); + for (int i = 0; i < 4; ++i) { + char c = OriginSet::asChar(origin_ids[i]); + Printf("%c", c); + if (i != 3) Printf(" "); + } + Printf("|"); + } + Printf("\n"); + } + size--; + s++; + pos++; + } + + Printf("\n"); + + for (int i = 0; i < origin_set.size(); ++i) { + u32 o = origin_set.get(i); + Printf("Origin %c (origin_id %x):\n", OriginSet::asChar(i), o); + DescribeOrigin(o); + } +} + } // namespace __msan diff --git a/compiler-rt/test/msan/msan_dump_shadow.cc b/compiler-rt/test/msan/msan_dump_shadow.cc new file mode 100644 index 000000000000..507a09991551 --- /dev/null +++ b/compiler-rt/test/msan/msan_dump_shadow.cc @@ -0,0 +1,22 @@ +// RUN: %clangxx_msan -m64 -O0 -g %s -o %t && %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 -g %s -o %t && %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -m64 -O0 -g %s -o %t && %t >%t.out 2>&1 +// RUN: FileCheck %s < %t.out + +#include + +int main(void) { + char *p = new char[16]; + __msan_dump_shadow(p, 5); + delete[] p; + const char *q = "abc"; + __msan_dump_shadow(q, 3); + return 0; +} + +// CHECK: ff ff ff ff ff +// CHECK: 00 00 00 diff --git a/compiler-rt/test/msan/msan_print_shadow.cc b/compiler-rt/test/msan/msan_print_shadow.cc new file mode 100644 index 000000000000..b33bae0e94f8 --- /dev/null +++ b/compiler-rt/test/msan/msan_print_shadow.cc @@ -0,0 +1,122 @@ +// RUN: %clangxx_msan -m64 -O0 -g %s -o %t && %t >%t.out 2>&1 +// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NO-ORIGINS < %t.out + +// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 -g %s -o %t && %t >%t.out 2>&1 +// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-ORIGINS < %t.out + +// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -m64 -O0 -g %s -o %t && %t >%t.out 2>&1 +// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-ORIGINS --check-prefix=CHECK-ORIGINS-2 < %t.out + +#include + +int main(void) { + char volatile x; + char *p = new char[320]; + p[2] = p[5] = 1; + p[8] = p[9] = p[10] = p[11] = p[12] = 2; + + __msan_allocated_memory(p + 4*3, 4); + __msan_allocated_memory(p + 4*4, 4); + __msan_allocated_memory(p + 4*5, 4); + __msan_allocated_memory(p + 4*6, 4); + __msan_allocated_memory(p + 4*7, 4); + __msan_allocated_memory(p + 4*8, 4); + __msan_allocated_memory(p + 4*9, 4); + __msan_allocated_memory(p + 4*10, 4); + __msan_allocated_memory(p + 4*11, 4); + __msan_allocated_memory(p + 4*12, 4); + __msan_allocated_memory(p + 4*13, 4); + __msan_allocated_memory(p + 4*14, 4); + __msan_allocated_memory(p + 4*15, 4); + __msan_allocated_memory(p + 4*16, 4); + __msan_allocated_memory(p + 4*17, 4); + __msan_allocated_memory(p + 4*18, 4); + __msan_allocated_memory(p + 4*19, 4); + __msan_allocated_memory(p + 4*20, 4); + __msan_allocated_memory(p + 4*21, 4); + __msan_allocated_memory(p + 4*22, 4); + __msan_allocated_memory(p + 4*23, 4); + __msan_allocated_memory(p + 4*24, 4); + __msan_allocated_memory(p + 4*25, 4); + __msan_allocated_memory(p + 4*26, 4); + __msan_allocated_memory(p + 4*27, 4); + __msan_allocated_memory(p + 4*28, 4); + __msan_allocated_memory(p + 4*29, 4); + __msan_allocated_memory(p + 4*30, 4); + __msan_allocated_memory(p + 4*31, 4); + + p[19] = x; + + __msan_print_shadow(p+5, 297); + delete[] p; + return 0; +} + +// CHECK: Shadow map of [{{.*}}), 297 bytes: + +// CHECK-NO-ORIGINS: 0x{{.*}}: ..00ffff 00000000 ffffffff ffffffff +// CHECK-NO-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff +// CHECK-NO-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff +// CHECK-NO-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff +// CHECK-NO-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff +// CHECK-NO-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff +// CHECK-NO-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff +// CHECK-NO-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff +// CHECK-NO-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff +// CHECK-NO-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff +// CHECK-NO-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff +// CHECK-NO-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff +// CHECK-NO-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff +// CHECK-NO-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff +// CHECK-NO-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff +// CHECK-NO-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff +// CHECK-NO-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff +// CHECK-NO-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff +// CHECK-NO-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffff.... ........ + +// CHECK-ORIGINS: 0x{{.*}}: ..00ffff 00000000 ffffffff ffffffff |A . B C| +// CHECK-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff |D E F G| +// CHECK-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff |H I J K| +// CHECK-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff |L M N O| +// CHECK-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff |P Q R S| +// CHECK-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff |T U V W| +// CHECK-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff |X Y Z *| +// CHECK-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff |* * * A| +// CHECK-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff |A A A A| +// CHECK-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff |A A A A| +// CHECK-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff |A A A A| +// CHECK-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff |A A A A| +// CHECK-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff |A A A A| +// CHECK-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff |A A A A| +// CHECK-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff |A A A A| +// CHECK-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff |A A A A| +// CHECK-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff |A A A A| +// CHECK-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffffffff ffffffff |A A A A| +// CHECK-ORIGINS: 0x{{.*}}: ffffffff ffffffff ffff.... ........ |A A A .| + +// CHECK-ORIGINS: Origin A (origin_id {{.*}}): +// CHECK-ORIGINS: Uninitialized value was created by a heap allocation +// CHECK-ORIGINS: #1 {{.*}} in main{{.*}}msan_print_shadow.cc:14 + +// CHECK-ORIGINS: Origin B (origin_id {{.*}}): +// CHECK-ORIGINS: Uninitialized value was created by a heap allocation +// CHECK-ORIGINS: #0 {{.*}} in __msan_allocated_memory +// CHECK-ORIGINS: #1 {{.*}} in main{{.*}}msan_print_shadow.cc:18 + +// CHECK-ORIGINS: Origin C (origin_id {{.*}}): +// CHECK-ORIGINS-2: Uninitialized value was stored to memory at +// CHECK-ORIGINS-2: #0 {{.*}} in main{{.*}}msan_print_shadow.cc:48 +// CHECK-ORIGINS: Uninitialized value was created by an allocation of 'x' in the stack frame of function 'main' +// CHECK-ORIGINS: #0 {{.*}} in main{{.*}}msan_print_shadow.cc:12 + +// CHECK-ORIGINS: Origin D (origin_id {{.*}}): +// CHECK-ORIGINS: Uninitialized value was created by a heap allocation +// CHECK-ORIGINS: #0 {{.*}} in __msan_allocated_memory +// CHECK-ORIGINS: #1 {{.*}} in main{{.*}}msan_print_shadow.cc:20 + +// ... + +// CHECK-ORIGINS: Origin Z (origin_id {{.*}}): +// CHECK-ORIGINS: Uninitialized value was created by a heap allocation +// CHECK-ORIGINS: #0 {{.*}} in __msan_allocated_memory +// CHECK-ORIGINS: #1 {{.*}} in main{{.*}}msan_print_shadow.cc:42 diff --git a/compiler-rt/test/msan/msan_print_shadow2.cc b/compiler-rt/test/msan/msan_print_shadow2.cc new file mode 100644 index 000000000000..bd7a7879449f --- /dev/null +++ b/compiler-rt/test/msan/msan_print_shadow2.cc @@ -0,0 +1,49 @@ +// RUN: %clangxx_msan -m64 -O0 -g %s -o %t && %t >%t.out 2>&1 +// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-NO-ORIGINS < %t.out + +// RUN: %clangxx_msan -fsanitize-memory-track-origins -m64 -O0 -g %s -o %t && %t >%t.out 2>&1 +// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-ORIGINS < %t.out + +// RUN: %clangxx_msan -fsanitize-memory-track-origins=2 -m64 -O0 -g %s -o %t && %t >%t.out 2>&1 +// RUN: FileCheck %s --check-prefix=CHECK --check-prefix=CHECK-ORIGINS < %t.out + +#include + +int main(void) { + char *p = new char[16]; + __msan_print_shadow(p, 1); + __msan_print_shadow(p+1, 1); + __msan_print_shadow(p+3, 1); + __msan_print_shadow(p+15, 1); + __msan_print_shadow(p, 0); + delete[] p; + const char *q = "abc"; + __msan_print_shadow(q, 3); + return 0; +} + +// CHECK: Shadow map of [0x{{.*}}, 0x{{.*}}), 1 bytes: +// CHECK-NO-ORIGINS: 0x{{.*}}: ff...... ........ ........ ........ +// CHECK-ORIGINS: 0x{{.*}}: ff...... ........ ........ ........ |A . . .| +// CHECK-ORIGINS: Origin A (origin_id {{.*}}): + +// CHECK: Shadow map of [0x{{.*}}, 0x{{.*}}), 1 bytes: +// CHECK-NO-ORIGINS: 0x{{.*}}: ..ff.... ........ ........ ........ +// CHECK-ORIGINS: 0x{{.*}}: ..ff.... ........ ........ ........ |A . . .| +// CHECK-ORIGINS: Origin A (origin_id {{.*}}): + +// CHECK: Shadow map of [0x{{.*}}, 0x{{.*}}), 1 bytes: +// CHECK-NO-ORIGINS: 0x{{.*}}: ......ff ........ ........ ........ +// CHECK-ORIGINS: 0x{{.*}}: ......ff ........ ........ ........ |A . . .| +// CHECK-ORIGINS: Origin A (origin_id {{.*}}): + +// CHECK: Shadow map of [0x{{.*}}, 0x{{.*}}), 1 bytes: +// CHECK-NO-ORIGINS: 0x{{.*}}: ......ff ........ ........ ........ +// CHECK-ORIGINS: 0x{{.*}}: ......ff ........ ........ ........ |A . . .| +// CHECK-ORIGINS: Origin A (origin_id {{.*}}): + +// CHECK: Shadow map of [0x{{.*}}, 0x{{.*}}), 0 bytes: + +// CHECK: Shadow map of [0x{{.*}}, 0x{{.*}}), 3 bytes: +// CHECK-NO-ORIGINS: 0x{{.*}}: 000000.. ........ ........ ........ +// CHECK-ORIGINS: 0x{{.*}}: 000000.. ........ ........ ........ |. . . .|