msan.cc revision efbc43528892b0a30039f68633e0b4ed3bbd2dae
11510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.org//===-- msan.cc -----------------------------------------------------------===//
21510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.org//
31510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.org//                     The LLVM Compiler Infrastructure
41510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.org//
51510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.org// This file is distributed under the University of Illinois Open Source
61510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.org// License. See LICENSE.TXT for details.
71510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.org//
81510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.org//===----------------------------------------------------------------------===//
91510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.org//
101510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.org// This file is a part of MemorySanitizer.
111510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.org//
121510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.org// MemorySanitizer runtime.
131510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.org//===----------------------------------------------------------------------===//
141510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.org
151510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.org#include "msan.h"
161510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.org#include "sanitizer_common/sanitizer_atomic.h"
171510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.org#include "sanitizer_common/sanitizer_common.h"
181510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.org#include "sanitizer_common/sanitizer_flags.h"
191510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.org#include "sanitizer_common/sanitizer_libc.h"
201510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.org#include "sanitizer_common/sanitizer_procmaps.h"
211510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.org#include "sanitizer_common/sanitizer_stacktrace.h"
221510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.org#include "sanitizer_common/sanitizer_symbolizer.h"
231510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.org
241510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.org#include "interception/interception.h"
251510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.org
261510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.org// ACHTUNG! No system header includes in this file.
271510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.org
281510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.orgusing namespace __sanitizer;
291510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.org
301510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.org// Globals.
311510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.orgstatic THREADLOCAL int msan_expect_umr = 0;
321510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.orgstatic THREADLOCAL int msan_expected_umr_found = 0;
331510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.org
341510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.orgstatic int msan_running_under_dr = 0;
351510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.org
361510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.orgSANITIZER_INTERFACE_ATTRIBUTE
371510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.orgTHREADLOCAL u64 __msan_param_tls[kMsanParamTlsSizeInWords];
381510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.org
391510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.orgSANITIZER_INTERFACE_ATTRIBUTE
401510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.orgTHREADLOCAL u32 __msan_param_origin_tls[kMsanParamTlsSizeInWords];
411510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.org
421510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.orgSANITIZER_INTERFACE_ATTRIBUTE
431510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.orgTHREADLOCAL u64 __msan_retval_tls[kMsanRetvalTlsSizeInWords];
441510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.org
451510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.orgSANITIZER_INTERFACE_ATTRIBUTE
461510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.orgTHREADLOCAL u32 __msan_retval_origin_tls;
471510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.org
481510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.orgSANITIZER_INTERFACE_ATTRIBUTE
491510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.orgTHREADLOCAL u64 __msan_va_arg_tls[kMsanParamTlsSizeInWords];
501510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.org
511510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.orgSANITIZER_INTERFACE_ATTRIBUTE
521510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.orgTHREADLOCAL u64 __msan_va_arg_overflow_size_tls;
531510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.org
541510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.orgSANITIZER_INTERFACE_ATTRIBUTE
551510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.orgTHREADLOCAL u32 __msan_origin_tls;
561510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.org
571510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.orgstatic THREADLOCAL struct {
581510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.org  uptr stack_top, stack_bottom;
591510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.org} __msan_stack_bounds;
601510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.org
611510d58cbcf57c82a10e7d390bfe21a7ae68ba43mstarzinger@chromium.orgstatic THREADLOCAL bool is_in_symbolizer;
62
63extern "C" const int __msan_track_origins;
64int __msan_get_track_origins() {
65  return __msan_track_origins;
66}
67
68namespace __msan {
69
70static bool IsRunningUnderDr() {
71  bool result = false;
72  MemoryMappingLayout proc_maps;
73  const sptr kBufSize = 4095;
74  char *filename = (char*)MmapOrDie(kBufSize, __FUNCTION__);
75  while (proc_maps.Next(/* start */0, /* end */0, /* file_offset */0,
76                        filename, kBufSize)) {
77    if (internal_strstr(filename, "libdynamorio") != 0) {
78      result = true;
79      break;
80    }
81  }
82  UnmapOrDie(filename, kBufSize);
83  return result;
84}
85
86void EnterSymbolizer() { is_in_symbolizer = true; }
87void ExitSymbolizer()  { is_in_symbolizer = false; }
88bool IsInSymbolizer() { return is_in_symbolizer; }
89
90static Flags msan_flags;
91
92Flags *flags() {
93  return &msan_flags;
94}
95
96int msan_inited = 0;
97bool msan_init_is_running;
98
99int msan_report_count = 0;
100
101// Array of stack origins.
102// FIXME: make it resizable.
103static const uptr kNumStackOriginDescrs = 1024 * 1024;
104static const char *StackOriginDescr[kNumStackOriginDescrs];
105static atomic_uint32_t NumStackOriginDescrs;
106
107static void ParseFlagsFromString(Flags *f, const char *str) {
108  ParseFlag(str, &f->poison_heap_with_zeroes, "poison_heap_with_zeroes");
109  ParseFlag(str, &f->poison_stack_with_zeroes, "poison_stack_with_zeroes");
110  ParseFlag(str, &f->poison_in_malloc, "poison_in_malloc");
111  ParseFlag(str, &f->exit_code, "exit_code");
112  if (f->exit_code < 0 || f->exit_code > 127) {
113    Printf("Exit code not in [0, 128) range: %d\n", f->exit_code);
114    f->exit_code = 1;
115    Die();
116  }
117  ParseFlag(str, &f->num_callers, "num_callers");
118  ParseFlag(str, &f->report_umrs, "report_umrs");
119  ParseFlag(str, &f->verbosity, "verbosity");
120  ParseFlag(str, &f->strip_path_prefix, "strip_path_prefix");
121}
122
123static void InitializeFlags(Flags *f, const char *options) {
124  internal_memset(f, 0, sizeof(*f));
125
126  f->poison_heap_with_zeroes = false;
127  f->poison_stack_with_zeroes = false;
128  f->poison_in_malloc = true;
129  f->exit_code = 77;
130  f->num_callers = 20;
131  f->report_umrs = true;
132  f->verbosity = 0;
133  f->strip_path_prefix = "";
134
135  // Override from user-specified string.
136  if (__msan_default_options)
137    ParseFlagsFromString(f, __msan_default_options());
138  ParseFlagsFromString(f, options);
139}
140
141static void GetCurrentStackBounds(uptr *stack_top, uptr *stack_bottom) {
142  if (__msan_stack_bounds.stack_top == 0) {
143    // Break recursion (GetStackTrace -> GetThreadStackTopAndBottom ->
144    // realloc -> GetStackTrace).
145    __msan_stack_bounds.stack_top = __msan_stack_bounds.stack_bottom = 1;
146    GetThreadStackTopAndBottom(/* at_initialization */false,
147                               &__msan_stack_bounds.stack_top,
148                               &__msan_stack_bounds.stack_bottom);
149  }
150  *stack_top = __msan_stack_bounds.stack_top;
151  *stack_bottom = __msan_stack_bounds.stack_bottom;
152}
153
154void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp,
155                   bool fast) {
156  if (!fast)
157    return stack->SlowUnwindStack(pc, max_s);
158
159  uptr stack_top, stack_bottom;
160  GetCurrentStackBounds(&stack_top, &stack_bottom);
161  stack->size = 0;
162  stack->trace[0] = pc;
163  stack->max_size = max_s;
164  stack->FastUnwindStack(pc, bp, stack_top, stack_bottom);
165}
166
167void PrintWarning(uptr pc, uptr bp) {
168  PrintWarningWithOrigin(pc, bp, __msan_origin_tls);
169}
170
171bool OriginIsValid(u32 origin) {
172  return origin != 0 && origin != (u32)-1;
173}
174
175void PrintWarningWithOrigin(uptr pc, uptr bp, u32 origin) {
176  if (msan_expect_umr) {
177    // Printf("Expected UMR\n");
178    __msan_origin_tls = origin;
179    msan_expected_umr_found = 1;
180    return;
181  }
182
183  ++msan_report_count;
184
185  StackTrace stack;
186  GetStackTrace(&stack, kStackTraceMax, pc, bp, /*fast*/false);
187
188  u32 report_origin =
189    (__msan_track_origins && OriginIsValid(origin)) ? origin : 0;
190  ReportUMR(&stack, report_origin);
191
192  if (__msan_track_origins && !OriginIsValid(origin)) {
193    Printf("  ORIGIN: invalid (%x). Might be a bug in MemorySanitizer, "
194           "please report to MemorySanitizer developers.\n",
195           origin);
196  }
197}
198
199}  // namespace __msan
200
201// Interface.
202
203using namespace __msan;
204
205void __msan_warning() {
206  GET_CALLER_PC_BP_SP;
207  (void)sp;
208  PrintWarning(pc, bp);
209}
210
211void __msan_warning_noreturn() {
212  GET_CALLER_PC_BP_SP;
213  (void)sp;
214  PrintWarning(pc, bp);
215  Printf("Exiting\n");
216  Die();
217}
218
219void __msan_init() {
220  if (msan_inited) return;
221  msan_init_is_running = 1;
222  SanitizerToolName = "MemorySanitizer";
223
224  InstallAtExitHandler();
225  SetDieCallback(MsanDie);
226  InitializeInterceptors();
227
228  ReplaceOperatorsNewAndDelete();
229  const char *msan_options = GetEnv("MSAN_OPTIONS");
230  InitializeFlags(&msan_flags, msan_options);
231  if (StackSizeIsUnlimited()) {
232    if (flags()->verbosity)
233      Printf("Unlimited stack, doing reexec\n");
234    // A reasonably large stack size. It is bigger than the usual 8Mb, because,
235    // well, the program could have been run with unlimited stack for a reason.
236    SetStackSizeLimitInBytes(32 * 1024 * 1024);
237    ReExec();
238  }
239
240  if (flags()->verbosity)
241    Printf("MSAN_OPTIONS: %s\n", msan_options ? msan_options : "<empty>");
242
243  msan_running_under_dr = IsRunningUnderDr();
244  __msan_clear_on_return();
245  if (__msan_track_origins && flags()->verbosity > 0)
246    Printf("msan_track_origins\n");
247  if (!InitShadow(/* prot1 */false, /* prot2 */true, /* map_shadow */true,
248                  __msan_track_origins)) {
249    // FIXME: prot1 = false is only required when running under DR.
250    Printf("FATAL: MemorySanitizer can not mmap the shadow memory.\n");
251    Printf("FATAL: Make sure to compile with -fPIE and to link with -pie.\n");
252    Printf("FATAL: Disabling ASLR is known to cause this error.\n");
253    Printf("FATAL: If running under GDB, try "
254           "'set disable-randomization off'.\n");
255    DumpProcessMap();
256    Die();
257  }
258
259  const char *external_symbolizer = GetEnv("MSAN_SYMBOLIZER_PATH");
260  if (external_symbolizer && external_symbolizer[0]) {
261    CHECK(InitializeExternalSymbolizer(external_symbolizer));
262  }
263
264  GetThreadStackTopAndBottom(/* at_initialization */true,
265                             &__msan_stack_bounds.stack_top,
266                             &__msan_stack_bounds.stack_bottom);
267  if (flags()->verbosity)
268    Printf("MemorySanitizer init done\n");
269  msan_init_is_running = 0;
270  msan_inited = 1;
271}
272
273void __msan_set_exit_code(int exit_code) {
274  flags()->exit_code = exit_code;
275}
276
277void __msan_set_expect_umr(int expect_umr) {
278  if (expect_umr) {
279    msan_expected_umr_found = 0;
280  } else if (!msan_expected_umr_found) {
281    GET_CALLER_PC_BP_SP;
282    (void)sp;
283    StackTrace stack;
284    GetStackTrace(&stack, kStackTraceMax, pc, bp, /*fast*/false);
285    ReportExpectedUMRNotFound(&stack);
286    Die();
287  }
288  msan_expect_umr = expect_umr;
289}
290
291void __msan_print_shadow(const void *x, uptr size) {
292  unsigned char *s = (unsigned char*)MEM_TO_SHADOW(x);
293  u32 *o = (u32*)MEM_TO_ORIGIN(x);
294  for (uptr i = 0; i < size; i++) {
295    Printf("%x%x ", s[i] >> 4, s[i] & 0xf);
296  }
297  Printf("\n");
298  if (__msan_track_origins) {
299    for (uptr i = 0; i < size / 4; i++) {
300      Printf(" o: %x ", o[i]);
301    }
302    Printf("\n");
303  }
304}
305
306void __msan_print_param_shadow() {
307  for (int i = 0; i < 16; i++) {
308    Printf("#%d:%zx ", i, __msan_param_tls[i]);
309  }
310  Printf("\n");
311}
312
313sptr __msan_test_shadow(const void *x, uptr size) {
314  unsigned char *s = (unsigned char*)MEM_TO_SHADOW((uptr)x);
315  for (uptr i = 0; i < size; ++i)
316    if (s[i])
317      return i;
318  return -1;
319}
320
321int __msan_set_poison_in_malloc(int do_poison) {
322  int old = flags()->poison_in_malloc;
323  flags()->poison_in_malloc = do_poison;
324  return old;
325}
326
327int  __msan_has_dynamic_component() {
328  return msan_running_under_dr;
329}
330
331NOINLINE
332void __msan_clear_on_return() {
333  __msan_param_tls[0] = 0;
334}
335
336static void* get_tls_base() {
337  u64 p;
338  asm("mov %%fs:0, %0"
339      : "=r"(p) ::);
340  return (void*)p;
341}
342
343int __msan_get_retval_tls_offset() {
344  // volatile here is needed to avoid UB, because the compiler thinks that we
345  // are doing address arithmetics on unrelated pointers, and takes some
346  // shortcuts
347  volatile sptr retval_tls_p = (sptr)&__msan_retval_tls;
348  volatile sptr tls_base_p = (sptr)get_tls_base();
349  return retval_tls_p - tls_base_p;
350}
351
352int __msan_get_param_tls_offset() {
353  // volatile here is needed to avoid UB, because the compiler thinks that we
354  // are doing address arithmetics on unrelated pointers, and takes some
355  // shortcuts
356  volatile sptr param_tls_p = (sptr)&__msan_param_tls;
357  volatile sptr tls_base_p = (sptr)get_tls_base();
358  return param_tls_p - tls_base_p;
359}
360
361void __msan_partial_poison(void* data, void* shadow, uptr size) {
362  internal_memcpy((void*)MEM_TO_SHADOW((uptr)data), shadow, size);
363}
364
365void __msan_load_unpoisoned(void *src, uptr size, void *dst) {
366  internal_memcpy(dst, src, size);
367  __msan_unpoison(dst, size);
368}
369
370void __msan_set_origin(void *a, uptr size, u32 origin) {
371  // Origin mapping is 4 bytes per 4 bytes of application memory.
372  // Here we extend the range such that its left and right bounds are both
373  // 4 byte aligned.
374  if (!__msan_track_origins) return;
375  uptr x = MEM_TO_ORIGIN((uptr)a);
376  uptr beg = x & ~3UL;  // align down.
377  uptr end = (x + size + 3) & ~3UL;  // align up.
378  u64 origin64 = ((u64)origin << 32) | origin;
379  // This is like memset, but the value is 32-bit. We unroll by 2 two write
380  // 64-bits at once. May want to unroll further to get 128-bit stores.
381  if (beg & 7ULL) {
382    *(u32*)beg = origin;
383    beg += 4;
384  }
385  for (uptr addr = beg; addr < (end & ~7UL); addr += 8)
386    *(u64*)addr = origin64;
387  if (end & 7ULL)
388    *(u32*)(end - 4) = origin;
389}
390
391// 'descr' is created at compile time and contains '----' in the beginning.
392// When we see descr for the first time we replace '----' with a uniq id
393// and set the origin to (id | (31-th bit)).
394void __msan_set_alloca_origin(void *a, uptr size, const char *descr) {
395  static const u32 dash = '-';
396  static const u32 first_timer =
397      dash + (dash << 8) + (dash << 16) + (dash << 24);
398  u32 *id_ptr = (u32*)descr;
399  bool print = false;  // internal_strstr(descr + 4, "AllocaTOTest") != 0;
400  u32 id = *id_ptr;
401  if (id == first_timer) {
402    id = atomic_fetch_add(&NumStackOriginDescrs,
403                          1, memory_order_relaxed);
404    *id_ptr = id;
405    CHECK_LT(id, kNumStackOriginDescrs);
406    StackOriginDescr[id] = descr + 4;
407    if (print)
408      Printf("First time: id=%d %s \n", id, descr + 4);
409  }
410  id |= 1U << 31;
411  if (print)
412    Printf("__msan_set_alloca_origin: descr=%s id=%x\n", descr + 4, id);
413  __msan_set_origin(a, size, id);
414}
415
416const char *__msan_get_origin_descr_if_stack(u32 id) {
417  if ((id >> 31) == 0) return 0;
418  id &= (1U << 31) - 1;
419  CHECK_LT(id, kNumStackOriginDescrs);
420  return StackOriginDescr[id];
421}
422
423
424u32 __msan_get_origin(void *a) {
425  if (!__msan_track_origins) return 0;
426  uptr x = (uptr)a;
427  uptr aligned = x & ~3ULL;
428  uptr origin_ptr = MEM_TO_ORIGIN(aligned);
429  return *(u32*)origin_ptr;
430}
431
432u32 __msan_get_umr_origin() {
433  return __msan_origin_tls;
434}
435
436#if !SANITIZER_SUPPORTS_WEAK_HOOKS
437extern "C" {
438SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
439const char* __msan_default_options() { return ""; }
440}  // extern "C"
441#endif
442
443