I was playing with C++20 coroutine support and I found an addressing error that I can't explain nor fix. It happens on Xcode 12.5, shipping with Apple Clang 12.0.5, when enabling Address Sanitizer feature. Here is a minimum reproducible example:
#include <experimental/coroutine>
struct ReturnType
{
struct promise_type
{
std::experimental::suspend_never initial_suspend() { return {}; }
std::experimental::suspend_always final_suspend() noexcept { return {}; }
ReturnType get_return_object() { return {}; }
void unhandled_exception() { throw; }
void return_void() {}
};
};
ReturnType my_coroutine()
{
throw 0;
co_return;
}
int main() {
try {
my_coroutine();
} catch (...) {
}
return 0;
}
The coroutine merely throws a dummy int which is rethrown in promise_type::unhandled_exception. No local variables, no manual allocations, but still Address Sanitizer reports the following error:
=================================================================
==3204==ERROR: AddressSanitizer: heap-use-after-free on address 0x60600004bb18 at pc 0x000100001ea9 bp 0x7ffeefbff0f0 sp 0x7ffeefbff0e8
READ of size 8 at 0x60600004bb18 thread T0
#0 0x100001ea8 in my_coroutine() main.cpp:15
#1 0x1000024e3 in main main.cpp:24
#2 0x7fff204ed620 in start+0x0 (libdyld.dylib:x86_64+0x15620)
0x60600004bb18 is located 24 bytes inside of 64-byte region [0x60600004bb00,0x60600004bb40)
freed by thread T0 here:
#0 0x1001810bd in wrap__ZdlPv+0x7d (libclang_rt.asan_osx_dynamic.dylib:x86_64h+0x550bd)
#1 0x100001e76 in my_coroutine() main.cpp:15
#2 0x1000024e3 in main main.cpp:24
#3 0x7fff204ed620 in start+0x0 (libdyld.dylib:x86_64+0x15620)
previously allocated by thread T0 here:
#0 0x100180c9d in wrap__Znwm+0x7d (libclang_rt.asan_osx_dynamic.dylib:x86_64h+0x54c9d)
#1 0x10000153d in my_coroutine() main.cpp:15
#2 0x1000024e3 in main main.cpp:24
#3 0x7fff204ed620 in start+0x0 (libdyld.dylib:x86_64+0x15620)
SUMMARY: AddressSanitizer: heap-use-after-free main.cpp:15 in my_coroutine()
Shadow bytes around the buggy address:
0x1c0c00009710: 00 00 00 00 fa fa fa fa 00 00 00 00 00 00 00 00
0x1c0c00009720: fa fa fa fa 00 00 00 00 00 00 00 00 fa fa fa fa
0x1c0c00009730: 00 00 00 00 00 00 00 00 fa fa fa fa 00 00 00 00
0x1c0c00009740: 00 00 00 00 fa fa fa fa 00 00 00 00 00 00 00 00
0x1c0c00009750: fa fa fa fa 00 00 00 00 00 00 00 00 fa fa fa fa
=>0x1c0c00009760: fd fd fd[fd]fd fd fd fd fa fa fa fa fa fa fa fa
0x1c0c00009770: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x1c0c00009780: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x1c0c00009790: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x1c0c000097a0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
0x1c0c000097b0: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa
Shadow byte legend (one shadow byte represents 8 application bytes):
Addressable: 00
Partially addressable: 01 02 03 04 05 06 07
Heap left redzone: fa
Freed heap region: fd
Stack left redzone: f1
Stack mid redzone: f2
Stack right redzone: f3
Stack after return: f5
Stack use after scope: f8
Global redzone: f9
Global init order: f6
Poisoned by user: f7
Container overflow: fc
Array cookie: ac
Intra object redzone: bb
ASan internal: fe
Left alloca redzone: ca
Right alloca redzone: cb
Shadow gap: cc
What is going on? Maybe a problem with the experimental coroutine support of Apple Clang 12?