Skip to content

Throw LZ4Exception for input shorter than the length prefix - #160

Merged
yawkat merged 1 commit into
mainfrom
fix/decompressor-with-length-short-input
Oct 15, 2026
Merged

yawkat merged 1 commit into
mainfrom
fix/decompressor-with-length-short-input

Conversation

@yawkat

@yawkat yawkat commented Oct 15, 2026

Copy link
Copy Markdown
Owner

LZ4DecompressorWithLength read the 4-byte length prefix without checking that the input was long enough. Input with fewer than 4 bytes therefore failed with an ArrayIndexOutOfBoundsException or IndexOutOfBoundsException instead of the documented LZ4Exception. Examples:

new LZ4DecompressorWithLength(factory.safeDecompressor()).decompress(new byte[]{1, 0});
new LZ4DecompressorWithLength(factory.safeDecompressor())
    .decompress(ByteBuffer.wrap(new byte[]{1, 0}), 0, 2, dest, 0);

On the safe paths with an explicit srcLen < 4 inside a longer array, the prefix was read past srcLen, and the call then failed with an IllegalArgumentException for the negative remaining length.

All decompress overloads now check that at least 4 bytes are available before reading the prefix, and throw LZ4Exception if they aren't. This covers array and ByteBuffer, and fast and safe decompressors. The available length is srcLen for the safe paths, src.length - srcOff or src.limit() - srcOff for the fast paths, and src.remaining() for decompress(ByteBuffer, ByteBuffer). Invalid offsets still throw ArrayIndexOutOfBoundsException, as before. The public static getDecompressedLength helpers are unchanged.

Found by fuzzing with micronaut-fuzzing.

Tests: I added OutOfBoundsTest.inputShorterThanLengthPrefix for 0–3 byte inputs. It runs every overload with fast and safe decompressors, using heap and direct buffers. I also added safeInputShorterThanLengthPrefixWithTrailingBytes, which covers srcLen < 4 inside a longer array or buffer. Without the fix, all three test cases fail with AIOOBE or IAE. With the fix, OutOfBoundsTest and LZ4Test pass.

🤖 Generated with Claude Code

LZ4DecompressorWithLength read the 4-byte length prefix without checking
that the input is long enough, so input of fewer than 4 bytes surfaced
as ArrayIndexOutOfBoundsException, IndexOutOfBoundsException or
IllegalArgumentException instead of LZ4Exception. Check the available
compressed length in all decompress overloads, for both fast and safe
decompressors, before reading the prefix.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
yawkat added a commit that referenced this pull request Oct 15, 2026
Place it after destinationBufferLimitsDecompressedLength so that it does
not conflict with the short input test from #160.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@yawkat
yawkat marked this pull request as ready for review October 15, 2026 13:21
@yawkat
yawkat merged commit 096cb51 into main Oct 15, 2026
3 checks passed
@yawkat
yawkat deleted the fix/decompressor-with-length-short-input branch October 15, 2026 13:21
yawkat added a commit that referenced this pull request Oct 15, 2026
…fer, int) (#161)

* Use the buffer limit for the safe decompress(ByteBuffer, int, ByteBuffer, int)

With a safe decompressor, decompress(ByteBuffer src, int srcOff,
ByteBuffer dest, int destOff) computed the compressed length as
src.remaining() - srcOff, mixing the buffer's position with the absolute
offset. Valid input failed to decompress whenever src.position() was not
0. Use src.limit() - srcOff, which matches the absolute indexing of the
other ByteBuffer arguments and the fast path.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

* Move the ByteBuffer source offset test

Place it after destinationBufferLimitsDecompressedLength so that it does
not conflict with the short input test from #160.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

---------

Co-authored-by: Claude Opus 5.5 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant