[Proto] fix: negative signed integers corrupt varint encoding (#917) - #918
Open
Deliay wants to merge 1 commit into
Open
[Proto] fix: negative signed integers corrupt varint encoding (#917)#918Deliay wants to merge 1 commit into
Deliay wants to merge 1 commit into
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
关联 Issue
Fixes #917
问题现象
含有符号整型字段(如
int Type = -1)的对象经过ProtoSerializer.Serialize→Deserialize往返后解析失败,抛出ArgumentOutOfRangeException(CreateSpan/SkipField越界)等异常。调查结果
通过编写单元测试复现后,定位到两处问题:
根因:
ProtoWriter.EncodeVarInt<T>单字节快路径误判(Lagrange.Proto/Primitives/ProtoWriter.cs)负数会错误进入单字节快路径,被
byte.CreateTruncating(value)截断为0xFF写入——这是一个 continuation bit 置位的非法 varint 起始字节,导致整个流的后续解析全部错乱。关联隐患:
ProtoHelper.GetVarIntLength长度计算数组越界(Lagrange.Proto/Utility/ProtoHelper.cs)长度计算使用
uint/ulong.CreateSaturating(value),负数被钳到 0,LeadingZeroCount(0) = 32(或 64),导致VarIntLengths32[32]数组越界抛IndexOutOfRangeException。嵌套对象序列化的Measure路径(ProtoSerializableConverter.Write→MeasureHandler)会稳定触发,已用嵌套对象的测试用例验证。修复方案
ProtoWriter.EncodeVarInt<T>:快路径条件改为ulong.CreateTruncating(value) < 0x80。负数转为无符号位模式后必然 ≥ 0x80,走正常多字节编码路径(int -1→ 5 字节 varintFF FF FF FF 0F;long -1→ 10 字节),解码端按截断语义可正确还原。ProtoHelper.GetVarIntLength:CreateSaturating→CreateTruncating,负数按位模式计算前导零,得到与实际编码一致的长度(32 位负数 → 5,64 位负数 → 10)。注:本库对负
int32编码为 5 字节 varint 而非 protobuf 规范的 10 字节符号扩展形式,但解码端为截断读取,两种形式均可正确还原,库内自洽,属于既有设计,本次未改动。测试
新增
Lagrange.Proto.Test/NegativeVarIntTest.cs,共 4 个用例:TestNegativeInt_Roundtrip_Reflection:issue 原始复现场景(反射路径Serialize/Deserialize)TestNegativeInt_Roundtrip_SourceGenerated:同场景走源生成路径(SerializeProtoPackable)TestNegativeInt_NestedObject_Roundtrip:嵌套对象含负数字段(覆盖Measure/GetVarIntLength路径)TestNegativeValues_Boundary:sbyte/short/int/long的-1与MinValue边界值往返修复前 4 个用例全部失败(复现成功),修复后全部通过;
Lagrange.Proto.Test完整套件 221 个测试全部通过,无回归。