Compressor: throw on overflow instead of returning a negative size
Compress() and FrameTransformation::CompressImage() returned int64_t with a negative value meaning "did not fit". That is a footgun: the negative result silently converts to a huge size_t if a caller forgets to check it. Return size_t and instead throw a named CompressionBufferTooSmallException (deriving from JFJochException, Compression category) when the output would not fit the destination buffer. The receiver catches it explicitly and drops just that frame, as before; the offline/GetCompressedImage path uses a worst-case buffer so it never throws. Add a test that a too-small destination throws and a worst-case buffer does not. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -85,20 +85,20 @@ std::vector<uint8_t> JFJochBitShuffleCompressor::Compress(const void *source, si
|
||||
return tmp;
|
||||
}
|
||||
|
||||
int64_t JFJochBitShuffleCompressor::Compress(void *dest, size_t dest_size, const void *source, size_t nelements, size_t elem_size) {
|
||||
size_t JFJochBitShuffleCompressor::Compress(void *dest, size_t dest_size, const void *source, size_t nelements, size_t elem_size) {
|
||||
auto c_dest = (char *) dest;
|
||||
auto c_source = (char *) source;
|
||||
|
||||
if (algorithm == CompressionAlgorithm::NO_COMPRESSION) {
|
||||
// Trivial case if no compression - copy content
|
||||
if (nelements * elem_size > dest_size)
|
||||
return -1;
|
||||
throw CompressionBufferTooSmallException("compressed output exceeds destination buffer");
|
||||
memcpy(dest, source, nelements * elem_size);
|
||||
return nelements * elem_size;
|
||||
}
|
||||
|
||||
if (dest_size < 12)
|
||||
return -1;
|
||||
throw CompressionBufferTooSmallException("compressed output exceeds destination buffer");
|
||||
|
||||
const size_t block_size = BlockSize(algorithm, elem_size);
|
||||
|
||||
@@ -115,10 +115,10 @@ int64_t JFJochBitShuffleCompressor::Compress(void *dest, size_t dest_size, const
|
||||
size_t compressed_size = 12;
|
||||
|
||||
// Blocks are small relative to the image, so before each one we just check that the
|
||||
// remaining space still covers that block's worst case, and bail out (-1) if not.
|
||||
// remaining space still covers that block's worst case, and throw if not.
|
||||
for (int i = 0; i < num_full_blocks; i++) {
|
||||
if (compressed_size + MaxCompressedBlockSize(algorithm, block_size * elem_size) > dest_size)
|
||||
return -1;
|
||||
throw CompressionBufferTooSmallException("compressed output exceeds destination buffer");
|
||||
compressed_size += CompressBlock(c_dest + compressed_size,
|
||||
c_source + i * block_size * elem_size, block_size, elem_size);
|
||||
}
|
||||
@@ -126,7 +126,7 @@ int64_t JFJochBitShuffleCompressor::Compress(void *dest, size_t dest_size, const
|
||||
size_t last_block_size = reminder_size - reminder_size % BSHUF_BLOCKED_MULT;
|
||||
if (last_block_size > 0) {
|
||||
if (compressed_size + MaxCompressedBlockSize(algorithm, last_block_size * elem_size) > dest_size)
|
||||
return -1;
|
||||
throw CompressionBufferTooSmallException("compressed output exceeds destination buffer");
|
||||
compressed_size += CompressBlock(c_dest + compressed_size,
|
||||
c_source + num_full_blocks * block_size * elem_size, last_block_size, elem_size);
|
||||
}
|
||||
@@ -134,7 +134,7 @@ int64_t JFJochBitShuffleCompressor::Compress(void *dest, size_t dest_size, const
|
||||
size_t leftover_bytes = (reminder_size % BSHUF_BLOCKED_MULT) * elem_size;
|
||||
if (leftover_bytes > 0) {
|
||||
if (compressed_size + leftover_bytes > dest_size)
|
||||
return -1;
|
||||
throw CompressionBufferTooSmallException("compressed output exceeds destination buffer");
|
||||
memcpy(c_dest + compressed_size, c_source + (num_full_blocks * block_size + last_block_size) * elem_size, leftover_bytes);
|
||||
compressed_size += leftover_bytes;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user