Home | History | Annotate | Download | only in msan
      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