Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 18 additions & 3 deletions lib/http/HttpClient_Curl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -173,11 +173,26 @@ class CurlHttpOperation {
*/
virtual ~CurlHttpOperation()
{
// Given the request has not been aborted we should wait for completion here
// This guarantees the lifetime of this request.
// libstdc++'s std::future<>::~future implicitly joins the async
// thread via call_once during destruction. If this destructor runs
// ON that same async thread (e.g. the user callback released the
// last shared_ptr from inside the lambda), the implicit self-join
// throws std::system_error("Resource deadlock avoided"), and because
// the throw originates inside a noexcept destructor it aborts the
// process. try/catch around `result` cannot rescue it.
//
// Defuse by moving the future onto a detached helper thread that is
// by definition NOT the async thread, so its implicit join succeeds
// immediately (the work has already finished, which is the only way
// we could be running this destructor on the async thread). On the
// common path (destructed from the caller thread) this just spawns
// a no-op helper that exits in microseconds.
if (result.valid())
{
result.wait();
std::thread([f = std::move(result)]() mutable {
// f goes out of scope here. ~future joins on this new
// thread (!= the original async thread), so no EDEADLK.
}).detach();
}
DispatchEvent(OnDestroy);
res = CURLE_OK;
Expand Down
Loading