summaryrefslogtreecommitdiff
path: root/lib/msan/msan.cc
diff options
context:
space:
mode:
authorEvgeniy Stepanov <eugeni.stepanov@gmail.com>2014-05-21 09:02:13 +0000
committerEvgeniy Stepanov <eugeni.stepanov@gmail.com>2014-05-21 09:02:13 +0000
commit6f365cc753d8150ae694357281e4775ac6e365cf (patch)
tree9e5c94cfc525292635964f034f96dbbc255cefe2 /lib/msan/msan.cc
parent72a4588166670e397a15c4a97529c849dcb11b3f (diff)
[msan] Chained origins re-design.
Generalize StackDepot and create a new specialized instance of it to efficiently (i.e. without duplicating stack trace data) store the origin history tree. This reduces memory usage for chained origins roughly by an order of magnitude. Most importantly, this new design allows us to put two limits on stored history data (exposed in MSAN_OPTIONS) that help avoid exponential growth in used memory on certain workloads. See comments in lib/msan/msan_origin.h for more details. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@209284 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/msan/msan.cc')
-rw-r--r--lib/msan/msan.cc75
1 files changed, 57 insertions, 18 deletions
diff --git a/lib/msan/msan.cc b/lib/msan/msan.cc
index 62f582aaa..308be461b 100644
--- a/lib/msan/msan.cc
+++ b/lib/msan/msan.cc
@@ -13,6 +13,8 @@
//===----------------------------------------------------------------------===//
#include "msan.h"
+#include "msan_chained_origin_depot.h"
+#include "msan_origin.h"
#include "msan_thread.h"
#include "sanitizer_common/sanitizer_atomic.h"
#include "sanitizer_common/sanitizer_common.h"
@@ -117,6 +119,28 @@ static void ParseFlagsFromString(Flags *f, const char *str) {
Printf("Exit code not in [0, 128) range: %d\n", f->exit_code);
Die();
}
+ ParseFlag(str, &f->origin_history_size, "origin_history_size", "");
+ if (f->origin_history_size < 0 ||
+ f->origin_history_size > Origin::kMaxDepth) {
+ Printf(
+ "Origin history size invalid: %d. Must be 0 (unlimited) or in [1, %d] "
+ "range.\n",
+ f->origin_history_size, Origin::kMaxDepth);
+ Die();
+ }
+ ParseFlag(str, &f->origin_history_per_stack_limit,
+ "origin_history_per_stack_limit", "");
+ // Limiting to kStackDepotMaxUseCount / 2 to avoid overflow in
+ // StackDepotHandle::inc_use_count_unsafe.
+ if (f->origin_history_per_stack_limit < 0 ||
+ f->origin_history_per_stack_limit > kStackDepotMaxUseCount / 2) {
+ Printf(
+ "Origin per-stack limit invalid: %d. Must be 0 (unlimited) or in [1, "
+ "%d] range.\n",
+ f->origin_history_per_stack_limit, kStackDepotMaxUseCount / 2);
+ Die();
+ }
+
ParseFlag(str, &f->report_umrs, "report_umrs", "");
ParseFlag(str, &f->wrap_signals, "wrap_signals", "");
@@ -143,6 +167,8 @@ static void InitializeFlags(Flags *f, const char *options) {
f->poison_in_malloc = true;
f->poison_in_free = true;
f->exit_code = 77;
+ f->origin_history_size = Origin::kMaxDepth;
+ f->origin_history_per_stack_limit = 20000;
f->report_umrs = true;
f->wrap_signals = true;
f->halt_on_error = !&__msan_keep_going;
@@ -230,9 +256,7 @@ void ScopedThreadLocalStateBackup::Restore() {
void UnpoisonThreadLocalState() {
}
-const char *GetOriginDescrIfStack(u32 id, uptr *pc) {
- if ((id >> 31) == 0) return 0;
- id &= (1U << 31) - 1;
+const char *GetStackOriginDescr(u32 id, uptr *pc) {
CHECK_LT(id, kNumStackOriginDescrs);
if (pc) *pc = StackOriginPC[id];
return StackOriginDescr[id];
@@ -242,10 +266,30 @@ u32 ChainOrigin(u32 id, StackTrace *stack) {
MsanThread *t = GetCurrentThread();
if (t && t->InSignalHandler())
return id;
- uptr idx = Min(stack->size, kStackTraceMax - 1);
- stack->trace[idx] = TRACE_MAKE_CHAINED(id);
- u32 new_id = StackDepotPut(stack->trace, idx + 1);
- return new_id;
+
+ Origin o(id);
+ int depth = o.depth();
+ // 0 means unlimited depth.
+ if (flags()->origin_history_size > 0 && depth > 0) {
+ if (depth >= flags()->origin_history_size) {
+ return id;
+ } else {
+ ++depth;
+ }
+ }
+
+ StackDepotHandle h = StackDepotPut_WithHandle(stack->trace, stack->size);
+ if (!h.valid()) return id;
+ int use_count = h.use_count();
+ if (use_count > flags()->origin_history_per_stack_limit)
+ return id;
+
+ u32 chained_id;
+ bool inserted = ChainedOriginDepotPut(h.id(), o.id(), &chained_id);
+
+ if (inserted) h.inc_use_count_unsafe();
+
+ return Origin(chained_id, depth).raw_id();
}
} // namespace __msan
@@ -514,16 +558,15 @@ void __msan_set_alloca_origin4(void *a, uptr size, const char *descr, uptr pc) {
bool print = false; // internal_strstr(descr + 4, "AllocaTOTest") != 0;
u32 id = *id_ptr;
if (id == first_timer) {
- id = atomic_fetch_add(&NumStackOriginDescrs,
- 1, memory_order_relaxed);
+ u32 idx = atomic_fetch_add(&NumStackOriginDescrs, 1, memory_order_relaxed);
+ CHECK_LT(idx, kNumStackOriginDescrs);
+ StackOriginDescr[idx] = descr + 4;
+ StackOriginPC[idx] = pc;
+ ChainedOriginDepotPut(idx, Origin::kStackRoot, &id);
*id_ptr = id;
- CHECK_LT(id, kNumStackOriginDescrs);
- StackOriginDescr[id] = descr + 4;
- StackOriginPC[id] = pc;
if (print)
- Printf("First time: id=%d %s %p \n", id, descr + 4, pc);
+ Printf("First time: idx=%d id=%d %s %p \n", idx, id, descr + 4, pc);
}
- id |= 1U << 31;
if (print)
Printf("__msan_set_alloca_origin: descr=%s id=%x\n", descr + 4, id);
__msan_set_origin(a, size, id);
@@ -536,10 +579,6 @@ u32 __msan_chain_origin(u32 id) {
return ChainOrigin(id, &stack);
}
-const char *__msan_get_origin_descr_if_stack(u32 id) {
- return GetOriginDescrIfStack(id, 0);
-}
-
u32 __msan_get_origin(const void *a) {
if (!__msan_get_track_origins()) return 0;
uptr x = (uptr)a;