Validate that after reading a message, we've consumed as many bytes as we expected to.

We should now have no conformance failures.
This commit is contained in:
Jon Skeet 2015-08-04 12:38:53 +01:00
parent fe355b26ec
commit 15bf55e225
3 changed files with 47 additions and 30 deletions

View File

@ -1,22 +0,0 @@
ProtobufInput.PrematureEofBeforeUnknownValue.BOOL
ProtobufInput.PrematureEofBeforeUnknownValue.BYTES
ProtobufInput.PrematureEofBeforeUnknownValue.DOUBLE
ProtobufInput.PrematureEofBeforeUnknownValue.ENUM
ProtobufInput.PrematureEofBeforeUnknownValue.FIXED32
ProtobufInput.PrematureEofBeforeUnknownValue.FIXED64
ProtobufInput.PrematureEofBeforeUnknownValue.FLOAT
ProtobufInput.PrematureEofBeforeUnknownValue.INT32
ProtobufInput.PrematureEofBeforeUnknownValue.INT64
ProtobufInput.PrematureEofBeforeUnknownValue.MESSAGE
ProtobufInput.PrematureEofBeforeUnknownValue.SFIXED32
ProtobufInput.PrematureEofBeforeUnknownValue.SFIXED64
ProtobufInput.PrematureEofBeforeUnknownValue.SINT32
ProtobufInput.PrematureEofBeforeUnknownValue.SINT64
ProtobufInput.PrematureEofBeforeUnknownValue.STRING
ProtobufInput.PrematureEofBeforeUnknownValue.UINT32
ProtobufInput.PrematureEofBeforeUnknownValue.UINT64
ProtobufInput.PrematureEofInDelimitedDataForKnownNonRepeatedValue.MESSAGE
ProtobufInput.PrematureEofInDelimitedDataForKnownRepeatedValue.MESSAGE
ProtobufInput.PrematureEofInDelimitedDataForUnknownValue.BYTES
ProtobufInput.PrematureEofInDelimitedDataForUnknownValue.MESSAGE
ProtobufInput.PrematureEofInDelimitedDataForUnknownValue.STRING

View File

