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(), 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