Merge pull request from GHSA-55g7-9cwv-5qfv
* Validate chunk size to be within a configured maximum * Add constructors to have max size configurable * Code cleanup * Use 512MB for consistency --------- Co-authored-by: Taro L. Saito <leo@xerial.org>
This commit is contained in:
parent
49d700175f
commit
9f8c3cf742
|
@ -1,9 +1,9 @@
|
|||
package org.xerial.snappy;
|
||||
|
||||
import java.io.OutputStream;
|
||||
|
||||
import org.xerial.snappy.buffer.CachedBufferAllocator;
|
||||
|
||||
import java.io.OutputStream;
|
||||
|
||||
public class SnappyHadoopCompatibleOutputStream extends SnappyOutputStream
|
||||
{
|
||||
public SnappyHadoopCompatibleOutputStream(OutputStream out)
|
||||
|
|
|
@ -36,8 +36,11 @@ import java.io.InputStream;
|
|||
public class SnappyInputStream
|
||||
extends InputStream
|
||||
{
|
||||
public static final int MAX_CHUNK_SIZE = 512 * 1024 * 1024; // 512 MiB
|
||||
|
||||
private boolean finishedReading = false;
|
||||
protected final InputStream in;
|
||||
private final int maxChunkSize;
|
||||
|
||||
private byte[] compressed;
|
||||
private byte[] uncompressed;
|
||||
|
@ -55,6 +58,21 @@ public class SnappyInputStream
|
|||
public SnappyInputStream(InputStream input)
|
||||
throws IOException
|
||||
{
|
||||
this(input, MAX_CHUNK_SIZE);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create a filter for reading compressed data as a uncompressed stream with provided maximum chunk size
|
||||
*
|
||||
* @param input
|
||||
* @param maxChunkSize
|
||||
* @throws IOException
|
||||
*/
|
||||
public SnappyInputStream(InputStream input, int maxChunkSize)
|
||||
throws IOException
|
||||
{
|
||||
this.maxChunkSize = maxChunkSize;
|
||||
this.in = input;
|
||||
readHeader();
|
||||
}
|
||||
|
@ -422,6 +440,11 @@ public class SnappyInputStream
|
|||
throw new SnappyError(SnappyErrorCode.INVALID_CHUNK_SIZE, "chunkSize is too big or negative : " + chunkSize);
|
||||
}
|
||||
|
||||
// chunkSize is big
|
||||
if (chunkSize > maxChunkSize) {
|
||||
throw new SnappyError(SnappyErrorCode.FAILED_TO_UNCOMPRESS, String.format("Received chunkSize %,d is greater than max configured chunk size %,d", chunkSize, maxChunkSize));
|
||||
}
|
||||
|
||||
// extend the compressed data buffer size
|
||||
if (compressed == null || chunkSize > compressed.length) {
|
||||
// chunkSize exceeds limit
|
||||
|
|
|
@ -59,6 +59,7 @@ import java.io.OutputStream;
|
|||
public class SnappyOutputStream
|
||||
extends OutputStream
|
||||
{
|
||||
public static final int MAX_BLOCK_SIZE = 512 * 1024 * 1024; // 512 MiB
|
||||
static final int MIN_BLOCK_SIZE = 1 * 1024;
|
||||
static final int DEFAULT_BLOCK_SIZE = 32 * 1024; // Use 32kb for the default block size
|
||||
|
||||
|
@ -84,7 +85,7 @@ public class SnappyOutputStream
|
|||
/**
|
||||
* @param out
|
||||
* @param blockSize byte size of the internal buffer size
|
||||
* @throws IOException
|
||||
* @throws IllegalArgumentException when blockSize is larger than 512 MiB
|
||||
*/
|
||||
public SnappyOutputStream(OutputStream out, int blockSize)
|
||||
{
|
||||
|
@ -95,6 +96,9 @@ public class SnappyOutputStream
|
|||
{
|
||||
this.out = out;
|
||||
this.blockSize = Math.max(MIN_BLOCK_SIZE, blockSize);
|
||||
if (this.blockSize > MAX_BLOCK_SIZE){
|
||||
throw new IllegalArgumentException(String.format("Provided chunk size %,d larger than max %,d", this.blockSize, MAX_BLOCK_SIZE));
|
||||
}
|
||||
int inputSize = blockSize;
|
||||
int outputSize = SnappyCodec.HEADER_SIZE + 4 + Snappy.maxCompressedLength(blockSize);
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@ import java.lang.ref.WeakReference;
|
|||
import java.nio.ByteOrder;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.Assert;
|
||||
import org.xerial.snappy.buffer.BufferAllocatorFactory;
|
||||
import org.xerial.snappy.buffer.CachedBufferAllocator;
|
||||
import org.xerial.snappy.buffer.DefaultBufferAllocator;
|
||||
|
@ -106,6 +107,17 @@ public class SnappyOutputStreamTest
|
|||
is.close();
|
||||
}
|
||||
|
||||
@Test(expected = IllegalArgumentException.class)
|
||||
public void invalidBlockSize()
|
||||
throws Exception
|
||||
{
|
||||
// We rely on catch below, if there is no error this test will pass
|
||||
// This can be done better with Assertions.assertThrows
|
||||
Boolean exceptionThrown = false;
|
||||
ByteArrayOutputStream b = new ByteArrayOutputStream();
|
||||
SnappyOutputStream os = new SnappyOutputStream(b, 1024 * 1024 * 1024);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void smallWrites()
|
||||
throws Exception
|
||||
|
|
|
@ -379,6 +379,24 @@ public class SnappyTest
|
|||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Tests sad cases for SnappyInputStream.read method
|
||||
- Expects a failed to compress exception due to upper bounds chunk size
|
||||
- {-126, 'S', 'N', 'A', 'P', 'P', 'Y', 0, 0, 0, 0, 0, 0, 0, 0, 0,(byte) 0x7f, (byte) 0xff, (byte) 0xff, (byte) 0xff}
|
||||
*/
|
||||
@Test
|
||||
public void isInvalidChunkLengthForSnappyInputStream()
|
||||
throws Exception {
|
||||
byte[] data = {-126, 'S', 'N', 'A', 'P', 'P', 'Y', 0, 0, 0, 0, 0, 0, 0, 0, 0, (byte) 0x7f, (byte) 0xff, (byte) 0xff, (byte) 0xff};
|
||||
SnappyInputStream in = new SnappyInputStream(new ByteArrayInputStream(data));
|
||||
byte[] out = new byte[50];
|
||||
try {
|
||||
in.read(out);
|
||||
} catch (SnappyError error) {
|
||||
Assert.assertEquals(error.errorCode, SnappyErrorCode.FAILED_TO_UNCOMPRESS);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
Tests happy cases for BitShuffle.shuffle method
|
||||
- double: 0, 10
|
||||
|
|
Loading…
Reference in New Issue