From 601208bb9cb0c57310a146b1a63114c6ad9b2bcf Mon Sep 17 00:00:00 2001 From: Dmitry Makarenko Date: Mon, 26 Jan 2026 20:55:44 +0300 Subject: [PATCH 1/5] Fix bool conversion from string treating "0" as true --- src/XMLHandler.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/XMLHandler.h b/src/XMLHandler.h index c3242cd..2221be4 100644 --- a/src/XMLHandler.h +++ b/src/XMLHandler.h @@ -55,7 +55,7 @@ void GetAttributeValue(const AttributeValue& attr, Ret& result) { if constexpr (std::is_same_v) { - result = arg == "true" || arg == "0"; + result = arg == "true" || arg == "1"; } else if constexpr (std::is_floating_point_v) { From 99837208db7c328f0601d16084cdf4741551c332 Mon Sep 17 00:00:00 2001 From: Dmitry Makarenko Date: Mon, 26 Jan 2026 20:55:57 +0300 Subject: [PATCH 2/5] Fix IdsLookup::store out-of-bounds access on resize --- src/BinaryXMLConverter.cpp | 13 +++---------- 1 file changed, 3 insertions(+), 10 deletions(-) diff --git a/src/BinaryXMLConverter.cpp b/src/BinaryXMLConverter.cpp index eea473c..b2a7493 100644 --- a/src/BinaryXMLConverter.cpp +++ b/src/BinaryXMLConverter.cpp @@ -281,17 +281,10 @@ class IdsLookup final public: void store(uint16_t index, std::string value) { - const auto size = mIds.size(); + if (index >= mIds.size()) + mIds.resize(index + 1); - if (index == size) - mIds.push_back(std::move(value)); - else - { - if ((index + 1) < size) - mIds.resize(index); - - mIds[index] = std::move(value); - } + mIds[index] = std::move(value); } std::string_view get(uint16_t index) From b5013399bc072cc8cac3a791e9101daca217c9fa Mon Sep 17 00:00:00 2001 From: Dmitry Makarenko Date: Mon, 26 Jan 2026 20:56:14 +0300 Subject: [PATCH 3/5] Fix Buffer::read corrupting data across chunk boundaries --- src/Buffer.cpp | 1 + src/Buffer.h | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/Buffer.cpp b/src/Buffer.cpp index 8ac8653..471a042 100644 --- a/src/Buffer.cpp +++ b/src/Buffer.cpp @@ -86,6 +86,7 @@ Buffer::read(void* data, size_t offset, size_t size) const noexcept offset = 0; bytesLeft -= chunkSize; outPtr += chunkSize; + ++chunk; } return size; diff --git a/src/Buffer.h b/src/Buffer.h index 9f1e537..f661e12 100644 --- a/src/Buffer.h +++ b/src/Buffer.h @@ -48,12 +48,12 @@ class Buffer final return 0; const size_t chunkIndex = offset / BUFFER_SIZE; - offset = offset - BUFFER_SIZE * chunkIndex; + const size_t chunkOffset = offset - BUFFER_SIZE * chunkIndex; - if (BUFFER_SIZE < (offset + size)) + if (BUFFER_SIZE < (chunkOffset + size)) return read(&data, offset, size); - const void* ptr = mChunks[chunkIndex].data() + offset; + const void* ptr = mChunks[chunkIndex].data() + chunkOffset; data = *static_cast(ptr); From 956b3120357e9af85640c6c440c07615f2a27a37 Mon Sep 17 00:00:00 2001 From: Dmitry Makarenko Date: Mon, 26 Jan 2026 20:56:28 +0300 Subject: [PATCH 4/5] Fix removeUnusedBlocks finding missing blocks instead of orphaned --- src/ProjectModel.cpp | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/src/ProjectModel.cpp b/src/ProjectModel.cpp index 632db63..5b84abf 100644 --- a/src/ProjectModel.cpp +++ b/src/ProjectModel.cpp @@ -483,15 +483,22 @@ void AudacityProject::removeUnusedBlocks() readBlocksList.reset(); - std::set orphanedBlocks; + std::set usedBlocks; - for (const auto block : mWaveBlocks) + for (const auto& block : mWaveBlocks) { if (block.isSilence()) continue; - if (availableBlocks.count(block.getBlockId()) == 0) - orphanedBlocks.emplace(block.getBlockId()); + usedBlocks.emplace(block.getBlockId()); + } + + std::set orphanedBlocks; + + for (auto blockId : availableBlocks) + { + if (usedBlocks.count(blockId) == 0) + orphanedBlocks.emplace(blockId); } mDb.reopenReadonlyAsWritable(); From edd0a14a5274fb0613d45126be83775dabbe92bc Mon Sep 17 00:00:00 2001 From: Dmitry Makarenko Date: Mon, 26 Jan 2026 21:40:50 +0300 Subject: [PATCH 5/5] Cleanup journal files on finish --- .gitignore | 9 +++++++++ src/AudacityDatabase.cpp | 34 ++++++++++++++++++++++------------ src/AudacityDatabase.h | 2 ++ 3 files changed, 33 insertions(+), 12 deletions(-) diff --git a/.gitignore b/.gitignore index 8ffcce1..5f06279 100644 --- a/.gitignore +++ b/.gitignore @@ -36,3 +36,12 @@ build/** out/** .venv/** CMakeUserPresets.json + +# Audacity files + +*.aup3 +*.aup4 +*.aup3-shm +*.aup3-wal +*.aup4-shm +*.aup4-wal diff --git a/src/AudacityDatabase.cpp b/src/AudacityDatabase.cpp index 4316c00..c95d9d4 100644 --- a/src/AudacityDatabase.cpp +++ b/src/AudacityDatabase.cpp @@ -132,6 +132,12 @@ AudacityDatabase::AudacityDatabase( }, true); } +AudacityDatabase::~AudacityDatabase() +{ + mDatabase.reset(); + removeJournalFiles(mReadOnly ? mProjectPath : mWritablePath); +} + void AudacityDatabase::reopenReadonlyAsWritable() { if (!mReadOnly) @@ -466,22 +472,26 @@ void AudacityDatabase::extractTrack( waveFile.writeFile(); } -void AudacityDatabase::removeOldFiles() +void AudacityDatabase::removeJournalFiles(const std::filesystem::path& dbPath) { - if (std::filesystem::exists(mWritablePath)) - { - std::filesystem::remove(mWritablePath); + auto walFile = dbPath; + walFile.replace_extension("aup3-wal"); - auto walFile = mWritablePath; - walFile.replace_extension("aup3-wal"); + if (std::filesystem::exists(walFile)) + std::filesystem::remove(walFile); - if (std::filesystem::exists(walFile)) - std::filesystem::remove(walFile); + auto shmFile = dbPath; + shmFile.replace_extension("aup3-shm"); - auto shmFile = mWritablePath; - shmFile.replace_extension("aup3-shm"); + if (std::filesystem::exists(shmFile)) + std::filesystem::remove(shmFile); +} - if (std::filesystem::exists(shmFile)) - std::filesystem::remove(shmFile); +void AudacityDatabase::removeOldFiles() +{ + if (std::filesystem::exists(mWritablePath)) + { + std::filesystem::remove(mWritablePath); + removeJournalFiles(mWritablePath); } } diff --git a/src/AudacityDatabase.h b/src/AudacityDatabase.h index 2cb4eaa..8d961d7 100644 --- a/src/AudacityDatabase.h +++ b/src/AudacityDatabase.h @@ -24,6 +24,7 @@ class AudacityDatabase final public: explicit AudacityDatabase( const std::filesystem::path& path, RecoveryConfig recoveryConfig); + ~AudacityDatabase(); void reopenReadonlyAsWritable(); void recoverDatabase(); @@ -43,6 +44,7 @@ class AudacityDatabase final void extractTrack(SampleFormat format, int32_t sampleRate, bool asStereo); private: + static void removeJournalFiles(const std::filesystem::path& dbPath); void removeOldFiles(); std::unique_ptr mDatabase;