[asan] introduce two functions that will allow implementations of C++ garbage colection to work with asan's fake stack

llvm-svn: 200908
This commit is contained in:
Kostya Serebryany 2014-02-06 06:56:22 +00:00
parent 993849490e
commit 1ee681305f
5 changed files with 102 additions and 5 deletions

View File

@ -122,6 +122,24 @@ extern "C" {
// deallocation of "ptr". // deallocation of "ptr".
void __asan_malloc_hook(void *ptr, size_t size); void __asan_malloc_hook(void *ptr, size_t size);
void __asan_free_hook(void *ptr); 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 #ifdef __cplusplus
} // extern "C" } // extern "C"
#endif #endif

View File

@ -104,7 +104,7 @@ FakeFrame *FakeStack::Allocate(uptr stack_size_log, uptr class_id,
return 0; // We are out of fake stack. 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 stack_size_log = this->stack_size_log();
uptr beg = reinterpret_cast<uptr>(GetFrame(stack_size_log, 0, 0)); uptr beg = reinterpret_cast<uptr>(GetFrame(stack_size_log, 0, 0));
uptr end = reinterpret_cast<uptr>(this) + RequiredSize(stack_size_log); uptr end = reinterpret_cast<uptr>(this) + RequiredSize(stack_size_log);
@ -114,7 +114,10 @@ uptr FakeStack::AddrIsInFakeStack(uptr ptr) {
CHECK_LE(base, ptr); CHECK_LE(base, ptr);
CHECK_LT(ptr, base + (1UL << stack_size_log)); CHECK_LT(ptr, base + (1UL << stack_size_log));
uptr pos = (ptr - base) >> (kMinStackFrameSizeLog + class_id); 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() { void FakeStack::HandleNoReturn() {
@ -208,14 +211,15 @@ ALWAYS_INLINE void OnFree(uptr ptr, uptr class_id, uptr size, uptr real_stack) {
} // namespace __asan } // namespace __asan
// ---------------------- Interface ---------------- {{{1 // ---------------------- Interface ---------------- {{{1
using namespace __asan;
#define DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(class_id) \ #define DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(class_id) \
extern "C" SANITIZER_INTERFACE_ATTRIBUTE uptr \ extern "C" SANITIZER_INTERFACE_ATTRIBUTE uptr \
__asan_stack_malloc_##class_id(uptr size, uptr real_stack) { \ __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( \ extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __asan_stack_free_##class_id( \
uptr ptr, uptr size, uptr real_stack) { \ 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) 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(8)
DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(9) DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(9)
DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(10) 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"

View File

@ -129,7 +129,11 @@ class FakeStack {
void PoisonAll(u8 magic); void PoisonAll(u8 magic);
// Return the beginning of the FakeFrame or 0 if the address is not ours. // 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. // Number of bytes in a fake frame of this size class.
static uptr BytesInSizeClass(uptr class_id) { static uptr BytesInSizeClass(uptr class_id) {

View File

@ -25,6 +25,8 @@
// RUN: echo __asan_report_store16 >> %t.interface // RUN: echo __asan_report_store16 >> %t.interface
// RUN: echo __asan_report_load_n >> %t.interface // RUN: echo __asan_report_load_n >> %t.interface
// RUN: echo __asan_report_store_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 - // RUN: cat %t.interface | sort -u | diff %t.symbols -
// FIXME: nm -D on powerpc somewhy shows ASan interface symbols residing // FIXME: nm -D on powerpc somewhy shows ASan interface symbols residing

View File

@ -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;
}