Skip to content

Commit 1ee6813

Browse files
committedFeb 6, 2014
[asan] introduce two functions that will allow implementations of C++ garbage colection to work with asan's fake stack
llvm-svn: 200908
1 parent 9938494 commit 1ee6813

File tree

5 files changed

+102
-5
lines changed

5 files changed

+102
-5
lines changed
 

‎compiler-rt/include/sanitizer/asan_interface.h

+18
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,24 @@ extern "C" {
122122
// deallocation of "ptr".
123123
void __asan_malloc_hook(void *ptr, size_t size);
124124
void __asan_free_hook(void *ptr);
125+
126+
// The following 2 functions facilitate garbage collection in presence of
127+
// asan's fake stack.
128+
129+
// Returns an opaque handler to be used later in __asan_addr_is_in_fake_stack.
130+
// Returns NULL if the current thread does not have a fake stack.
131+
void *__asan_get_current_fake_stack();
132+
133+
// If fake_stack is non-NULL and addr belongs to a fake frame in
134+
// fake_stack, returns the address on real stack that corresponds to
135+
// the fake frame and sets beg/end to the boundaries of this fake frame.
136+
// Otherwise returns NULL and does not touch beg/end.
137+
// If beg/end are NULL, they are not touched.
138+
// This function may be called from a thread other than the owner of
139+
// fake_stack, but the owner thread need to be alive.
140+
void *__asan_addr_is_in_fake_stack(void *fake_stack, void *addr, void **beg,
141+
void **end);
142+
125143
#ifdef __cplusplus
126144
} // extern "C"
127145
#endif

‎compiler-rt/lib/asan/asan_fake_stack.cc

+28-4
Original file line numberDiff line numberDiff line change
@@ -104,7 +104,7 @@ FakeFrame *FakeStack::Allocate(uptr stack_size_log, uptr class_id,
104104
return 0; // We are out of fake stack.
105105
}
106106

