|
|
|
@ -615,5 +615,88 @@ namespace Google.Protobuf |
|
|
|
|
var stream = new CodedInputStream(new byte[10]); |
|
|
|
|
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; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
} |