From d01fb6730a7ac889f104490022c9dbb581e45db2 Mon Sep 17 00:00:00 2001
From: Max Kellermann <max@musicpd.org>
Date: Mon, 23 Dec 2019 13:37:58 +0100
Subject: [PATCH] storage/curl: move start call out of the constructor

This can cause request completion in the I/O thread before this
constructor returns, leaving the object in an abstract state, causing
a crash due to pure virtual method call.  We should not start the
request until this object is fully constructed.

Closes https://github.com/MusicPlayerDaemon/MPD/issues/665
---
 NEWS                                | 2 ++
 src/storage/plugins/CurlStorage.cxx | 5 +++++
 2 files changed, 7 insertions(+)

diff --git a/NEWS b/NEWS
index 7804e0d20..3e48c90e6 100644
--- a/NEWS
+++ b/NEWS
@@ -1,6 +1,8 @@
 ver 0.21.18 (not yet released)
 * output
   - alsa: fix hang bug with ALSA "null" outputs
+* storage
+  - curl: fix crash bug
 * reduce unnecessary CPU wakeups
 
 ver 0.21.17 (2019/12/16)
diff --git a/src/storage/plugins/CurlStorage.cxx b/src/storage/plugins/CurlStorage.cxx
index b4e73ba0a..5417dae29 100644
--- a/src/storage/plugins/CurlStorage.cxx
+++ b/src/storage/plugins/CurlStorage.cxx
@@ -109,7 +109,9 @@ public:
 			     BIND_THIS_METHOD(OnDeferredStart)),
 		 request(curl, uri, *this) {
 		// TODO: use CurlInputStream's configuration
+	}
 
+	void DeferStart() noexcept {
 		/* start the transfer inside the IOThread */
 		defer_start.Schedule();
 	}
@@ -283,6 +285,7 @@ public:
 	}
 
 	using BlockingHttpRequest::GetEasy;
+	using BlockingHttpRequest::DeferStart;
 	using BlockingHttpRequest::Wait;
 
 protected:
@@ -430,6 +433,7 @@ public:
 	}
 
 	const StorageFileInfo &Perform() {
+		DeferStart();
 		Wait();
 		return info;
 	}
@@ -481,6 +485,7 @@ public:
 		 base_path(UriPathOrSlash(uri)) {}
 
 	std::unique_ptr<StorageDirectoryReader> Perform() {
+		DeferStart();
 		Wait();
 		return ToReader();
 	}