Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 14 additions & 8 deletions src/main/java/org/xerial/snappy/SnappyFramedInputStream.java
Original file line number Diff line number Diff line change
Expand Up @@ -517,18 +517,24 @@ private boolean ensureBuffer()
return false;
}

if (!readBlockHeader()) {
eof = true;
return false;
}
// consume any run of skippable chunks iteratively; recursing once per
// chunk lets ~4 input bytes grow the call stack by one frame
FrameMetaData frameMetaData;
while (true) {
if (!readBlockHeader()) {
eof = true;
return false;
}

// get action based on header
final FrameMetaData frameMetaData = getFrameMetaData(frameHeader);
// get action based on header
frameMetaData = getFrameMetaData(frameHeader);

if (FrameAction.SKIP != frameMetaData.frameAction) {
break;
}

if (FrameAction.SKIP == frameMetaData.frameAction) {
SnappyFramed.skip(rbc, frameMetaData.length,
ByteBuffer.wrap(buffer));
return ensureBuffer();
}

if (frameMetaData.length > input.capacity()) {
Expand Down
50 changes: 50 additions & 0 deletions src/test/java/org/xerial/snappy/SnappyFramedStreamTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,56 @@ public void testSkippableChunkFlags()
}
}

@Test
public void testSkippableChunkRun()
throws Exception
{
// each zero-length skippable chunk is only 4 bytes on the wire; a long
// run must be skipped iteratively without exhausting the call stack
ByteArrayOutputStream stream = new ByteArrayOutputStream();
stream.write(HEADER_BYTES);
final byte[] skipChunk = {(byte) 0x80, 0, 0, 0};
for (int i = 0; i < 100000; i++) {
stream.write(skipChunk);
}
// uncompressed data chunk: flag 0x01, length 6 (crc32c + 2 bytes)
final byte[] data = {'h', 'i'};
final int crc32c = maskedCrc32c(data);
stream.write(new byte[] {1, 6, 0, 0, (byte) crc32c,
(byte) (crc32c >>> 8), (byte) (crc32c >>> 16),
(byte) (crc32c >>> 24), 'h', 'i'});

InputStream in = createInputStream(new ByteArrayInputStream(
stream.toByteArray()), true);
try {
assertArrayEquals(new byte[] {'h', 'i'}, toByteArray(in));
}
finally {
in.close();
}
}

@Test
public void testSkippableChunkRunToEof()
throws Exception
{
ByteArrayOutputStream stream = new ByteArrayOutputStream();
stream.write(HEADER_BYTES);
final byte[] skipChunk = {(byte) 0x80, 0, 0, 0};
for (int i = 0; i < 100000; i++) {
stream.write(skipChunk);
}

InputStream in = createInputStream(new ByteArrayInputStream(
stream.toByteArray()), true);
try {
assertEquals(-1, in.read());
}
finally {
in.close();
}
}

@Test(expected = IOException.class)
public void testInvalidBlockSizeZero()
throws Exception
Expand Down
Loading