@ -259,7 +259,7 @@ namespace Google.Protobuf
output.WriteTag(TestMap.MapInt32ForeignMessageFieldNumber, WireFormat.WireType.LengthDelimited);
var nestedMessage = new ForeignMessage { C = 20 };
// Size of the entry (tag, size written by WriteMessage, data written by WriteMessage)
output.WriteRawVarint32((uint)(nestedMessage.CalculateSize() + 3));
output.WriteLength(2 + nestedMessage.CalculateSize());
output.WriteTag(2, WireFormat.WireType.LengthDelimited);
output.WriteMessage(nestedMessage);
output.Flush();
@ -283,7 +283,7 @@ namespace Google.Protobuf
// Each field can be represented in a single byte, with a single byte tag.
// Total message size: 6 bytes.
output.WriteRawVarint32(6);
output.WriteLength(6);
output.WriteTag(1, WireFormat.WireType.Varint);
output.WriteInt32(key);
output.WriteTag(2, WireFormat.WireType.Varint);
@ -309,7 +309,7 @@ namespace Google.Protobuf
// Each field can be represented in a single byte, with a single byte tag.
// Total message size: 4 bytes.
output.WriteRawVarint32(4);
output.WriteLength(4);
output.WriteTag(2, WireFormat.WireType.Varint);
output.WriteInt32(value);
output.WriteTag(1, WireFormat.WireType.Varint);
@ -335,7 +335,7 @@ namespace Google.Protobuf
var key1 = 10;
var value1 = 20;
output.WriteTag(TestMap.MapInt32Int32FieldNumber, WireFormat.WireType.LengthDelimited);
output.WriteRawVarint32(4);
output.WriteLength(4);
output.WriteTag(1, WireFormat.WireType.Varint);
output.WriteInt32(key1);
output.WriteTag(2, WireFormat.WireType.Varint);
@ -345,7 +345,7 @@ namespace Google.Protobuf
var key2 = "a";
var value2 = "b";
output.WriteTag(TestMap.MapStringStringFieldNumber, WireFormat.WireType.LengthDelimited);
output.WriteRawVarint32(6); // 3 bytes per entry: tag, size, character
output.WriteLength(6); // 3 bytes per entry: tag, size, character
output.WriteTag(1, WireFormat.WireType.LengthDelimited);
output.WriteString(key2);
output.WriteTag(2, WireFormat.WireType.LengthDelimited);
@ -355,7 +355,7 @@ namespace Google.Protobuf
var key3 = 15;
var value3 = 25;
output.WriteTag(TestMap.MapInt32Int32FieldNumber, WireFormat.WireType.LengthDelimited);
output.WriteRawVarint32(4);
output.WriteLength(4);
output.WriteTag(1, WireFormat.WireType.Varint);
output.WriteInt32(key3);
output.WriteTag(2, WireFormat.WireType.Varint);
@ -383,7 +383,7 @@ namespace Google.Protobuf
// First entry
output.WriteTag(TestMap.MapInt32Int32FieldNumber, WireFormat.WireType.LengthDelimited);
output.WriteRawVarint32(4);
output.WriteLength(4);
output.WriteTag(1, WireFormat.WireType.Varint);
output.WriteInt32(key);
output.WriteTag(2, WireFormat.WireType.Varint);
@ -391,7 +391,7 @@ namespace Google.Protobuf
// Second entry - same key, different value
output.WriteTag(TestMap.MapInt32Int32FieldNumber, WireFormat.WireType.LengthDelimited);
output.WriteRawVarint32(4);
output.WriteLength(4);
output.WriteTag(1, WireFormat.WireType.Varint);
output.WriteInt32(key);
output.WriteTag(2, WireFormat.WireType.Varint);
@ -619,5 +619,15 @@ namespace Google.Protobuf
var empty = Empty.Parser.ParseFrom(data);
Assert.AreEqual(new Empty(), empty);
}
// This was originally seen as a conformance test failure.
[Test]
public void TruncatedMessageFieldThrows()
{
// 130, 3 is the message tag
// 1 is the data length - but there's no data.
var data = new byte[] { 130, 3, 1 };
Assert.Throws<InvalidProtocolBufferException>(() => TestAllTypes.Parser.ParseFrom(data));
}
}
}

View File

@ -54,13 +54,37 @@ namespace Google.Protobuf
/// </remarks>
public sealed class CodedInputStream
{
/// <summary>
/// Buffer of data read from the stream or provided at construction time.
/// </summary>
private readonly byte[] buffer;
/// <summary>
/// The number of valid bytes in the buffer.
/// </summary>
private int bufferSize;
private int bufferSizeAfterLimit = 0;
/// <summary>
/// The position within the current buffer (i.e. the next byte to read)
/// </summary>
private int bufferPos = 0;
/// <summary>
/// The stream to read further input from, or null if the byte array buffer was provided
/// directly on construction, with no further data available.
/// </summary>
private readonly Stream input;
/// <summary>
/// The last tag we read. 0 indicates we've read to the end of the stream
/// (or haven't read anything yet).
/// </summary>
private uint lastTag = 0;
/// <summary>
/// The next tag, used to store the value read by PeekTag.
/// </summary>
private uint nextTag = 0;
private bool hasNextTag = false;
@ -456,6 +480,11 @@ namespace Google.Protobuf
++recursionDepth;
builder.MergeFrom(this);
CheckLastTagWas(0);
// Check that we've read exactly as much data as expected.
if (!ReachedLimit)
{
throw InvalidProtocolBufferException.TruncatedMessage();
}
--recursionDepth;
PopLimit(oldLimit);
}