From d4d06da2f8ed7364ae897bb9527923c704c0892e Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Mon, 15 Feb 2021 17:34:03 +0100 Subject: [PATCH] db/simple: fix dangling LightSong::tag reference in moved ExportedSong After commit 1afa33c3c766af2, an old bug was revealed: SimpleDatabase::GetSong() constructs an ExportedSong instance by moving the return value of Song::Export(), which causes the LightSong::tag field to be dangling on the moved-from ExportedSong::tag_buffer. This broke tags from CUE sheets. Closes https://github.com/MusicPlayerDaemon/MPD/issues/1070 --- NEWS | 2 ++ src/db/plugins/simple/ExportedSong.hxx | 9 +++++++++ src/song/LightSong.hxx | 13 +++++++++++++ 3 files changed, 24 insertions(+) diff --git a/NEWS b/NEWS index 7b0615128..80ae7c3c7 100644 --- a/NEWS +++ b/NEWS @@ -1,4 +1,6 @@ ver 0.22.5 (not yet released) +* database + - simple: fix missing CUE sheet metadata in "addid" command * tags - id: translate TPE3 to Conductor, not Performer * archive diff --git a/src/db/plugins/simple/ExportedSong.hxx b/src/db/plugins/simple/ExportedSong.hxx index 886be078b..37e4109b5 100644 --- a/src/db/plugins/simple/ExportedSong.hxx +++ b/src/db/plugins/simple/ExportedSong.hxx @@ -37,6 +37,15 @@ public: ExportedSong(const char *_uri, Tag &&_tag) noexcept :LightSong(_uri, tag_buffer), tag_buffer(std::move(_tag)) {} + + /* this custom move constructor is necessary so LightSong::tag + points to this instance's #Tag field instead of leaving a + dangling reference to the source object's #Tag field */ + ExportedSong(ExportedSong &&src) noexcept + :LightSong(src, tag_buffer), + tag_buffer(std::move(src.tag_buffer)) {} + + ExportedSong &operator=(ExportedSong &&) = delete; }; #endif diff --git a/src/song/LightSong.hxx b/src/song/LightSong.hxx index ee372576a..06f0a41f9 100644 --- a/src/song/LightSong.hxx +++ b/src/song/LightSong.hxx @@ -88,6 +88,19 @@ struct LightSong { LightSong(const char *_uri, const Tag &_tag) noexcept :uri(_uri), tag(_tag) {} + /** + * A copy constructor which copies all fields, but only sets + * the tag to a caller-provided reference. This is used by + * the #ExportedSong move constructor. + */ + LightSong(const LightSong &src, const Tag &_tag) noexcept + :directory(src.directory), uri(src.uri), + real_uri(src.real_uri), + tag(_tag), + mtime(src.mtime), + start_time(src.start_time), end_time(src.end_time), + audio_format(src.audio_format) {} + gcc_pure std::string GetURI() const noexcept { if (directory == nullptr)