fix: limit the chunks and the inflated size of an sd0 buffer

An sd0 buffer could hold any number of chunks, and each chunk grew the
inflated data by a full chunk whatever it held, so the data of a chunk
that was not full was followed by a gap. A buffer now holds at most
4096 chunks and inflates to at most 64 MiB, and every chunk is inflated
right after the one before it.

Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
This commit is contained in:
Aaron Kimbrell
2026-11-10 13:03:24 -06:00
parent a235e57975
commit 43cea3a245
3 changed files with 103 additions and 1 deletions

View File

@@ -66,6 +66,11 @@ Sd0::Sd0(std::istream& buffer) {
LOG("Failed to read chunk size from stream %lld %zu", buffer.tellg(), m_Chunks.size());
break;
}
if (m_Chunks.size() >= MAX_CHUNKS) {
LOG("More than %u chunks in an sd0 buffer, rejecting.", MAX_CHUNKS);
m_Chunks.clear();
break;
}
auto& chunk = m_Chunks.emplace_back();
bool firstBuffer = m_Chunks.size() == 1;
auto dataOffset = GetDataOffset(firstBuffer);
@@ -155,7 +160,8 @@ std::string Sd0::GetAsStringUncompressed() const {
break;
}
auto oldSize = toReturn.size();
// Each chunk is inflated right after the one before it
const auto oldSize = toReturn.size();
toReturn.resize(oldSize + MAX_UNCOMPRESSED_CHUNK_SIZE);
int32_t error{};
const auto uncompressedSize = ZCompression::Decompress(
@@ -171,6 +177,14 @@ std::string Sd0::GetAsStringUncompressed() const {
}
totalSize += uncompressedSize;
toReturn.resize(totalSize);
if (totalSize > MAX_UNCOMPRESSED_SIZE) {
LOG("An sd0 buffer inflates to more than %u bytes, aborting", MAX_UNCOMPRESSED_SIZE);
toReturn = "";
totalSize = 0;
break;
}
}
toReturn.resize(totalSize);