aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--Makefile.am11
-rw-r--r--NEWS8
-rw-r--r--src/decoder/DecoderAPI.cxx4
-rw-r--r--src/decoder/DecoderInternal.cxx3
-rw-r--r--src/decoder/DecoderThread.cxx12
-rw-r--r--src/decoder/plugins/FfmpegDecoderPlugin.cxx13
-rw-r--r--src/protocol/ArgParser.cxx4
-rw-r--r--test/test_protocol.cxx60
9 files changed, 113 insertions, 3 deletions
diff --git a/.gitignore b/.gitignore
index 4e262ff2e..cf130ad92 100644
--- a/.gitignore
+++ b/.gitignore
@@ -64,6 +64,7 @@ tags
/test/tmp
/test/run_inotify
/test/test_queue_priority
+/test/test_protocol
/test/run_ntp_server
/test/run_resolver
/test/run_tcp_connect
diff --git a/Makefile.am b/Makefile.am
index 0e3b871e7..9e04def44 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1458,6 +1458,7 @@ C_TESTS = \
test/test_rewind \
test/test_mixramp \
test/test_pcm \
+ test/test_protocol \
test/test_queue_priority
if ENABLE_CURL
@@ -2035,6 +2036,16 @@ test_test_translate_song_LDADD = \
endif
+test_test_protocol_SOURCES = \
+ src/protocol/ArgParser.cxx \
+ test/test_protocol.cxx
+test_test_protocol_CPPFLAGS = $(AM_CPPFLAGS) $(CPPUNIT_CFLAGS) -DCPPUNIT_HAVE_RTTI=0
+test_test_protocol_CXXFLAGS = $(AM_CXXFLAGS) -Wno-error=deprecated-declarations
+test_test_protocol_LDADD = \
+ libsystem.a \
+ libutil.a \
+ $(CPPUNIT_LIBS)
+
test_test_queue_priority_SOURCES = \
src/queue/Queue.cxx \
src/DetachedSong.cxx \
diff --git a/NEWS b/NEWS
index 94fb234ca..0a68d3c80 100644
--- a/NEWS
+++ b/NEWS
@@ -69,6 +69,14 @@ ver 0.19 (not yet released)
* install systemd unit for socket activation
* Android port
+ver 0.18.14 (2014/09/11)
+* protocol
+ - fix range parser bug on certain 32 bit architectures
+* decoder
+ - audiofile: fix crash after seeking
+ - ffmpeg: fix crash with ffmpeg/libav version 11
+ - fix assertion failure after seeking
+
ver 0.18.13 (2014/08/31)
* protocol
- don't change song on "seekcur" in random mode
diff --git a/src/decoder/DecoderAPI.cxx b/src/decoder/DecoderAPI.cxx
index c3cbb3a21..4794d60e7 100644
--- a/src/decoder/DecoderAPI.cxx
+++ b/src/decoder/DecoderAPI.cxx
@@ -48,6 +48,7 @@ decoder_initialized(Decoder &decoder,
assert(dc.state == DecoderState::START);
assert(dc.pipe != nullptr);
+ assert(dc.pipe->IsEmpty());
assert(decoder.convert == nullptr);
assert(decoder.stream_tag == nullptr);
assert(decoder.decoder_tag == nullptr);
@@ -461,6 +462,9 @@ decoder_data(Decoder &decoder,
length == 0)
return cmd;
+ assert(!decoder.initial_seek_pending);
+ assert(!decoder.initial_seek_running);
+
/* send stream tags */
if (update_stream_tag(decoder, is)) {
diff --git a/src/decoder/DecoderInternal.cxx b/src/decoder/DecoderInternal.cxx
index 416a75b75..f35878682 100644
--- a/src/decoder/DecoderInternal.cxx
+++ b/src/decoder/DecoderInternal.cxx
@@ -85,6 +85,9 @@ Decoder::GetChunk()
void
Decoder::FlushChunk()
{
+ assert(!seeking);
+ assert(!initial_seek_running);
+ assert(!initial_seek_pending);
assert(chunk != nullptr);
if (chunk->IsEmpty())
diff --git a/src/decoder/DecoderThread.cxx b/src/decoder/DecoderThread.cxx
index 3f4f7c42e..b2b41b661 100644
--- a/src/decoder/DecoderThread.cxx
+++ b/src/decoder/DecoderThread.cxx
@@ -25,6 +25,7 @@
#include "DecoderPlugin.hxx"
#include "DetachedSong.hxx"
#include "system/FatalError.hxx"
+#include "MusicPipe.hxx"
#include "fs/Traits.hxx"
#include "fs/AllocatedPath.hxx"
#include "DecoderAPI.hxx"
@@ -449,9 +450,18 @@ decoder_task(void *arg)
dc.replay_gain_prev_db = dc.replay_gain_db;
dc.replay_gain_db = 0;
- /* fall through */
+ decoder_run(dc);
+ break;
case DecoderCommand::SEEK:
+ /* this seek was too late, and the decoder had
+ already finished; start a new decoder */
+
+ /* we need to clear the pipe here; usually the
+ PlayerThread is responsible, but it is not
+ aware that the decoder has finished */
+ dc.pipe->Clear(*dc.buffer);
+
decoder_run(dc);
break;
diff --git a/src/decoder/plugins/FfmpegDecoderPlugin.cxx b/src/decoder/plugins/FfmpegDecoderPlugin.cxx
index 7f4ac8bcc..904e21a5a 100644
--- a/src/decoder/plugins/FfmpegDecoderPlugin.cxx
+++ b/src/decoder/plugins/FfmpegDecoderPlugin.cxx
@@ -412,10 +412,23 @@ ffmpeg_probe(Decoder *decoder, InputStream &is)
nbytes -= PADDING;
AVProbeData avpd;
+
+ /* new versions of ffmpeg may add new attributes, and leaving
+ them uninitialized may crash; hopefully, zero-initializing
+ everything we don't know is ok */
+ memset(&avpd, 0, sizeof(avpd));
+
avpd.buf = buffer;
avpd.buf_size = nbytes;
avpd.filename = is.GetURI();
+#ifdef AVPROBE_SCORE_MIME
+ /* this attribute was added in libav/ffmpeg version 11, but
+ unfortunately it's "uint8_t" instead of "char", and it's
+ not "const" - wtf? */
+ avpd.mime_type = (uint8_t *)const_cast<char *>(is.GetMimeType());
+#endif
+
return av_probe_input_format(&avpd, true);
}
diff --git a/src/protocol/ArgParser.cxx b/src/protocol/ArgParser.cxx
index e3a0c107c..e373827b4 100644
--- a/src/protocol/ArgParser.cxx
+++ b/src/protocol/ArgParser.cxx
@@ -82,7 +82,7 @@ check_range(Client &client, unsigned *value_r1, unsigned *value_r2,
/* compatibility with older MPD versions: specifying
"-1" makes MPD display the whole list */
*value_r1 = 0;
- *value_r2 = std::numeric_limits<unsigned>::max();
+ *value_r2 = std::numeric_limits<int>::max();
return true;
}
@@ -109,7 +109,7 @@ check_range(Client &client, unsigned *value_r1, unsigned *value_r2,
}
if (test == test2)
- value = std::numeric_limits<unsigned>::max();
+ value = std::numeric_limits<int>::max();
if (value < 0) {
command_error(client, ACK_ERROR_ARG,
diff --git a/test/test_protocol.cxx b/test/test_protocol.cxx
new file mode 100644
index 000000000..d7ea7cd87
--- /dev/null
+++ b/test/test_protocol.cxx
@@ -0,0 +1,60 @@
+#include "config.h"
+#include "protocol/ArgParser.hxx"
+#include "protocol/Result.hxx"
+#include "Compiler.h"
+
+#include <cppunit/TestFixture.h>
+#include <cppunit/extensions/TestFactoryRegistry.h>
+#include <cppunit/ui/text/TestRunner.h>
+#include <cppunit/extensions/HelperMacros.h>
+
+static enum ack last_error = ack(-1);
+
+void
+command_error(gcc_unused Client &client, enum ack error,
+ gcc_unused const char *fmt, ...)
+{
+ last_error = error;
+}
+
+class ArgParserTest : public CppUnit::TestFixture {
+ CPPUNIT_TEST_SUITE(ArgParserTest);
+ CPPUNIT_TEST(TestRange);
+ CPPUNIT_TEST_SUITE_END();
+
+public:
+ void TestRange();
+};
+
+void
+ArgParserTest::TestRange()
+{
+ Client &client = *(Client *)nullptr;
+ unsigned a, b;
+
+ CPPUNIT_ASSERT(check_range(client, &a, &b, "1"));
+ CPPUNIT_ASSERT_EQUAL(1u, a);
+ CPPUNIT_ASSERT_EQUAL(2u, b);
+
+ CPPUNIT_ASSERT(check_range(client, &a, &b, "1:5"));
+ CPPUNIT_ASSERT_EQUAL(1u, a);
+ CPPUNIT_ASSERT_EQUAL(5u, b);
+
+ CPPUNIT_ASSERT(check_range(client, &a, &b, "1:"));
+ CPPUNIT_ASSERT_EQUAL(1u, a);
+ CPPUNIT_ASSERT(b >= 999999u);
+
+ CPPUNIT_ASSERT(!check_range(client, &a, &b, "-2"));
+ CPPUNIT_ASSERT_EQUAL(ACK_ERROR_ARG, last_error);
+}
+
+CPPUNIT_TEST_SUITE_REGISTRATION(ArgParserTest);
+
+int
+main(gcc_unused int argc, gcc_unused char **argv)
+{
+ CppUnit::TextUi::TestRunner runner;
+ auto &registry = CppUnit::TestFactoryRegistry::getRegistry();
+ runner.addTest(registry.makeTest());
+ return runner.run() ? EXIT_SUCCESS : EXIT_FAILURE;
+}