-
Notifications
You must be signed in to change notification settings - Fork 1.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Segfault when exception thrown from within stackful coroutine #1110
Comments
Hi. I maked some changed with the same example program, like as: #include <iostream>
#include <boost/asio/io_context.hpp>
#include <boost/asio/spawn.hpp>
int main()
{
boost::asio::io_context ioctx;
boost::asio::spawn(
ioctx,
[](boost::asio::yield_context yield)
{
std::cout << "Hello World!" << std::endl;
});
ioctx.run();
return 0;
} When I build and run this program with boost_1_80_0, it would throw forced_unwind exception from: |
@AsonWon Please triple-backticks to properly render your code with indentation: https://docs.github.com/en/get-started/writing-on-github/working-with-advanced-formatting/creating-and-highlighting-code-blocks Even better, add the c++ tag next to the triple backticks as so: |
@ecorm Can you please try with the changes in this commit 13045b6 @AsonWon I cannot reproduce any problem with your test program. Are you getting an unhandled exception resulting in a crash? Or are you simply observing that there is a |
@chriskohlhoff I tried the same example program above modified to use standalone Asio, and it works with the commit you linked, using Boost 1.80 for the coroutine stuff:
Thanks! I hope Boost publishes a hotfix version before the next "major" version. Environment info: |
@AsonWon That's the debugger telling you an exception is being thrown. Is it being caught inside the library? It should be. If so, that's not a bug. |
@chriskohlhoff Your fix doesn't seem to work when defining I've tried this example: #define ASIO_DISABLE_BOOST_COROUTINE
#include <iostream>
#include <stdexcept>
#include <asio/detached.hpp>
#include <asio/io_context.hpp>
#include <asio/spawn.hpp>
//------------------------------------------------------------------------------
int main()
{
asio::io_context ioctx;
// auto work = asio::make_work_guard(ioctx);
asio::spawn(
ioctx,
[](asio::yield_context yield)
{
std::cout << "Before throw" << std::endl;
throw std::runtime_error("bad");
std::cout << "After throw" << std::endl;
},
asio::detached
);
try
{
std::cout << "Before ioctx.run()" << std::endl;
ioctx.run();
std::cout << "After ioctx.run()" << std::endl;
}
catch (const std::exception& e)
{
std::cout << "Caught std::exception: " << e.what() << std::endl;
}
catch (...)
{
std::cout << "Caught unknown exception" << std::endl;
}
return 0;
} The output is:
In other words, If I enable the
It seems as if the coroutine is simply discarded when an exception is thrown, and the |
Yep: #1111 (comment) Instead of |
Ah, yes, I see now that This now works for me (with your commit 13045b6) and matches the old behavior #define ASIO_DISABLE_BOOST_COROUTINE
#include <exception>
#include <iostream>
#include <stdexcept>
#include <asio/io_context.hpp>
#include <asio/spawn.hpp>
//------------------------------------------------------------------------------
struct propagating_t
{
void operator()(std::exception_ptr e) const
{
if (e) std::rethrow_exception(e);
}
};
const propagating_t propagating;
//------------------------------------------------------------------------------
int main()
{
asio::io_context ioctx;
asio::spawn(
ioctx,
[](asio::yield_context yield)
{
std::cout << "Before throw" << std::endl;
throw std::runtime_error("bad");
std::cout << "After throw" << std::endl;
},
propagating
);
try
{
ioctx.run();
}
catch (const std::exception& e)
{
std::cout << "Caught std::exception: " << e.what() << std::endl;
}
catch (...)
{
std::cout << "Caught unknown exception" << std::endl;
}
return 0;
} Output:
|
This is the new program that i want to avoid or catch this exception: #include <iostream>
#include <boost/asio/io_context.hpp>
#include <boost/asio/spawn.hpp>
int main()
{
boost::asio::io_context ioctx;
boost::asio::spawn(
ioctx,
[](boost::asio::yield_context yield)
{
std::cout << "Hello World!" << std::endl;
});
try
{
ioctx.run();
}
catch (const std::logic_error &e)
{
std::cout << "LogicError: " << e.what() << std::endl;
}
catch (const std::runtime_error &e)
{
std::cout << "RunError: " << e.what() << std::endl;
}
catch (const boost::coroutines::detail::forced_unwind &e)
{
//std::cout << "UnWindError: " << e.what() << std::endl;
std::cout << "UnWindError: " << std::endl;
}
catch (...)
{
std::cout << "OtherError: " << std::endl;
}
return 0;
} When I run it with boost_1_80_0, it doesn't seem to work with any catch conditions. My development environment: |
@AsonWon The |
@ecorm |
You can't disable the internal throwing of But yes, you can ignore I agree with you that the frequent internal throwing and catching of Stackful coroutines are expensive to spawn, because they each need their own stack. If your code is spawning them frequently, consider trying to reuse the same long-lived coroutine. Or use the traditional callback technique and save the state of your logic in class member variables. Or consider using C++20 coroutines which are stackless. The problem you describe is separate from the segfault problem I reported in this issue. Please create a new issue for it. |
@chriskohlhoff Am I correct to assume that the debugging ergonomics problem described by AsonWon is purely due to Boost.Context? If so, the issue should be reported in the Boost.Context repository. |
@ecorm Under normal conditions, the user's program will not generate this exception report in the output window, unless the user's program doesn't catch this exception, or the boost library doesn't catch this exception. It's not an question caught by Visual Studio, I made some attempt on Visual Studio, I cann't ignore this exception to do some settings by the VS exception filter. @chriskohlhoff How do you think about this? Should I reported this issue in boost::context? |
@chriskohlhoff |
@AsonWon can you please paste the output of you test program above when you run it outside of visual studio, at the command prompt.
…On Wed, Aug 24, 2022, at 9:45 PM, AsonWon wrote:
@chriskohlhoff <https://github.com/chriskohlhoff>
According to my test results, the forced_unwind exception being thrown
by boost::asio is not being caught inside the library, the caught code
may not be executed inside the library. I use boost_1_80_0-msvc-14.2-64.
—
Reply to this email directly, view it on GitHub
<#1110 (comment)>,
or unsubscribe
<https://github.com/notifications/unsubscribe-auth/AADQ5STBJ5S7QFNAYTBLN33V2YDL5ANCNFSM5667OL7Q>.
You are receiving this because you were mentioned.Message ID:
***@***.***>
|
@ecorm @chriskohlhoff #include <iostream>
#include <stdexcept>
int main(int argc, char *argv[])
{
throw std::runtime_error("bad");
return 0;
} The following screenshot is an uncaught exception that I throw myself. |
@AsonWon I'm glad you figured it out. Your findings has still brought up the problem of Boost.Context throwing (and catching) exceptions as part of its normal operations. This is a nuisance for those of us who use the GDB debugger to catch any thrown exception while troubleshooting problems in our own code. |
I've made a tentative change in 96e1a95 to allow the coroutine to run to completion if the user-supplied function has itself completed. This should eliminate the |
I confirm that GDB no longer breaks when set up to break on on any C++ exception thrown, using the following example: #include <iostream>
#include <memory>
#include <asio/detached.hpp>
#include <asio/io_context.hpp>
#include <asio/spawn.hpp>
//------------------------------------------------------------------------------
int main()
{
asio::io_context ioctx;
asio::spawn(
ioctx,
[](asio::yield_context yield)
{
std::cout << "Coroutine enter" << std::endl;
auto ptr = std::make_shared<int>(42);
std::cout << "Coroutine leave" << std::endl;
}
// , asio::detached
);
ioctx.run();
std::cout << "After ioctx.run()" << std::endl;
return 0;
} I've tried it with When using my original example that throws a I'll whip up another test program where the coroutine doesn't run to completion. |
Here's a test where the coroutine does not run to completion: #include <iostream>
#include <memory>
#include <asio/detached.hpp>
#include <asio/io_context.hpp>
#include <asio/spawn.hpp>
#include <asio/steady_timer.hpp>
//------------------------------------------------------------------------------
int main()
{
{
asio::io_context ioctx;
asio::steady_timer timer(ioctx);
int count = 0;
asio::spawn(
ioctx,
[&timer, &count](asio::yield_context yield)
{
std::cout << "Coroutine enter" << std::endl;
std::shared_ptr<int> ptr{
new int(42),
[](int* i)
{
std::cout << "ptr deleter" << std::endl;
delete i;
}};
timer.expires_from_now(std::chrono::milliseconds(1000));
timer.async_wait(yield);
std::cout << "Tick" << std::endl;
++count;
timer.expires_from_now(std::chrono::milliseconds(1000));
timer.async_wait(yield);
++count;
std::cout << "Coroutine leave" << std::endl;
}
#ifdef ASIO_DISABLE_BOOST_COROUTINE
, asio::detached
#endif
);
while (count == 0)
ioctx.poll();
std::cout << "Leaving scope" << std::endl;
}
std::cout << "Exiting main" << std::endl;
return 0;
} Output:
The forced coroutine stack unwinding occurs, as evidenced by With "break on C++ exceptions thrown" enabled in GDB, it breaks with the I get the same behavior with Everything seems to be working with 96e1a95, as far as I can tell. 👍 |
Hi! I faced with the same issue on Windows after upgrading to Boost v1.80.0, 13045b6 fixes the crash in my case so I hope it gets merged soon. |
As of Boost 1.80, throwing an exception within a stackful coroutine results in a segfault. In previous releases, the exception would be transported to
asio::io_context::run
and rethrown there.Example program reproducing the problem:
With Boost 1.80, the output is:
With GDB, it stops at some
ldmxcrx
instruction with no source-level debug information at all, including the stack trace. I'm using a release build of Boost.With Boost 1.79, the output is:
The text was updated successfully, but these errors were encountered: