From 5a5655b790cde8b643b59bfd9beb38bf92ad554a Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Fri, 1 Jul 2022 12:38:49 +0200 Subject: [PATCH] lib/curl/Adapter: catch and postpone exceptions in WriteFunction() This fixes a std::terminate() crash in the CURL storage plugin when PropfindOperation::OnHeaders() throws an exception after receiving a non-207 status. Closes https://github.com/MusicPlayerDaemon/MPD/issues/1559 --- NEWS | 2 ++ src/lib/curl/Adapter.cxx | 13 +++++++++++++ src/lib/curl/Adapter.hxx | 7 +++++++ src/lib/curl/Handler.hxx | 8 +++++++- 4 files changed, 29 insertions(+), 1 deletion(-) diff --git a/NEWS b/NEWS index fa0477a1a..acdca2550 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,6 @@ ver 0.23.8 (not yet released) +* storage + - curl: fix crash if web server does not understand WebDAV ver 0.23.7 (2022/05/09) * database diff --git a/src/lib/curl/Adapter.cxx b/src/lib/curl/Adapter.cxx index e41587bff..d2e69ed2b 100644 --- a/src/lib/curl/Adapter.cxx +++ b/src/lib/curl/Adapter.cxx @@ -85,6 +85,12 @@ CurlResponseHandlerAdapter::FinishBody() void CurlResponseHandlerAdapter::Done(CURLcode result) noexcept { + if (postponed_error) { + state = State::CLOSED; + handler.OnError(std::move(postponed_error)); + return; + } + try { if (result != CURLE_OK) { StripRight(error_buffer); @@ -172,6 +178,13 @@ CurlResponseHandlerAdapter::DataReceived(const void *ptr, return received_size; } catch (CurlResponseHandler::Pause) { return CURL_WRITEFUNC_PAUSE; + } catch (...) { + /* from inside this libCURL callback function, we + can't do much, so we remember the exception to be + handled later by Done(), and return 0, causing the + response to be aborted with CURLE_WRITE_ERROR */ + postponed_error = std::current_exception(); + return 0; } } diff --git a/src/lib/curl/Adapter.hxx b/src/lib/curl/Adapter.hxx index fc4c946c3..e47e19921 100644 --- a/src/lib/curl/Adapter.hxx +++ b/src/lib/curl/Adapter.hxx @@ -34,6 +34,7 @@ #include #include +#include struct StringView; class CurlEasy; @@ -46,6 +47,12 @@ class CurlResponseHandlerAdapter { Curl::Headers headers; + /** + * An exception caught from within the WriteFunction() which + * will later be handled by Done(). + */ + std::exception_ptr postponed_error; + /** error message provided by libcurl */ char error_buffer[CURL_ERROR_SIZE]; diff --git a/src/lib/curl/Handler.hxx b/src/lib/curl/Handler.hxx index c0bdeced1..c1fd4ac42 100644 --- a/src/lib/curl/Handler.hxx +++ b/src/lib/curl/Handler.hxx @@ -50,13 +50,19 @@ public: /** * Status line and headers have been received. + * + * Exceptions thrown by this method will be passed to + * OnError(), aborting the request. */ virtual void OnHeaders(unsigned status, Curl::Headers &&headers) = 0; /** * Response body data has been received. * - * May throw #Pause (but nothing else). + * May throw #Pause. + * + * Other exceptions thrown by this method will be passed to + * OnError(), aborting the request. */ virtual void OnData(ConstBuffer data) = 0;