diff --git a/compiler-rt/lib/asan/asan_interceptors.cpp b/compiler-rt/lib/asan/asan_interceptors.cpp --- a/compiler-rt/lib/asan/asan_interceptors.cpp +++ b/compiler-rt/lib/asan/asan_interceptors.cpp @@ -253,6 +253,14 @@ PoisonShadow(bottom, ssize, 0); } +INTERCEPTOR(int, getcontext, struct ucontext_t *ucp) { + // API does not requires to have ucp clean, and sets only part of fields. We + // use ucp->uc_stack to unpoison new stack. We prefer to have zeroes then + // uninitialized bytes. + ResetContextStack(ucp); + return REAL(getcontext)(ucp); +} + INTERCEPTOR(int, swapcontext, struct ucontext_t *oucp, struct ucontext_t *ucp) { static bool reported_warning = false; @@ -266,6 +274,10 @@ uptr stack, ssize; ReadContextStack(ucp, &stack, &ssize); ClearShadowMemoryForContextStack(stack, ssize); + + // See getcontext interceptor. + ResetContextStack(oucp); + # if __has_attribute(__indirect_return__) && \ (defined(__x86_64__) || defined(__i386__)) int (*real_swapcontext)(struct ucontext_t *, struct ucontext_t *) @@ -643,6 +655,7 @@ ASAN_INTERCEPT_FUNC(longjmp); #if ASAN_INTERCEPT_SWAPCONTEXT + ASAN_INTERCEPT_FUNC(getcontext); ASAN_INTERCEPT_FUNC(swapcontext); #endif #if ASAN_INTERCEPT__LONGJMP diff --git a/compiler-rt/lib/asan/asan_internal.h b/compiler-rt/lib/asan/asan_internal.h --- a/compiler-rt/lib/asan/asan_internal.h +++ b/compiler-rt/lib/asan/asan_internal.h @@ -106,6 +106,7 @@ void AsanOnDeadlySignal(int, void *siginfo, void *context); void ReadContextStack(void *context, uptr *stack, uptr *ssize); +void ResetContextStack(void *context); void StopInitOrderChecking(); // Wrapper for TLS/TSD. diff --git a/compiler-rt/lib/asan/asan_linux.cpp b/compiler-rt/lib/asan/asan_linux.cpp --- a/compiler-rt/lib/asan/asan_linux.cpp +++ b/compiler-rt/lib/asan/asan_linux.cpp @@ -214,11 +214,19 @@ *stack = (uptr)ucp->uc_stack.ss_sp; *ssize = ucp->uc_stack.ss_size; } -#else + +void ResetContextStack(void *context) { + ucontext_t *ucp = (ucontext_t *)context; + ucp->uc_stack.ss_sp = nullptr; + ucp->uc_stack.ss_size = 0; +} +# else void ReadContextStack(void *context, uptr *stack, uptr *ssize) { UNIMPLEMENTED(); } -#endif + +void ResetContextStack(void *context) { UNIMPLEMENTED(); } +# endif void *AsanDlSymNext(const char *sym) { return dlsym(RTLD_NEXT, sym); diff --git a/compiler-rt/lib/asan/asan_mac.cpp b/compiler-rt/lib/asan/asan_mac.cpp --- a/compiler-rt/lib/asan/asan_mac.cpp +++ b/compiler-rt/lib/asan/asan_mac.cpp @@ -99,6 +99,8 @@ UNIMPLEMENTED(); } +void ResetContextStack(void *context) { UNIMPLEMENTED(); } + // Support for the following functions from libdispatch on Mac OS: // dispatch_async_f() // dispatch_async() diff --git a/compiler-rt/lib/asan/asan_win.cpp b/compiler-rt/lib/asan/asan_win.cpp --- a/compiler-rt/lib/asan/asan_win.cpp +++ b/compiler-rt/lib/asan/asan_win.cpp @@ -267,6 +267,8 @@ UNIMPLEMENTED(); } +void ResetContextStack(void *context) { UNIMPLEMENTED(); } + void AsanOnDeadlySignal(int, void *siginfo, void *context) { UNIMPLEMENTED(); } bool PlatformUnpoisonStacks() { return false; } diff --git a/compiler-rt/test/asan/TestCases/Linux/swapcontext_test.cpp b/compiler-rt/test/asan/TestCases/Linux/swapcontext_test.cpp --- a/compiler-rt/test/asan/TestCases/Linux/swapcontext_test.cpp +++ b/compiler-rt/test/asan/TestCases/Linux/swapcontext_test.cpp @@ -9,6 +9,8 @@ // Android and musl do not support swapcontext. // REQUIRES: x86-target-arch && glibc-2.27 +#include +#include #include #include #include @@ -33,6 +35,7 @@ } void Child(int mode) { + assert(orig_context.uc_stack.ss_size == 0); char x[32] = {0}; // Stack gets poisoned. printf("Child: %p\n", x); ThrowAndCatch(); // Simulate __asan_handle_no_return(). @@ -50,13 +53,16 @@ int Run(int arg, int mode, char *child_stack) { printf("Child stack: %p\n", child_stack); // Setup child context. + memset(&child_context, 0xff, sizeof(child_context)); getcontext(&child_context); + assert(child_context.uc_stack.ss_size == 0); child_context.uc_stack.ss_sp = child_stack; child_context.uc_stack.ss_size = kStackSize / 2; if (mode == 0) { child_context.uc_link = &orig_context; } makecontext(&child_context, (void (*)())Child, 1, mode); + memset(&orig_context, 0xff, sizeof(orig_context)); if (swapcontext(&orig_context, &child_context) < 0) { perror("swapcontext"); return 0;