input/thread: move code to Stop()

Fixes crash due to "pure virtual method called" in the "mms" input
plugin.  Closes #253
This commit is contained in:
Max Kellermann 2018-03-15 19:23:31 +01:00
parent e8099f01b5
commit 73013a3c04
4 changed files with 30 additions and 3 deletions

2
NEWS
View File

@ -2,7 +2,7 @@ ver 0.20.19 (not yet released)
* protocol * protocol
- validate absolute seek time, reject negative values - validate absolute seek time, reject negative values
* input * input
- mms: fix lockup bug - mms: fix lockup bug and a crash bug
* macOS: fix crash bug * macOS: fix crash bug
ver 0.20.18 (2018/02/24) ver 0.20.18 (2018/02/24)

View File

@ -26,8 +26,12 @@
#include <assert.h> #include <assert.h>
#include <string.h> #include <string.h>
ThreadInputStream::~ThreadInputStream() void
ThreadInputStream::Stop() noexcept
{ {
if (!thread.IsDefined())
return;
{ {
const std::lock_guard<Mutex> lock(mutex); const std::lock_guard<Mutex> lock(mutex);
close = true; close = true;
@ -42,6 +46,7 @@ ThreadInputStream::~ThreadInputStream()
buffer->Clear(); buffer->Clear();
HugeFree(buffer->Write().data, buffer_size); HugeFree(buffer->Write().data, buffer_size);
delete buffer; delete buffer;
buffer = nullptr;
} }
} }

View File

@ -27,6 +27,7 @@
#include <exception> #include <exception>
#include <assert.h>
#include <stdint.h> #include <stdint.h>
template<typename T> class CircularBuffer; template<typename T> class CircularBuffer;
@ -39,6 +40,11 @@ template<typename T> class CircularBuffer;
* manages the thread and the buffer. * manages the thread and the buffer.
* *
* This works only for "streams": unknown length, no seeking, no tags. * This works only for "streams": unknown length, no seeking, no tags.
*
* The implementation must call Stop() before its destruction
* completes. This cannot be done in ~ThreadInputStream() because at
* this point, the class has been morphed back to #ThreadInputStream
* and the still-running thread will crash due to pure method call.
*/ */
class ThreadInputStream : public InputStream { class ThreadInputStream : public InputStream {
const char *const plugin; const char *const plugin;
@ -76,7 +82,13 @@ public:
thread(BIND_THIS_METHOD(ThreadFunc)), thread(BIND_THIS_METHOD(ThreadFunc)),
buffer_size(_buffer_size) {} buffer_size(_buffer_size) {}
virtual ~ThreadInputStream(); #ifndef NDEBUG
~ThreadInputStream() override {
/* Stop() must have been called already */
assert(!thread.IsDefined());
assert(buffer == nullptr);
}
#endif
/** /**
* Initialize the object and start the thread. * Initialize the object and start the thread.
@ -90,6 +102,12 @@ public:
size_t Read(void *ptr, size_t size) override final; size_t Read(void *ptr, size_t size) override final;
protected: protected:
/**
* Stop the thread and free the buffer. This must be called
* before destruction of this object completes.
*/
void Stop() noexcept;
void SetMimeType(const char *_mime) { void SetMimeType(const char *_mime) {
assert(thread.IsInside()); assert(thread.IsInside());

View File

@ -39,6 +39,10 @@ public:
MMS_BUFFER_SIZE) { MMS_BUFFER_SIZE) {
} }
~MmsInputStream() noexcept override {
Stop();
}
protected: protected:
virtual void Open() override; virtual void Open() override;
virtual size_t ThreadRead(void *ptr, size_t size) override; virtual size_t ThreadRead(void *ptr, size_t size) override;