https://gcc.gnu.org/bugzilla/show_bug.cgi?id=102217

            Bug ID: 102217
           Summary: co_awaiting a temporary produced by ternary operator
                    crashes (double-free)
           Product: gcc
           Version: 11.2.0
            Status: UNCONFIRMED
          Severity: normal
          Priority: P3
         Component: c++
          Assignee: unassigned at gcc dot gnu.org
          Reporter: max at duempel dot org
  Target Milestone: ---

Created attachment 51414
  --> https://gcc.gnu.org/bugzilla/attachment.cgi?id=51414&action=edit
Crashing demo program

When awaiting a coroutine task which is a temporary evaluated with the ternary
operator, GCC emits faulty code that destructs the task twice, leading to a
crash due to double free / use-after-free.

Tested with "gcc version 10.2.1 20210110 (Debian 10.2.1-6)" and "gcc version
11.2.0 (Debian 11.2.0-1)"

clang ("Debian clang version 11.0.1-2") is fine.

This crash bug can be worked around by assigning the result of the ternary
operator to a local variable first, and then co_await that variable.

In my demo program, the UniqueHandle destructor gets called twice with the same
contained pointer value; however, the UniqueHandle instance that gets
destructed first was never constructed.

ASan output with GCC 11:

==2==ERROR: AddressSanitizer: heap-use-after-free on address 0x606000000028 at
pc 0x5573042b18a9 bp 0x7ffdde510f60 sp 0x7ffdde510f58
READ of size 8 at 0x606000000028 thread T0
    #0 0x5573042b18a8 in Co::UniqueHandle<Co::promise<Foo, Co::Task<Foo> >
>::~UniqueHandle() (/home/max/dl/a.out+0x28a8)
    #1 0x5573042b1284 in FooC(FooC(bool)::_Z4FooCb.frame*) [clone .actor]
(/home/max/dl/a.out+0x2284)
    #2 0x5573042b0582 in FooA(FooA()::_Z4FooAv.frame*) [clone .actor]
(/home/max/dl/a.out+0x1582)
    #3 0x5573042b13a1 in FooC(FooC(bool)::_Z4FooCb.frame*) [clone .actor]
(/home/max/dl/a.out+0x23a1)
    #4 0x5573042b00dd in main (/home/max/dl/a.out+0x10dd)
    #5 0x7fa1f4ffbe39 in __libc_start_main
(/lib/x86_64-linux-gnu/libc.so.6+0x27e39)
    #6 0x5573042b01e9 in _start (/home/max/dl/a.out+0x11e9)

0x606000000028 is located 8 bytes inside of 64-byte region
[0x606000000020,0x606000000060)
freed by thread T0 here:
    #0 0x7fa1f55b6957 in operator delete(void*)
../../../../src/libsanitizer/asan/asan_new_delete.cpp:160
    #1 0x5573042b05b7 in FooA(FooA()::_Z4FooAv.frame*) [clone .actor]
(/home/max/dl/a.out+0x15b7)

previously allocated by thread T0 here:
    #0 0x7fa1f55b5f57 in operator new(unsigned long)
../../../../src/libsanitizer/asan/asan_new_delete.cpp:99
    #1 0x5573042b0af5 in FooA() (/home/max/dl/a.out+0x1af5)

Reply via email to