aboutsummaryrefslogtreecommitdiffhomepage
path: root/java
diff options
context:
space:
mode:
authorGravatar Michael Stack <saint.ack@gmail.com>2016-12-01 16:34:04 -0800
committerGravatar Michael Stack <saint.ack@gmail.com>2016-12-01 20:18:31 -0800
commit7550bcd89f5a9f0a94b4e3ad93da02f3d98529f1 (patch)
tree028efeea5ae20d1cd0d7e86898e0964f77befb42 /java
parentf8ca3acd2924421dc18f685c629a6e54875ac113 (diff)
Change CodedInputStream#DEFAULT_SIZE_LIMIT from 64MB to
Integer.MAX_SIZE (0x7FFFFFF) #2228 M java/core/src/main/java/com/google/protobuf/CodedInputStream.java Set DEFAULT_SIZE_LIMIT to Integer.MAX_SIZE (Was 64MB). This is how it was in pre-2.7.0 pb. Changed size check to an overflow-conscious test (as it is later in tryRefillBuffer (making sizeLimit a long was to disruptive). M java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java Add two tests that echo tests recently added over in c++ to test parse of message sizes that are approach and are beyond the size limit.
Diffstat (limited to 'java')
-rw-r--r--java/core/src/main/java/com/google/protobuf/CodedInputStream.java7
-rw-r--r--java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java78
2 files changed, 80 insertions, 5 deletions
diff --git a/java/core/src/main/java/com/google/protobuf/CodedInputStream.java b/java/core/src/main/java/com/google/protobuf/CodedInputStream.java
index e461fa28..14169dc4 100644
--- a/java/core/src/main/java/com/google/protobuf/CodedInputStream.java
+++ b/java/core/src/main/java/com/google/protobuf/CodedInputStream.java
@@ -60,7 +60,8 @@ import java.util.List;
public abstract class CodedInputStream {
private static final int DEFAULT_BUFFER_SIZE = 4096;
private static final int DEFAULT_RECURSION_LIMIT = 100;
- private static final int DEFAULT_SIZE_LIMIT = 64 << 20; // 64MB
+ // Integer.MAX_VALUE == 0x7FFFFFF == INT_MAX from limits.h
+ private static final int DEFAULT_SIZE_LIMIT = Integer.MAX_VALUE;
/** Visible for subclasses. See setRecursionLimit() */
int recursionDepth;
@@ -2762,9 +2763,9 @@ public abstract class CodedInputStream {
throw InvalidProtocolBufferException.negativeSize();
}
- // Verify that the message size so far has not exceeded sizeLimit.
+ // Integer-overflow-conscious check that the message size so far has not exceeded sizeLimit.
int currentMessageSize = totalBytesRetired + pos + size;
- if (currentMessageSize > sizeLimit) {
+ if (currentMessageSize - sizeLimit > 0) {
throw InvalidProtocolBufferException.sizeLimitExceeded();
}
diff --git a/java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java b/java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java
index e2ab0df9..e440c7db 100644
--- a/java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java
+++ b/java/core/src/test/java/com/google/protobuf/CodedInputStreamTest.java
@@ -30,8 +30,6 @@
package com.google.protobuf;
-import static org.junit.Assert.assertArrayEquals;
-
import protobuf_unittest.UnittestProto.BoolMessage;
import protobuf_unittest.UnittestProto.Int32Message;
import protobuf_unittest.UnittestProto.Int64Message;
@@ -445,6 +443,82 @@ public class CodedInputStreamTest extends TestCase {
}
}
+ /**
+ * Test we can do messages that are up to CodedInputStream#DEFAULT_SIZE_LIMIT
+ * in size (2G or Integer#MAX_SIZE).
+ * @throws IOException
+ */
+ public void testParseMessagesCloseTo2G() throws IOException {
+ byte[] serializedMessage = getBigSerializedMessage();
+ // How many of these big messages do we need to take us near our 2G limit?
+ int count = Integer.MAX_VALUE / serializedMessage.length;
+ // Now make an inputstream that will fake a near 2G message of messages
+ // returning our big serialized message 'count' times.
+ InputStream is = new RepeatingInputStream(serializedMessage, count);
+ // Parse should succeed!
+ TestAllTypes.parseFrom(is);
+ }
+
+ /**
+ * Test there is an exception if a message exceeds
+ * CodedInputStream#DEFAULT_SIZE_LIMIT in size (2G or Integer#MAX_SIZE).
+ * @throws IOException
+ */
+ public void testParseMessagesOver2G() throws IOException {
+ byte[] serializedMessage = getBigSerializedMessage();
+ // How many of these big messages do we need to take us near our 2G limit?
+ int count = Integer.MAX_VALUE / serializedMessage.length;
+ // Now add one to take us over the limit
+ count++;
+ // Now make an inputstream that will fake a near 2G message of messages
+ // returning our big serialized message 'count' times.
+ InputStream is = new RepeatingInputStream(serializedMessage, count);
+ try {
+ TestAllTypes.parseFrom(is);
+ fail("Should have thrown an exception!");
+ } catch (InvalidProtocolBufferException e) {
+ assertTrue(e.getMessage().contains("too large"));
+ }
+ }
+
+ /*
+ * @return A serialized big message.
+ */
+ private static byte[] getBigSerializedMessage() {
+ byte[] value = new byte[16 * 1024 * 1024];
+ ByteString bsValue = ByteString.wrap(value);
+ return TestAllTypes.newBuilder().setOptionalBytes(bsValue).build().toByteArray();
+ }
+
+ /*
+ * An input stream that repeats a byte arrays' content a number of times.
+ * Simulates really large input without consuming loads of memory. Used above
+ * to test the parsing behavior when the input size exceeds 2G or close to it.
+ */
+ private static class RepeatingInputStream extends InputStream {
+ private final byte[] serializedMessage;
+ private final int count;
+ private int index = 0;
+ private int offset = 0;
+
+ RepeatingInputStream(byte[] serializedMessage, int count) {
+ this.serializedMessage = serializedMessage;
+ this.count = count;
+ }
+
+ @Override
+ public int read() throws IOException {
+ if (this.offset == this.serializedMessage.length) {
+ this.index++;
+ this.offset = 0;
+ }
+ if (this.index == this.count) {
+ return -1;
+ }
+ return this.serializedMessage[offset++];
+ }
+ }
+
private TestRecursiveMessage makeRecursiveMessage(int depth) {
if (depth == 0) {
return TestRecursiveMessage.newBuilder().setI(5).build();