[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:
parent
993849490e
commit
1ee681305f
|
@ -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
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
Loading…
Reference in New Issue