From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 48) id A38A43833031; Thu, 3 Jun 2021 20:03:06 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org A38A43833031 From: "l.v.merzljak at gmail dot com" To: gcc-bugs@gcc.gnu.org Subject: [Bug c++/100897] New: Symmetric transfer does not prevent stack-overflow for C++20 coroutines Date: Thu, 03 Jun 2021 20:03:06 +0000 X-Bugzilla-Reason: CC X-Bugzilla-Type: new X-Bugzilla-Watch-Reason: None X-Bugzilla-Product: gcc X-Bugzilla-Component: c++ X-Bugzilla-Version: 11.1.0 X-Bugzilla-Keywords: X-Bugzilla-Severity: normal X-Bugzilla-Who: l.v.merzljak at gmail dot com X-Bugzilla-Status: UNCONFIRMED X-Bugzilla-Resolution: X-Bugzilla-Priority: P3 X-Bugzilla-Assigned-To: unassigned at gcc dot gnu.org X-Bugzilla-Target-Milestone: --- X-Bugzilla-Flags: X-Bugzilla-Changed-Fields: bug_id short_desc product version bug_status bug_severity priority component assigned_to reporter target_milestone Message-ID: Content-Type: text/plain; charset="UTF-8" Content-Transfer-Encoding: quoted-printable X-Bugzilla-URL: http://gcc.gnu.org/bugzilla/ Auto-Submitted: auto-generated MIME-Version: 1.0 X-BeenThere: gcc-bugs@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-bugs mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 03 Jun 2021 20:03:06 -0000 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=3D100897 Bug ID: 100897 Summary: Symmetric transfer does not prevent stack-overflow for C++20 coroutines Product: gcc Version: 11.1.0 Status: UNCONFIRMED Severity: normal Priority: P3 Component: c++ Assignee: unassigned at gcc dot gnu.org Reporter: l.v.merzljak at gmail dot com Target Milestone: --- Although the following code uses symmetric transfer, it crashes due to a stack-overflow. The crash is also reproducible when using the task<> type of the cppcoro library. The crash does not occur when using clang. ``` // main.cc #include #include class Task { public: struct promise_type { Task get_return_object() { return Handle::from_promise(*this); } struct FinalAwaitable { bool await_ready() const noexcept { return false; } // Use symmetric transfer. Resuming coro.promise().m_continuation sho= uld // not require extra stack space std::coroutine_handle<> await_suspend( std::coroutine_handle coro) noexcept { if (coro.promise().m_continuation) { return coro.promise().m_continuation; } else { // The top-level task started from within main() does not have a // continuation. This will give control back to the main function. return std::noop_coroutine(); } } void await_resume() noexcept {} }; std::suspend_always initial_suspend() noexcept { return {}; } FinalAwaitable final_suspend() noexcept { return {}; } void unhandled_exception() noexcept { std::terminate(); } void set_continuation(std::coroutine_handle<> continuation) noexcept { m_continuation =3D continuation; } void return_void() noexcept {} private: std::coroutine_handle<> m_continuation; }; using Handle =3D std::coroutine_handle; Task(Handle coroutine) : m_coroutine(coroutine) {} ~Task() { if (m_coroutine) { m_coroutine.destroy(); } } void start() noexcept { m_coroutine.resume(); } auto operator co_await() const noexcept { return Awaitable{m_coroutine}; } private: struct Awaitable { Handle m_coroutine; Awaitable(Handle coroutine) noexcept : m_coroutine(coroutine) {} bool await_ready() const noexcept { return false; } // Use symmetric transfer. Resuming m_coroutine should not require extra // stack space std::coroutine_handle<> await_suspend( std::coroutine_handle<> awaitingCoroutine) noexcept { m_coroutine.promise().set_continuation(awaitingCoroutine); return m_coroutine; } void await_resume() {} }; Handle m_coroutine; }; Task inner() { co_return; } Task outer() { // Use large number of iterations to trigger stack-overflow for (int i =3D 0; i !=3D 50000000; ++i) { co_await inner(); } } int main() { auto task =3D outer(); task.start(); } ``` I compile the code with `g++-11 main.cc -std=3Dc++20 -O3 -fsanitize=3Daddre= ss`. Here is the output: ``` $ ./a.out AddressSanitizer:DEADLYSIGNAL =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D= =3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D =3D=3D21002=3D=3DERROR: AddressSanitizer: stack-overflow on address 0x7fffc= 666dff8 (pc 0x7f6ec2dfa16d bp 0x7fffc666e870 sp 0x7fffc666e000 T0) #0 0x7f6ec2dfa16d in __sanitizer::BufferedStackTrace::UnwindImpl(unsign= ed long, unsigned long, void*, bool, unsigned int) ../../../../src/libsanitizer/asan/asan_stack.cpp:57 #1 0x7f6ec2df00eb in __sanitizer::BufferedStackTrace::Unwind(unsigned l= ong, unsigned long, void*, bool, unsigned int) ../../../../src/libsanitizer/sanitizer_common/sanitizer_stacktrace.h:122 #2 0x7f6ec2df00eb in operator delete(void*) ../../../../src/libsanitizer/asan/asan_new_delete.cpp:160 #3 0x560193552e57 in _Z5innerv.destroy(inner()::_Z5innerv.frame*) (/home/leonard/Desktop/hiwi/async_io_uring/stack-overflow/a.out+0x1e57) #4 0x560193553b30 in _Z5outerv.actor(outer()::_Z5outerv.frame*) (/home/leonard/Desktop/hiwi/async_io_uring/stack-overflow/a.out+0x2b30) #5 0x560193552bbb in _Z5innerv.actor(inner()::_Z5innerv.frame*) (/home/leonard/Desktop/hiwi/async_io_uring/stack-overflow/a.out+0x1bbb) ... ```=