107-
uptr FakeStack::AddrIsInFakeStack(uptr ptr) {
107+
uptr FakeStack::AddrIsInFakeStack(uptr ptr, uptr *frame_beg, uptr *frame_end) {
108108
uptr stack_size_log = this->stack_size_log();
109109
uptr beg = reinterpret_cast<uptr>(GetFrame(stack_size_log, 0, 0));
110110
uptr end = reinterpret_cast<uptr>(this) + RequiredSize(stack_size_log);
@@ -114,7 +114,10 @@ uptr FakeStack::AddrIsInFakeStack(uptr ptr) {
114114
CHECK_LE(base, ptr);
115115
CHECK_LT(ptr, base + (1UL << stack_size_log));
116116
uptr pos = (ptr - base) >> (kMinStackFrameSizeLog + class_id);
117-
return base + pos * BytesInSizeClass(class_id);
117+
uptr res = base + pos * BytesInSizeClass(class_id);
118+
*frame_end = res + BytesInSizeClass(class_id);
119+
*frame_beg = res + sizeof(FakeFrame);
120+
return res;
118121
}
119122

120123
void FakeStack::HandleNoReturn() {
@@ -208,14 +211,15 @@ ALWAYS_INLINE void OnFree(uptr ptr, uptr class_id, uptr size, uptr real_stack) {
208211
} // namespace __asan
209212

210213
// ---------------------- Interface ---------------- {{{1
214+
using namespace __asan;
211215
#define DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(class_id) \
212216
extern "C" SANITIZER_INTERFACE_ATTRIBUTE uptr \
213217
__asan_stack_malloc_##class_id(uptr size, uptr real_stack) { \
214-
return __asan::OnMalloc(class_id, size, real_stack); \
218+
return OnMalloc(class_id, size, real_stack); \
215219
} \
216220
extern "C" SANITIZER_INTERFACE_ATTRIBUTE void __asan_stack_free_##class_id( \
217221
uptr ptr, uptr size, uptr real_stack) { \
218-
__asan::OnFree(ptr, class_id, size, real_stack); \
222+
OnFree(ptr, class_id, size, real_stack); \
219223
}
220224

221225
DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(0)
@@ -229,3 +233,23 @@ DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(7)
229233
DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(8)
230234
DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(9)
231235
DEFINE_STACK_MALLOC_FREE_WITH_CLASS_ID(10)
236+
extern "C" {
237+
SANITIZER_INTERFACE_ATTRIBUTE
238+
void *__asan_get_current_fake_stack() { return GetFakeStackFast(); }
239+
240+
SANITIZER_INTERFACE_ATTRIBUTE
241+
void *__asan_addr_is_in_fake_stack(void *fake_stack, void *addr, void **beg,
242+
void **end) {
243+
FakeStack *fs = reinterpret_cast<FakeStack*>(fake_stack);
244+
if (!fs) return 0;
245+
uptr frame_beg, frame_end;
246+
FakeFrame *frame = reinterpret_cast<FakeFrame *>(fs->AddrIsInFakeStack(
247+
reinterpret_cast<uptr>(addr), &frame_beg, &frame_end));
248+
if (!frame) return 0;
249+
if (frame->magic != kCurrentStackFrameMagic)
250+
return 0;
251+
if (beg) *beg = reinterpret_cast<void*>(frame_beg);
252+
if (end) *end = reinterpret_cast<void*>(frame_end);
253+
return reinterpret_cast<void*>(frame->real_stack);
254+
}
255+
} // extern "C"

‎compiler-rt/lib/asan/asan_fake_stack.h

+5-1
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,11 @@ class FakeStack {
129129
void PoisonAll(u8 magic);
130130

131131
// Return the beginning of the FakeFrame or 0 if the address is not ours.
132-
uptr AddrIsInFakeStack(uptr addr);
132+
uptr AddrIsInFakeStack(uptr addr, uptr *frame_beg, uptr *frame_end);
133+
USED uptr AddrIsInFakeStack(uptr addr) {
134+
uptr t1, t2;
135+
return AddrIsInFakeStack(addr, &t1, &t2);
136+
}
133137

134138
// Number of bytes in a fake frame of this size class.
135139
static uptr BytesInSizeClass(uptr class_id) {

‎compiler-rt/lib/asan/lit_tests/TestCases/Linux/interface_symbols_linux.c

+2
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@
2525
// RUN: echo __asan_report_store16 >> %t.interface
2626
// RUN: echo __asan_report_load_n >> %t.interface
2727
// RUN: echo __asan_report_store_n >> %t.interface
28+
// RUN: echo __asan_get_current_fake_stack >> %t.interface
29+
// RUN: echo __asan_addr_is_in_fake_stack >> %t.interface
2830
// RUN: cat %t.interface | sort -u | diff %t.symbols -
2931

3032
// FIXME: nm -D on powerpc somewhy shows ASan interface symbols residing
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// RUN: %clangxx_asan %s -o %t
2+
// RUN: ASAN_OPTIONS=detect_stack_use_after_return=1 %t 2>&1 | FileCheck %s --check-prefix=CHECK1
3+
// RUN: ASAN_OPTIONS=detect_stack_use_after_return=0 %t 2>&1 | FileCheck %s --check-prefix=CHECK0
4+
5+
#include <assert.h>
6+
#include <stdio.h>
7+
#include <pthread.h>
8+
#include <sanitizer/asan_interface.h>
9+
10+
static const int kNumThreads = 2;
11+
12+
void *Thread(void *unused) {
13+
void *fake_stack = __asan_get_current_fake_stack();
14+
char var[15];
15+
if (fake_stack) {
16+
fprintf(stderr, "fake stack found: %p; var: %p\n", fake_stack, var);
17+
// CHECK1: fake stack found
18+
// CHECK1: fake stack found
19+
void *beg, *end;
20+
void *real_stack =
21+
__asan_addr_is_in_fake_stack(fake_stack, &var[0], &beg, &end);
22+
assert(real_stack);
23+
assert((char*)beg <= (char*)&var[0]);
24+
assert((char*)end > (char*)&var[0]);
25+
for (int i = -32; i < 15; i++) {
26+
void *beg1, *end1;
27+
char *ptr = &var[0] + i;
28+
void *real_stack1 =
29+
__asan_addr_is_in_fake_stack(fake_stack, ptr, &beg1, &end1);
30+
assert(real_stack == real_stack1);
31+
assert(beg == beg1);
32+
assert(end == end1);
33+
}
34+
} else {
35+
fprintf(stderr, "no fake stack\n");
36+
// CHECK0: no fake stack
37+
// CHECK0: no fake stack
38+
}
39+
return NULL;
40+
}
41+
42+
int main(int argc, char **argv) {
43+
pthread_t t[kNumThreads];
44+
for (int i = 0; i < kNumThreads; i++)
45+
pthread_create(&t[i], 0, Thread, 0);
46+
for (int i = 0; i < kNumThreads; i++)
47+
pthread_join(t[i], 0);
48+
return 0;
49+
}

0 commit comments

Comments
 (0)
Please sign in to comment.