Loading debian/changelog +11 −0 Original line number Diff line number Diff line mediadb (20260422+66) unstable; urgency=low * Fix segfault in PrefetchBuffer (use-after-free): - Add destructor that waits for all in-flight io_pool futures before PrefetchBuffer members are destroyed. - Change lambda captures from `this` to by-value copies of db, cache, and media_id so tasks remain safe if PrefetchBuffer is destroyed while they are still queued or running. -- Jan Koester <jan.koester@tuxist.de> Tue, 22 Apr 2026 00:00:00 +0200 mediadb (20260422+65) unstable; urgency=low * Fix HTTP timeouts on /raw and /preview endpoints: Loading src/preview.cpp +25 −3 Original line number Diff line number Diff line Loading @@ -41,6 +41,17 @@ struct PrefetchBuffer { }; std::deque<PendingBlock> ring; ~PrefetchBuffer() { // Wait for all in-flight io_pool tasks before destroying members // they reference (db, media_id, cache). Destroying a std::future // does NOT block, so without this the tasks would access freed memory. for (auto& b : ring) { if (b.fut.valid()) { try { b.fut.wait(); } catch (...) {} } } } static std::string make_key(const std::string& mid, std::uint64_t off, std::uint64_t len) { return "prefetch:" + mid + ":" + std::to_string(off) + ":" + std::to_string(len); } Loading Loading @@ -79,11 +90,22 @@ struct PrefetchBuffer { p.set_value(cached); ring.push_back(PendingBlock{off, len, p.get_future(), std::vector<uint8_t>()}); } else { // Capture members by value — not `this` — so the lambda // remains safe even if PrefetchBuffer is destroyed while // the task is still queued / running in io_pool. MediaBackendApi* pdb = db; BlobCache* pcache = cache; std::string pmid = media_id; ring.push_back(PendingBlock{ off, len, io_pool->submit([this, off, len]() { auto bytes = db->read_media_data_range(media_id, off, len); cache_put(off, len, bytes); io_pool->submit([pdb, pcache, pmid, off, len]() { auto bytes = pdb->read_media_data_range(pmid, off, len); if (pcache && !bytes.empty()) { BlobValue bv; bv.data = bytes; bv.type = BlobType::prefetch; pcache->put(make_key(pmid, off, len), std::move(bv)); } return bytes; }), std::vector<uint8_t>() Loading Loading
debian/changelog +11 −0 Original line number Diff line number Diff line mediadb (20260422+66) unstable; urgency=low * Fix segfault in PrefetchBuffer (use-after-free): - Add destructor that waits for all in-flight io_pool futures before PrefetchBuffer members are destroyed. - Change lambda captures from `this` to by-value copies of db, cache, and media_id so tasks remain safe if PrefetchBuffer is destroyed while they are still queued or running. -- Jan Koester <jan.koester@tuxist.de> Tue, 22 Apr 2026 00:00:00 +0200 mediadb (20260422+65) unstable; urgency=low * Fix HTTP timeouts on /raw and /preview endpoints: Loading
src/preview.cpp +25 −3 Original line number Diff line number Diff line Loading @@ -41,6 +41,17 @@ struct PrefetchBuffer { }; std::deque<PendingBlock> ring; ~PrefetchBuffer() { // Wait for all in-flight io_pool tasks before destroying members // they reference (db, media_id, cache). Destroying a std::future // does NOT block, so without this the tasks would access freed memory. for (auto& b : ring) { if (b.fut.valid()) { try { b.fut.wait(); } catch (...) {} } } } static std::string make_key(const std::string& mid, std::uint64_t off, std::uint64_t len) { return "prefetch:" + mid + ":" + std::to_string(off) + ":" + std::to_string(len); } Loading Loading @@ -79,11 +90,22 @@ struct PrefetchBuffer { p.set_value(cached); ring.push_back(PendingBlock{off, len, p.get_future(), std::vector<uint8_t>()}); } else { // Capture members by value — not `this` — so the lambda // remains safe even if PrefetchBuffer is destroyed while // the task is still queued / running in io_pool. MediaBackendApi* pdb = db; BlobCache* pcache = cache; std::string pmid = media_id; ring.push_back(PendingBlock{ off, len, io_pool->submit([this, off, len]() { auto bytes = db->read_media_data_range(media_id, off, len); cache_put(off, len, bytes); io_pool->submit([pdb, pcache, pmid, off, len]() { auto bytes = pdb->read_media_data_range(pmid, off, len); if (pcache && !bytes.empty()) { BlobValue bv; bv.data = bytes; bv.type = BlobType::prefetch; pcache->put(make_key(pmid, off, len), std::move(bv)); } return bytes; }), std::vector<uint8_t>() Loading