|
@@ -615,5 +615,88 @@ namespace Google.Protobuf
|
|
var stream = new CodedInputStream(new byte[10]);
|
|
var stream = new CodedInputStream(new byte[10]);
|
|
stream.Dispose();
|
|
stream.Dispose();
|
|
}
|
|
}
|
|
|
|
+
|
|
|
|
+ [Test]
|
|
|
|
+ public void TestParseMessagesCloseTo2G()
|
|
|
|
+ {
|
|
|
|
+ byte[] serializedMessage = GenerateBigSerializedMessage();
|
|
|
|
+ // How many of these big messages do we need to take us near our 2GB limit?
|
|
|
|
+ int count = Int32.MaxValue / serializedMessage.Length;
|
|
|
|
+ // Now make a MemoryStream that will fake a near-2GB stream of messages by returning
|
|
|
|
+ // our big serialized message 'count' times.
|
|
|
|
+ using (RepeatingMemoryStream stream = new RepeatingMemoryStream(serializedMessage, count))
|
|
|
|
+ {
|
|
|
|
+ Assert.DoesNotThrow(()=>TestAllTypes.Parser.ParseFrom(stream));
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ [Test]
|
|
|
|
+ public void TestParseMessagesOver2G()
|
|
|
|
+ {
|
|
|
|
+ byte[] serializedMessage = GenerateBigSerializedMessage();
|
|
|
|
+ // How many of these big messages do we need to take us near our 2GB limit?
|
|
|
|
+ int count = Int32.MaxValue / serializedMessage.Length;
|
|
|
|
+ // Now add one to take us over the 2GB limit
|
|
|
|
+ count++;
|
|
|
|
+ // Now make a MemoryStream that will fake a near-2GB stream of messages by returning
|
|
|
|
+ // our big serialized message 'count' times.
|
|
|
|
+ using (RepeatingMemoryStream stream = new RepeatingMemoryStream(serializedMessage, count))
|
|
|
|
+ {
|
|
|
|
+ Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseFrom(stream),
|
|
|
|
+ "Protocol message was too large. May be malicious. " +
|
|
|
|
+ "Use CodedInputStream.SetSizeLimit() to increase the size limit.");
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /// <returns>A serialized big message</returns>
|
|
|
|
+ private static byte[] GenerateBigSerializedMessage()
|
|
|
|
+ {
|
|
|
|
+ byte[] value = new byte[16 * 1024 * 1024];
|
|
|
|
+ TestAllTypes message = SampleMessages.CreateFullTestAllTypes();
|
|
|
|
+ message.SingleBytes = ByteString.CopyFrom(value);
|
|
|
|
+ return message.ToByteArray();
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ /// <summary>
|
|
|
|
+ /// A MemoryStream 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 2GB or close to it.
|
|
|
|
+ /// </summary>
|
|
|
|
+ private class RepeatingMemoryStream: MemoryStream
|
|
|
|
+ {
|
|
|
|
+ private readonly byte[] bytes;
|
|
|
|
+ private readonly int maxIterations;
|
|
|
|
+ private int index = 0;
|
|
|
|
+
|
|
|
|
+ public RepeatingMemoryStream(byte[] bytes, int maxIterations)
|
|
|
|
+ {
|
|
|
|
+ this.bytes = bytes;
|
|
|
|
+ this.maxIterations = maxIterations;
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ public override int Read(byte[] buffer, int offset, int count)
|
|
|
|
+ {
|
|
|
|
+ if (bytes.Length == 0)
|
|
|
|
+ {
|
|
|
|
+ return 0;
|
|
|
|
+ }
|
|
|
|
+ int numBytesCopiedTotal = 0;
|
|
|
|
+ while (numBytesCopiedTotal < count && index < maxIterations)
|
|
|
|
+ {
|
|
|
|
+ int numBytesToCopy = Math.Min(bytes.Length - (int)Position, count);
|
|
|
|
+ Array.Copy(bytes, (int)Position, buffer, offset, numBytesToCopy);
|
|
|
|
+ numBytesCopiedTotal += numBytesToCopy;
|
|
|
|
+ offset += numBytesToCopy;
|
|
|
|
+ count -= numBytesCopiedTotal;
|
|
|
|
+ Position += numBytesToCopy;
|
|
|
|
+ if (Position >= bytes.Length)
|
|
|
|
+ {
|
|
|
|
+ Position = 0;
|
|
|
|
+ index++;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ return numBytesCopiedTotal;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
}
|
|
}
|
|
}
|
|
}
|