From f403d8dbce91a4196a67570cef3259a16999e3c2 Mon Sep 17 00:00:00 2001 From: Kostya Serebryany Date: Thu, 6 Feb 2014 06:56:22 +0000 Subject: [asan] introduce two functions that will allow implementations of C++ garbage colection to work with asan's fake stack git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@200908 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/sanitizer/asan_interface.h | 18 ++++++++ lib/asan/asan_fake_stack.cc | 32 ++++++++++++-- lib/asan/asan_fake_stack.h | 6 ++- .../TestCases/Linux/interface_symbols_linux.c | 2 + lib/asan/lit_tests/TestCases/gc-test.cc | 49 ++++++++++++++++++++++ 5 files changed, 102 insertions(+), 5 deletions(-) create mode 100644 lib/asan/lit_tests/TestCases/gc-test.cc diff --git a/include/sanitizer/asan_interface.h b/include/sanitizer/asan_interface.h index a943cfe34..045ca954b 100644 --- a/include/sanitizer/asan_interface.h +++ b/include/sanitizer/asan_interface.h @@ -122,6 +122,24 @@ extern "C" { // deallocation of "ptr". void __asan_malloc_hook(void *ptr, size_t size); void __asan_free_hook(void *ptr); + + // The following 2 functions facilitate garbage collection in presence of + // asan's fake stack. + + // Returns an opaque handler to be used later in __asan_addr_is_in_fake_stack. + // Returns NULL if the current thread does not have a fake stack. + void *__asan_get_current_fake_stack(); + + // If fake_stack is non-NULL and addr belongs to a fake frame in + // fake_stack, returns the address on real stack that corresponds to + // the fake frame and sets beg/end to the boundaries of this fake frame. + // Otherwise returns NULL and does not touch beg/end. + // If beg/end are NULL, they are not touched. + // This function may be called from a thread other than the owner of + // fake_stack, but the owner thread need to be alive. + void *__asan_addr_is_in_fake_stack(void *fake_stack, void *addr, void **beg, + void **end); + #ifdef __cplusplus } // extern "C" #endif diff --git a/lib/asan/asan_fake_stack.cc b/lib/asan/asan_fake_stack.cc index 4d830f4af..c7f13c731 100644 --- a/lib/asan/asan_fake_stack.cc +++ b/lib/asan/asan_fake_stack.cc @@ -104,7 +104,7 @@ FakeFrame *FakeStack::Allocate(uptr stack_size_log, uptr class_id, return 0; // We are out of fake stack. } -uptr FakeStack::AddrIsInFakeStack(uptr ptr) { +uptr FakeStack::AddrIsInFakeStack(uptr ptr, uptr *frame_beg, uptr *frame_end) { uptr stack_size_log = this->stack_size_log(); uptr beg = reinterpret_cast(GetFrame(stack_size_log, 0, 0)); uptr end = reinterpret_cast(this) + RequiredSize(stack_size_log); @@ -114,7 +114,10 @@ uptr FakeStack::AddrIsInFakeStack(uptr ptr) { CHECK_LE(base, ptr); CHECK_LT(ptr, base + (1UL << stack_size_log)); uptr pos = (ptr - base) >> (kMinStackFrameSizeLog + class_id); - return base + pos * BytesInSizeClass(class_id); + uptr res = base + pos * BytesInSizeClass(class_id); + *frame_end = res + BytesInSizeClass(class_id); + *frame_beg = res + sizeof(FakeFrame); + return res; } void FakeStack::HandleNoReturn() { @@ -208,14 +211,15 @@ ALWAYS_INLINE void OnFree(uptr ptr, uptr class_id, uptr size, uptr real_stack) { } // namespace __asan // ---------------------- Interface ---------------- {{{1 +using namespace __asan; #define DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(class_id) \ extern "C" SANITIZER_INTERFACE_ATTRIBUTE uptr \ __asan_stack_malloc_##class_id(uptr size, uptr real_stack) { \ - return __asan::OnMalloc(class_id, size, real_stack); \ + return OnMalloc(class_id, size, real_stack); \ } \ extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __asan_stack_free_##class_id( \ uptr ptr, uptr size, uptr real_stack) { \ - __asan::OnFree(ptr, class_id, size, real_stack); \ + OnFree(ptr, class_id, size, real_stack); \ } DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(0) @@ -229,3 +233,23 @@ DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(7) DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(8) DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(9) DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(10) +extern "C" { +SANITIZER_INTERFACE_ATTRIBUTE +void *__asan_get_current_fake_stack() { return GetFakeStackFast(); } + +SANITIZER_INTERFACE_ATTRIBUTE +void *__asan_addr_is_in_fake_stack(void *fake_stack, void *addr, void **beg, + void **end) { + FakeStack *fs = reinterpret_cast(fake_stack); + if (!fs) return 0; + uptr frame_beg, frame_end; + FakeFrame *frame = reinterpret_cast(fs->AddrIsInFakeStack( + reinterpret_cast(addr), &frame_beg, &frame_end)); + if (!frame) return 0; + if (frame->magic != kCurrentStackFrameMagic) + return 0; + if (beg) *beg = reinterpret_cast(frame_beg); + if (end) *end = reinterpret_cast(frame_end); + return reinterpret_cast(frame->real_stack); +} +} // extern "C" diff --git a/lib/asan/asan_fake_stack.h b/lib/asan/asan_fake_stack.h index 726fb094a..3b1d9eb3b 100644 --- a/lib/asan/asan_fake_stack.h +++ b/lib/asan/asan_fake_stack.h @@ -129,7 +129,11 @@ class FakeStack { void PoisonAll(u8 magic); // Return the beginning of the FakeFrame or 0 if the address is not ours. - uptr AddrIsInFakeStack(uptr addr); + uptr AddrIsInFakeStack(uptr addr, uptr *frame_beg, uptr *frame_end); + USED uptr AddrIsInFakeStack(uptr addr) { + uptr t1, t2; + return AddrIsInFakeStack(addr, &t1, &t2); + } // Number of bytes in a fake frame of this size class. static uptr BytesInSizeClass(uptr class_id) { diff --git a/lib/asan/lit_tests/TestCases/Linux/interface_symbols_linux.c b/lib/asan/lit_tests/TestCases/Linux/interface_symbols_linux.c index 26e5083ff..ea33084ad 100644 --- a/lib/asan/lit_tests/TestCases/Linux/interface_symbols_linux.c +++ b/lib/asan/lit_tests/TestCases/Linux/interface_symbols_linux.c @@ -25,6 +25,8 @@ // RUN: echo __asan_report_store16 >> %t.interface // RUN: echo __asan_report_load_n >> %t.interface // RUN: echo __asan_report_store_n >> %t.interface +// RUN: echo __asan_get_current_fake_stack >> %t.interface +// RUN: echo __asan_addr_is_in_fake_stack >> %t.interface // RUN: cat %t.interface | sort -u | diff %t.symbols - // FIXME: nm -D on powerpc somewhy shows ASan interface symbols residing diff --git a/lib/asan/lit_tests/TestCases/gc-test.cc b/lib/asan/lit_tests/TestCases/gc-test.cc new file mode 100644 index 000000000..984146481 --- /dev/null +++ b/lib/asan/lit_tests/TestCases/gc-test.cc @@ -0,0 +1,49 @@ +// RUN: %clangxx_asan %s -o %t +// RUN: ASAN_OPTIONS=detect_stack_use_after_return=1 %t 2>&1 | FileCheck %s --check-prefix=CHECK1 +// RUN: ASAN_OPTIONS=detect_stack_use_after_return=0 %t 2>&1 | FileCheck %s --check-prefix=CHECK0 + +#include +#include +#include +#include + +static const int kNumThreads = 2; + +void *Thread(void *unused) { + void *fake_stack = __asan_get_current_fake_stack(); + char var[15]; + if (fake_stack) { + fprintf(stderr, "fake stack found: %p; var: %p\n", fake_stack, var); + // CHECK1: fake stack found + // CHECK1: fake stack found + void *beg, *end; + void *real_stack = + __asan_addr_is_in_fake_stack(fake_stack, &var[0], &beg, &end); + assert(real_stack); + assert((char*)beg <= (char*)&var[0]); + assert((char*)end > (char*)&var[0]); + for (int i = -32; i < 15; i++) { + void *beg1, *end1; + char *ptr = &var[0] + i; + void *real_stack1 = + __asan_addr_is_in_fake_stack(fake_stack, ptr, &beg1, &end1); + assert(real_stack == real_stack1); + assert(beg == beg1); + assert(end == end1); + } + } else { + fprintf(stderr, "no fake stack\n"); + // CHECK0: no fake stack + // CHECK0: no fake stack + } + return NULL; +} + +int main(int argc, char **argv) { + pthread_t t[kNumThreads]; + for (int i = 0; i < kNumThreads; i++) + pthread_create(&t[i], 0, Thread, 0); + for (int i = 0; i < kNumThreads; i++) + pthread_join(t[i], 0); + return 0; +} -- cgit v1.2.3