Skip to content

Commit

Permalink
Merge pull request #8035 from JamesNK/jamesnk/int32wrapper-blocksize
Browse files Browse the repository at this point in the history
Fix parsing negative Int32Value that crosses segment boundary
  • Loading branch information
jtattermusch committed Nov 13, 2020
2 parents 397d34c + fdf4ef6 commit 012fe85
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 4 deletions.
19 changes: 19 additions & 0 deletions csharp/src/Google.Protobuf.Test/CodedInputStreamTest.cs
Expand Up @@ -343,6 +343,25 @@ public void ReadWholeMessage_VaryingBlockSizes_FromSequence()
}
}

[Test]
public void ReadInt32Wrapper_VariableBlockSizes()
{
byte[] rawBytes = new byte[] { 202, 1, 11, 8, 254, 255, 255, 255, 255, 255, 255, 255, 255, 1 };

for (int blockSize = 1; blockSize <= rawBytes.Length; blockSize++)
{
ReadOnlySequence<byte> data = ReadOnlySequenceFactory.CreateWithContent(rawBytes, blockSize);
AssertReadFromParseContext(data, (ref ParseContext ctx) =>
{
ctx.ReadTag();
var value = ParsingPrimitivesWrappers.ReadInt32Wrapper(ref ctx);
Assert.AreEqual(-2, value);
}, true);
}
}

[Test]
public void ReadHugeBlob()
{
Expand Down
22 changes: 22 additions & 0 deletions csharp/src/Google.Protobuf.Test/WellKnownTypes/WrappersTest.cs
Expand Up @@ -87,6 +87,28 @@ public void NonDefaultSingleValues()
});
}

[Test]
public void NegativeSingleValues()
{
var message = new TestWellKnownTypes
{
FloatField = -12.5f,
DoubleField = -12.25d,
Int32Field = -1,
Int64Field = -2
};

MessageParsingHelpers.AssertWritingMessage(message);

MessageParsingHelpers.AssertRoundtrip(TestWellKnownTypes.Parser, message, parsed =>
{
Assert.AreEqual(-12.5f, parsed.FloatField);
Assert.AreEqual(-12.25d, parsed.DoubleField);
Assert.AreEqual(-1, parsed.Int32Field);
Assert.AreEqual(-2L, parsed.Int64Field);
});
}

[Test]
public void NonNullDefaultIsPreservedThroughSerialization()
{
Expand Down
10 changes: 6 additions & 4 deletions csharp/src/Google.Protobuf/ParsingPrimitivesWrappers.cs
Expand Up @@ -160,8 +160,11 @@ internal static class ParsingPrimitivesWrappers

internal static uint? ReadUInt32Wrapper(ref ReadOnlySpan<byte> buffer, ref ParserInternalState state)
{
// length:1 + tag:1 + value:5(varint32-max) = 7 bytes
if (state.bufferPos + 7 <= state.bufferSize)
// field=1, type=varint = tag of 8
const int expectedTag = 8;
// length:1 + tag:1 + value:10(varint64-max) = 12 bytes
// Value can be 64 bits for negative integers
if (state.bufferPos + 12 <= state.bufferSize)
{
// The entire wrapper message is already contained in `buffer`.
int pos0 = state.bufferPos;
Expand All @@ -177,8 +180,7 @@ internal static class ParsingPrimitivesWrappers
return ReadUInt32WrapperSlow(ref buffer, ref state);
}
int finalBufferPos = state.bufferPos + length;
// field=1, type=varint = tag of 8
if (buffer[state.bufferPos++] != 8)
if (buffer[state.bufferPos++] != expectedTag)
{
state.bufferPos = pos0;
return ReadUInt32WrapperSlow(ref buffer, ref state);
Expand Down

0 comments on commit 012fe85

Please sign in to comment.