<body><table border="1" cellspacing="0" cellpadding="8">
title="NEW - ASan produces false positive when using std::rethrow_exception"
<td>ASan produces false positive when using std::rethrow_exception
<pre>Created <span class=""><a href="attachment.cgi?id=18177" name="attach_18177" title="Reproducer and patch">attachment 18177</a> <a href="attachment.cgi?id=18177&action=edit" title="Reproducer and patch">[details]</a></span>
Reproducer and patch
We've encountered a false positive stack-buffer-*flow report by the Address
Sanitizer when building with gcc4.8.5. The problem remains in the latest
version of gcc. We can provide a fix, although we're unsure about the
portability and inclusion of a system header file. The issue in ASan is a
missing interceptor for std::rethrow_exception (it does NOT call __cxa_throw).
Since we do not know how to intercept this C++11 function in the ASan source
code, we intercept _Unwind_RaiseException instead.
The false positive occurs only under very specific circumstances (see below)
and is caused by not unpoisoning the stack before unwinding due to an
Detailed explanation of our findings:
The false positive occurs when using a component Alice which has not been
compiled with ASan, and Alice calls std::rethrow_exception. That function is
marked as [[noreturn]]. If Alice was compiled with ASan, the sanitizer would
place a call to __asan_handle_no_return right before the call to
std::rethrow_exception. But since Alice is built without ASan and there is no
interceptor for std::rethrow_exception, the stack remains poisoned during and
after the unwinding caused by std::rethrow_exception.
If the component Bob using the stack after or during unwinding is also built
without ASan, the stack will not be re-poisoned; the old poison remains. If Bob
uses non-inlined calls to memcpy, memset etc. which are intercepted by ASan,
then the sanitizer will check against the old poison from before the stack
unwinding. For us, this happened during unwinding in libgcc.so's
Initially, we tried to intercept std::rethrow_exception directly. However, its
argument is a std::exception_ptr, which is a non-trivial C++11 type. It is
unclear to us where to get this type from within the address sanitizer source
code. Instead, we intercept _Unwind_RaiseException. This returns a
_Unwind_Reason_Code, which is an enumeration defined in the unwind.h header.
We're probably doing something wrong by just including "unwind.h" which might
come from the host environment.
Since we've only looked at Linux so far, other platforms might need a different
solution for the false positive.
To reproduce the issue, we use two translation units. The TU containing the
main function builds up and poisons the stack, whereas the other TU is Alice
and calls std::rethrow_exception. libgcc.so built without optimizations serves
as Bob. The _Unwind_Resume function in libgcc.so (when compiled without
optimizations) contains calls to memset and memcpy. The reproducing program is
set up in such a way that the mem* functions in _Unwind_Resume use stack space
which has been poisoned before the stack unwinding. Since
std::make_exception_ptr in certain implementations uses try/catch, it cannot be
used directly before std::rethrow_exception: it would unpoison the stack and
therefore the false positive would not occur.
The reproducer requires a special build mode and consists of two TUs, therefore
we do not know how to introduce it into the sanitizer test suites. It should be
possible to further simplify it, by using a custom Bob which manually calls
memcpy/memset (instead of using a non-optimized libgcc.so). This custom Bob
would have to use new stack variables after the exception was caught and stack
unwinding is finished.</pre>
<span>You are receiving this mail because:</span>
<li>You are on the CC list for the bug.</li>