summaryrefslogtreecommitdiffstats
path: root/compiler-rt
diff options
context:
space:
mode:
authorKostya Serebryany <kcc@google.com>2013-09-12 13:25:29 +0000
committerKostya Serebryany <kcc@google.com>2013-09-12 13:25:29 +0000
commit627ea6391e7ed1be37cf284e39e10de9862df4c1 (patch)
tree355a89fa16c5ea899fed7d770565d53f88a5a76f /compiler-rt
parentdb6144e3e33ceef876be04805cf3333289830ce0 (diff)
downloadbcm5719-llvm-627ea6391e7ed1be37cf284e39e10de9862df4c1.tar.gz
bcm5719-llvm-627ea6391e7ed1be37cf284e39e10de9862df4c1.zip
[asan] add a test for use-after-return and exceptions and fix it. Not 100% sure this is a complete fix, will keep looking for harder cases.
llvm-svn: 190603
Diffstat (limited to 'compiler-rt')
-rw-r--r--compiler-rt/lib/asan/asan_fake_stack.cc32
-rw-r--r--compiler-rt/lib/asan/asan_fake_stack.h8
-rw-r--r--compiler-rt/lib/asan/asan_rtl.cc2
-rw-r--r--compiler-rt/lib/asan/lit_tests/TestCases/uar_and_exceptions.cc27
4 files changed, 68 insertions, 1 deletions
diff --git a/compiler-rt/lib/asan/asan_fake_stack.cc b/compiler-rt/lib/asan/asan_fake_stack.cc
index 69044f00c00..078f9042eee 100644
--- a/compiler-rt/lib/asan/asan_fake_stack.cc
+++ b/compiler-rt/lib/asan/asan_fake_stack.cc
@@ -25,6 +25,8 @@ void FakeStack::PoisonAll(u8 magic) {
FakeFrame *FakeStack::Allocate(uptr stack_size_log, uptr class_id,
uptr real_stack) {
CHECK_LT(class_id, kNumberOfSizeClasses);
+ if (needs_gc_)
+ GC(real_stack);
uptr &hint_position = hint_position_[class_id];
const int num_iter = NumberOfFrames(stack_size_log, class_id);
u8 *flags = GetFlags(stack_size_log, class_id);
@@ -38,6 +40,7 @@ FakeFrame *FakeStack::Allocate(uptr stack_size_log, uptr class_id,
GetFrame(stack_size_log, class_id, pos));
res->real_stack = real_stack;
res->class_id = class_id;
+ allocated_from_size_class_mask_ |= 1UL << class_id;
return res;
}
}
@@ -70,6 +73,35 @@ uptr FakeStack::AddrIsInFakeStack(uptr ptr) {
return base + pos * BytesInSizeClass(class_id);
}
+void FakeStack::HandleNoReturn() {
+ needs_gc_ = true;
+}
+
+// When throw, longjmp or some such happens we don't call OnFree() and
+// as the result may leak one or more fake frames, but the good news is that
+// we are notified about all such events by HandleNoReturn().
+// If we recently had such no-return event we need to collect garbage frames.
+// We do it based on their 'real_stack' values -- everything that is lower
+// than the current real_stack is garbage.
+NOINLINE void FakeStack::GC(uptr real_stack) {
+ uptr collected = 0;
+ for (uptr class_id = 0; class_id < kNumberOfSizeClasses; class_id++) {
+ if (!(allocated_from_size_class_mask_ & (1UL << class_id))) continue;
+ u8 *flags = GetFlags(stack_size_log(), class_id);
+ for (uptr i = 0, n = NumberOfFrames(stack_size_log(), class_id); i < n;
+ i++) {
+ if (flags[i] == 0) continue; // not allocated.
+ FakeFrame *ff = reinterpret_cast<FakeFrame *>(
+ GetFrame(stack_size_log(), class_id, i));
+ if (ff->real_stack < real_stack) {
+ flags[i] = 0;
+ collected++;
+ }
+ }
+ }
+ needs_gc_ = false;
+}
+
ALWAYS_INLINE uptr OnMalloc(uptr class_id, uptr size, uptr real_stack) {
AsanThread *t = GetCurrentThread();
if (!t) return real_stack;
diff --git a/compiler-rt/lib/asan/asan_fake_stack.h b/compiler-rt/lib/asan/asan_fake_stack.h
index 493e7e521d8..f5f49064de6 100644
--- a/compiler-rt/lib/asan/asan_fake_stack.h
+++ b/compiler-rt/lib/asan/asan_fake_stack.h
@@ -153,15 +153,21 @@ class FakeStack {
uptr stack_size_log() const { return stack_size_log_; }
+ void HandleNoReturn();
+ void GC(uptr real_stack);
+
private:
FakeStack() { }
- static const uptr kFlagsOffset = 4096; // There is were flags begin.
+ static const uptr kFlagsOffset = 4096; // This is were the flags begin.
// Must match the number of uses of DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID
COMPILER_CHECK(kNumberOfSizeClasses == 11);
static const uptr kMaxStackMallocSize = 1 << kMaxStackFrameSizeLog;
uptr hint_position_[kNumberOfSizeClasses];
uptr stack_size_log_;
+ // a bit is set if something was allocated from the corresponding size class.
+ uptr allocated_from_size_class_mask_;
+ bool needs_gc_;
};
} // namespace __asan
diff --git a/compiler-rt/lib/asan/asan_rtl.cc b/compiler-rt/lib/asan/asan_rtl.cc
index 80bd5918013..a77f9de6ba4 100644
--- a/compiler-rt/lib/asan/asan_rtl.cc
+++ b/compiler-rt/lib/asan/asan_rtl.cc
@@ -427,6 +427,8 @@ void NOINLINE __asan_handle_no_return() {
return;
}
PoisonShadow(bottom, top - bottom, 0);
+ if (curr_thread->has_fake_stack())
+ curr_thread->fake_stack()->HandleNoReturn();
}
void NOINLINE __asan_set_death_callback(void (*callback)(void)) {
diff --git a/compiler-rt/lib/asan/lit_tests/TestCases/uar_and_exceptions.cc b/compiler-rt/lib/asan/lit_tests/TestCases/uar_and_exceptions.cc
new file mode 100644
index 00000000000..f1639f08443
--- /dev/null
+++ b/compiler-rt/lib/asan/lit_tests/TestCases/uar_and_exceptions.cc
@@ -0,0 +1,27 @@
+// Test that use-after-return works with exceptions.
+// RUN: %clangxx_asan -fsanitize=use-after-return -O0 %s -o %t && %t
+
+#include <stdio.h>
+
+volatile char *g;
+
+void Func(int depth) {
+ char frame[100];
+ g = &frame[0];
+ if (depth)
+ Func(depth - 1);
+ else
+ throw 1;
+}
+
+int main(int argc, char **argv) {
+ for (int i = 0; i < 4000; i++) {
+ try {
+ Func(argc * 100);
+ } catch(...) {
+ }
+ if ((i % 1000) == 0)
+ fprintf(stderr, "done [%d]\n", i);
+ }
+ return 0;
+}
OpenPOWER on IntegriCloud