Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix parsing negative Int32Value that crosses segment boundary #8035

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
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