[compiler-rt] r190603 - [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.
Kostya Serebryany
kcc at google.com
Thu Sep 12 06:25:29 PDT 2013
Author: kcc
Date: Thu Sep 12 08:25:29 2013
New Revision: 190603
URL: http://llvm.org/viewvc/llvm-project?rev=190603&view=rev
Log:
[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.
Added:
compiler-rt/trunk/lib/asan/lit_tests/TestCases/uar_and_exceptions.cc
Modified:
compiler-rt/trunk/lib/asan/asan_fake_stack.cc
compiler-rt/trunk/lib/asan/asan_fake_stack.h
compiler-rt/trunk/lib/asan/asan_rtl.cc
Modified: compiler-rt/trunk/lib/asan/asan_fake_stack.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_fake_stack.cc?rev=190603&r1=190602&r2=190603&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_fake_stack.cc (original)
+++ compiler-rt/trunk/lib/asan/asan_fake_stack.cc Thu Sep 12 08:25:29 2013
@@ -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 stac
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 p
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;
Modified: compiler-rt/trunk/lib/asan/asan_fake_stack.h
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_fake_stack.h?rev=190603&r1=190602&r2=190603&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_fake_stack.h (original)
+++ compiler-rt/trunk/lib/asan/asan_fake_stack.h Thu Sep 12 08:25:29 2013
@@ -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
Modified: compiler-rt/trunk/lib/asan/asan_rtl.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/asan_rtl.cc?rev=190603&r1=190602&r2=190603&view=diff
==============================================================================
--- compiler-rt/trunk/lib/asan/asan_rtl.cc (original)
+++ compiler-rt/trunk/lib/asan/asan_rtl.cc Thu Sep 12 08:25:29 2013
@@ -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)) {
Added: compiler-rt/trunk/lib/asan/lit_tests/TestCases/uar_and_exceptions.cc
URL: http://llvm.org/viewvc/llvm-project/compiler-rt/trunk/lib/asan/lit_tests/TestCases/uar_and_exceptions.cc?rev=190603&view=auto
==============================================================================
--- compiler-rt/trunk/lib/asan/lit_tests/TestCases/uar_and_exceptions.cc (added)
+++ compiler-rt/trunk/lib/asan/lit_tests/TestCases/uar_and_exceptions.cc Thu Sep 12 08:25:29 2013
@@ -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;
+}
More information about the llvm-commits
mailing list