summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKostya Serebryany <kcc@google.com>2014-02-06 06:56:22 +0000
committerKostya Serebryany <kcc@google.com>2014-02-06 06:56:22 +0000
commitf403d8dbce91a4196a67570cef3259a16999e3c2 (patch)
tree6eff94249b0744cfae15bf8a9fc36e527dc05311
parente2cdf0bda99368cfb311d89719ef39b7197f30a7 (diff)
[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
-rw-r--r--include/sanitizer/asan_interface.h18
-rw-r--r--lib/asan/asan_fake_stack.cc32
-rw-r--r--lib/asan/asan_fake_stack.h6
-rw-r--r--lib/asan/lit_tests/TestCases/Linux/interface_symbols_linux.c2
-rw-r--r--lib/asan/lit_tests/TestCases/gc-test.cc49
5 files changed, 102 insertions, 5 deletions
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<uptr>(GetFrame(stack_size_log, 0, 0));
uptr end = reinterpret_cast<uptr>(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<FakeStack*>(fake_stack);
+ if (!fs) return 0;
+ uptr frame_beg, frame_end;
+ FakeFrame *frame = reinterpret_cast<FakeFrame *>(fs->AddrIsInFakeStack(
+ reinterpret_cast<uptr>(addr), &frame_beg, &frame_end));
+ if (!frame) return 0;
+ if (frame->magic != kCurrentStackFrameMagic)
+ return 0;
+ if (beg) *beg = reinterpret_cast<void*>(frame_beg);
+ if (end) *end = reinterpret_cast<void*>(frame_end);
+ return reinterpret_cast<void*>(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 <assert.h>
+#include <stdio.h>
+#include <pthread.h>
+#include <sanitizer/asan_interface.h>
+
+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;
+}