aboutsummaryrefslogtreecommitdiff
path: root/lib/msan/msan.cc
diff options
context:
space:
mode:
Diffstat (limited to 'lib/msan/msan.cc')
-rw-r--r--lib/msan/msan.cc199
1 files changed, 148 insertions, 51 deletions
diff --git a/lib/msan/msan.cc b/lib/msan/msan.cc
index aa79b31be2e0..83b11e5c2ff3 100644
--- a/lib/msan/msan.cc
+++ b/lib/msan/msan.cc
@@ -58,14 +58,17 @@ static THREADLOCAL struct {
uptr stack_top, stack_bottom;
} __msan_stack_bounds;
-static THREADLOCAL bool is_in_symbolizer;
-static THREADLOCAL bool is_in_loader;
+static THREADLOCAL int is_in_symbolizer;
+static THREADLOCAL int is_in_loader;
+
+extern "C" SANITIZER_WEAK_ATTRIBUTE const int __msan_track_origins;
-extern "C" const int __msan_track_origins;
int __msan_get_track_origins() {
- return __msan_track_origins;
+ return &__msan_track_origins ? __msan_track_origins : 0;
}
+extern "C" SANITIZER_WEAK_ATTRIBUTE const int __msan_keep_going;
+
namespace __msan {
static bool IsRunningUnderDr() {
@@ -84,12 +87,12 @@ static bool IsRunningUnderDr() {
return result;
}
-void EnterSymbolizer() { is_in_symbolizer = true; }
-void ExitSymbolizer() { is_in_symbolizer = false; }
+void EnterSymbolizer() { ++is_in_symbolizer; }
+void ExitSymbolizer() { --is_in_symbolizer; }
bool IsInSymbolizer() { return is_in_symbolizer; }
-void EnterLoader() { is_in_loader = true; }
-void ExitLoader() { is_in_loader = false; }
+void EnterLoader() { ++is_in_loader; }
+void ExitLoader() { --is_in_loader; }
extern "C" {
SANITIZER_INTERFACE_ATTRIBUTE
@@ -111,6 +114,7 @@ int msan_report_count = 0;
// FIXME: make it resizable.
static const uptr kNumStackOriginDescrs = 1024 * 1024;
static const char *StackOriginDescr[kNumStackOriginDescrs];
+static uptr StackOriginPC[kNumStackOriginDescrs];
static atomic_uint32_t NumStackOriginDescrs;
static void ParseFlagsFromString(Flags *f, const char *str) {
@@ -118,33 +122,39 @@ static void ParseFlagsFromString(Flags *f, const char *str) {
ParseFlag(str, &f->poison_heap_with_zeroes, "poison_heap_with_zeroes");
ParseFlag(str, &f->poison_stack_with_zeroes, "poison_stack_with_zeroes");
ParseFlag(str, &f->poison_in_malloc, "poison_in_malloc");
+ ParseFlag(str, &f->poison_in_free, "poison_in_free");
ParseFlag(str, &f->exit_code, "exit_code");
if (f->exit_code < 0 || f->exit_code > 127) {
Printf("Exit code not in [0, 128) range: %d\n", f->exit_code);
- f->exit_code = 1;
Die();
}
ParseFlag(str, &f->report_umrs, "report_umrs");
- ParseFlag(str, &f->verbosity, "verbosity");
ParseFlag(str, &f->wrap_signals, "wrap_signals");
+
+ // keep_going is an old name for halt_on_error,
+ // and it has inverse meaning.
+ f->halt_on_error = !f->halt_on_error;
+ ParseFlag(str, &f->halt_on_error, "keep_going");
+ f->halt_on_error = !f->halt_on_error;
+ ParseFlag(str, &f->halt_on_error, "halt_on_error");
}
static void InitializeFlags(Flags *f, const char *options) {
CommonFlags *cf = common_flags();
+ SetCommonFlagDefaults();
cf->external_symbolizer_path = GetEnv("MSAN_SYMBOLIZER_PATH");
- cf->strip_path_prefix = "";
- cf->fast_unwind_on_fatal = false;
- cf->fast_unwind_on_malloc = true;
cf->malloc_context_size = 20;
+ cf->handle_ioctl = true;
internal_memset(f, 0, sizeof(*f));
f->poison_heap_with_zeroes = false;
f->poison_stack_with_zeroes = false;
f->poison_in_malloc = true;
+ f->poison_in_free = true;
f->exit_code = 77;
f->report_umrs = true;
- f->verbosity = 0;
f->wrap_signals = true;
+ f->halt_on_error = !&__msan_keep_going;
// Override from user-specified string.
if (__msan_default_options)
@@ -166,19 +176,15 @@ static void GetCurrentStackBounds(uptr *stack_top, uptr *stack_bottom) {
}
void GetStackTrace(StackTrace *stack, uptr max_s, uptr pc, uptr bp,
- bool fast) {
- if (!fast) {
+ bool request_fast_unwind) {
+ if (!StackTrace::WillUseFastUnwind(request_fast_unwind)) {
// Block reports from our interceptors during _Unwind_Backtrace.
SymbolizerScope sym_scope;
- return stack->SlowUnwindStack(pc, max_s);
+ return stack->Unwind(max_s, pc, bp, 0, 0, request_fast_unwind);
}
-
uptr stack_top, stack_bottom;
GetCurrentStackBounds(&stack_top, &stack_bottom);
- stack->size = 0;
- stack->trace[0] = pc;
- stack->max_size = max_s;
- stack->FastUnwindStack(pc, bp, stack_top, stack_bottom);
+ stack->Unwind(max_s, pc, bp, stack_top, stack_bottom, request_fast_unwind);
}
void PrintWarning(uptr pc, uptr bp) {
@@ -204,16 +210,55 @@ void PrintWarningWithOrigin(uptr pc, uptr bp, u32 origin) {
common_flags()->fast_unwind_on_fatal);
u32 report_origin =
- (__msan_track_origins && OriginIsValid(origin)) ? origin : 0;
+ (__msan_get_track_origins() && OriginIsValid(origin)) ? origin : 0;
ReportUMR(&stack, report_origin);
- if (__msan_track_origins && !OriginIsValid(origin)) {
- Printf(" ORIGIN: invalid (%x). Might be a bug in MemorySanitizer, "
- "please report to MemorySanitizer developers.\n",
- origin);
+ if (__msan_get_track_origins() && !OriginIsValid(origin)) {
+ Printf(
+ " ORIGIN: invalid (%x). Might be a bug in MemorySanitizer origin "
+ "tracking.\n This could still be a bug in your code, too!\n",
+ origin);
+ }
+}
+
+void UnpoisonParam(uptr n) {
+ internal_memset(__msan_param_tls, 0, n * sizeof(*__msan_param_tls));
+}
+
+// Backup MSan runtime TLS state.
+// Implementation must be async-signal-safe.
+// Instances of this class may live on the signal handler stack, and data size
+// may be an issue.
+void ScopedThreadLocalStateBackup::Backup() {
+ va_arg_overflow_size_tls = __msan_va_arg_overflow_size_tls;
+}
+
+void ScopedThreadLocalStateBackup::Restore() {
+ // A lame implementation that only keeps essential state and resets the rest.
+ __msan_va_arg_overflow_size_tls = va_arg_overflow_size_tls;
+
+ internal_memset(__msan_param_tls, 0, sizeof(__msan_param_tls));
+ internal_memset(__msan_retval_tls, 0, sizeof(__msan_retval_tls));
+ internal_memset(__msan_va_arg_tls, 0, sizeof(__msan_va_arg_tls));
+
+ if (__msan_get_track_origins()) {
+ internal_memset(&__msan_retval_origin_tls, 0, sizeof(__msan_retval_tls));
+ internal_memset(__msan_param_origin_tls, 0,
+ sizeof(__msan_param_origin_tls));
}
}
+void UnpoisonThreadLocalState() {
+}
+
+const char *GetOriginDescrIfStack(u32 id, uptr *pc) {
+ if ((id >> 31) == 0) return 0;
+ id &= (1U << 31) - 1;
+ CHECK_LT(id, kNumStackOriginDescrs);
+ if (pc) *pc = StackOriginPC[id];
+ return StackOriginDescr[id];
+}
+
} // namespace __msan
// Interface.
@@ -224,6 +269,10 @@ void __msan_warning() {
GET_CALLER_PC_BP_SP;
(void)sp;
PrintWarning(pc, bp);
+ if (__msan::flags()->halt_on_error) {
+ Printf("Exiting\n");
+ Die();
+ }
}
void __msan_warning_noreturn() {
@@ -239,17 +288,20 @@ void __msan_init() {
msan_init_is_running = 1;
SanitizerToolName = "MemorySanitizer";
- InstallAtExitHandler();
SetDieCallback(MsanDie);
InitTlsSize();
+
+ const char *msan_options = GetEnv("MSAN_OPTIONS");
+ InitializeFlags(&msan_flags, msan_options);
+ __sanitizer_set_report_path(common_flags()->log_path);
+
InitializeInterceptors();
+ InstallAtExitHandler(); // Needs __cxa_atexit interceptor.
if (MSAN_REPLACE_OPERATORS_NEW_AND_DELETE)
ReplaceOperatorsNewAndDelete();
- const char *msan_options = GetEnv("MSAN_OPTIONS");
- InitializeFlags(&msan_flags, msan_options);
if (StackSizeIsUnlimited()) {
- if (flags()->verbosity)
+ if (common_flags()->verbosity)
Printf("Unlimited stack, doing reexec\n");
// A reasonably large stack size. It is bigger than the usual 8Mb, because,
// well, the program could have been run with unlimited stack for a reason.
@@ -257,15 +309,15 @@ void __msan_init() {
ReExec();
}
- if (flags()->verbosity)
+ if (common_flags()->verbosity)
Printf("MSAN_OPTIONS: %s\n", msan_options ? msan_options : "<empty>");
msan_running_under_dr = IsRunningUnderDr();
__msan_clear_on_return();
- if (__msan_track_origins && flags()->verbosity > 0)
+ if (__msan_get_track_origins() && common_flags()->verbosity > 0)
Printf("msan_track_origins\n");
- if (!InitShadow(/* prot1 */false, /* prot2 */true, /* map_shadow */true,
- __msan_track_origins)) {
+ if (!InitShadow(/* prot1 */ false, /* prot2 */ true, /* map_shadow */ true,
+ __msan_get_track_origins())) {
// FIXME: prot1 = false is only required when running under DR.
Printf("FATAL: MemorySanitizer can not mmap the shadow memory.\n");
Printf("FATAL: Make sure to compile with -fPIE and to link with -pie.\n");
@@ -277,14 +329,17 @@ void __msan_init() {
}
const char *external_symbolizer = common_flags()->external_symbolizer_path;
+ bool external_symbolizer_started =
+ Symbolizer::Init(external_symbolizer)->IsExternalAvailable();
if (external_symbolizer && external_symbolizer[0]) {
- CHECK(InitializeExternalSymbolizer(external_symbolizer));
+ CHECK(external_symbolizer_started);
}
+ Symbolizer::Get()->AddHooks(EnterSymbolizer, ExitSymbolizer);
GetThreadStackTopAndBottom(/* at_initialization */true,
&__msan_stack_bounds.stack_top,
&__msan_stack_bounds.stack_bottom);
- if (flags()->verbosity)
+ if (common_flags()->verbosity)
Printf("MemorySanitizer init done\n");
msan_init_is_running = 0;
msan_inited = 1;
@@ -294,6 +349,10 @@ void __msan_set_exit_code(int exit_code) {
flags()->exit_code = exit_code;
}
+void __msan_set_keep_going(int keep_going) {
+ flags()->halt_on_error = !keep_going;
+}
+
void __msan_set_expect_umr(int expect_umr) {
if (expect_umr) {
msan_expected_umr_found = 0;
@@ -310,13 +369,17 @@ void __msan_set_expect_umr(int expect_umr) {
}
void __msan_print_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_track_origins) {
+ if (__msan_get_track_origins()) {
for (uptr i = 0; i < size / 4; i++) {
Printf(" o: %x ", o[i]);
}
@@ -331,10 +394,6 @@ void __msan_print_param_shadow() {
Printf("\n");
}
-void __msan_unpoison_param(uptr n) {
- internal_memset(__msan_param_tls, 0, n * sizeof(*__msan_param_tls));
-}
-
sptr __msan_test_shadow(const void *x, uptr size) {
unsigned char *s = (unsigned char*)MEM_TO_SHADOW((uptr)x);
for (uptr i = 0; i < size; ++i)
@@ -396,7 +455,7 @@ void __msan_set_origin(const void *a, uptr size, u32 origin) {
// Origin mapping is 4 bytes per 4 bytes of application memory.
// Here we extend the range such that its left and right bounds are both
// 4 byte aligned.
- if (!__msan_track_origins) return;
+ if (!__msan_get_track_origins()) return;
uptr x = MEM_TO_ORIGIN((uptr)a);
uptr beg = x & ~3UL; // align down.
uptr end = (x + size + 3) & ~3UL; // align up.
@@ -417,6 +476,10 @@ void __msan_set_origin(const void *a, uptr size, u32 origin) {
// When we see descr for the first time we replace '----' with a uniq id
// and set the origin to (id | (31-th bit)).
void __msan_set_alloca_origin(void *a, uptr size, const char *descr) {
+ __msan_set_alloca_origin4(a, size, descr, 0);
+}
+
+void __msan_set_alloca_origin4(void *a, uptr size, const char *descr, uptr pc) {
static const u32 dash = '-';
static const u32 first_timer =
dash + (dash << 8) + (dash << 16) + (dash << 24);
@@ -429,8 +492,9 @@ void __msan_set_alloca_origin(void *a, uptr size, const char *descr) {
*id_ptr = id;
CHECK_LT(id, kNumStackOriginDescrs);
StackOriginDescr[id] = descr + 4;
+ StackOriginPC[id] = pc;
if (print)
- Printf("First time: id=%d %s \n", id, descr + 4);
+ Printf("First time: id=%d %s %p \n", id, descr + 4, pc);
}
id |= 1U << 31;
if (print)
@@ -439,15 +503,11 @@ void __msan_set_alloca_origin(void *a, uptr size, const char *descr) {
}
const char *__msan_get_origin_descr_if_stack(u32 id) {
- if ((id >> 31) == 0) return 0;
- id &= (1U << 31) - 1;
- CHECK_LT(id, kNumStackOriginDescrs);
- return StackOriginDescr[id];
+ return GetOriginDescrIfStack(id, 0);
}
-
u32 __msan_get_origin(const void *a) {
- if (!__msan_track_origins) return 0;
+ if (!__msan_get_track_origins()) return 0;
uptr x = (uptr)a;
uptr aligned = x & ~3ULL;
uptr origin_ptr = MEM_TO_ORIGIN(aligned);
@@ -458,9 +518,46 @@ u32 __msan_get_umr_origin() {
return __msan_origin_tls;
}
+u16 __sanitizer_unaligned_load16(const uu16 *p) {
+ __msan_retval_tls[0] = *(uu16 *)MEM_TO_SHADOW((uptr)p);
+ if (__msan_get_track_origins())
+ __msan_retval_origin_tls = *(uu32 *)MEM_TO_ORIGIN((uptr)p);
+ return *p;
+}
+u32 __sanitizer_unaligned_load32(const uu32 *p) {
+ __msan_retval_tls[0] = *(uu32 *)MEM_TO_SHADOW((uptr)p);
+ if (__msan_get_track_origins())
+ __msan_retval_origin_tls = *(uu32 *)MEM_TO_ORIGIN((uptr)p);
+ return *p;
+}
+u64 __sanitizer_unaligned_load64(const uu64 *p) {
+ __msan_retval_tls[0] = *(uu64 *)MEM_TO_SHADOW((uptr)p);
+ if (__msan_get_track_origins())
+ __msan_retval_origin_tls = *(uu32 *)MEM_TO_ORIGIN((uptr)p);
+ return *p;
+}
+void __sanitizer_unaligned_store16(uu16 *p, u16 x) {
+ *(uu16 *)MEM_TO_SHADOW((uptr)p) = __msan_param_tls[1];
+ if (__msan_get_track_origins())
+ *(uu32 *)MEM_TO_ORIGIN((uptr)p) = __msan_param_origin_tls[1];
+ *p = x;
+}
+void __sanitizer_unaligned_store32(uu32 *p, u32 x) {
+ *(uu32 *)MEM_TO_SHADOW((uptr)p) = __msan_param_tls[1];
+ if (__msan_get_track_origins())
+ *(uu32 *)MEM_TO_ORIGIN((uptr)p) = __msan_param_origin_tls[1];
+ *p = x;
+}
+void __sanitizer_unaligned_store64(uu64 *p, u64 x) {
+ *(uu64 *)MEM_TO_SHADOW((uptr)p) = __msan_param_tls[1];
+ if (__msan_get_track_origins())
+ *(uu32 *)MEM_TO_ORIGIN((uptr)p) = __msan_param_origin_tls[1];
+ *p = x;
+}
+
#if !SANITIZER_SUPPORTS_WEAK_HOOKS
extern "C" {
-SANITIZER_WEAK_ATTRIBUTE SANITIZER_INTERFACE_ATTRIBUTE
+SANITIZER_INTERFACE_ATTRIBUTE SANITIZER_WEAK_ATTRIBUTE
const char* __msan_default_options() { return ""; }
} // extern "C"
#endif