Reject varint payloads exceeding u64 range The 10th varint byte (shift=63) can only contribute 1 bit of payload. Previously, bytes like 0x02 at this position silently truncated the extra bit and returned a wrong value. Now decode_varint checks payload > 1 at shift=63 and returns InvalidData. Add test_varint_above_u64_max_returns_error: [0xFF; 9] + [0x02] is rejected as exceeding u64. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
diff --git a/core/src/io.rs b/core/src/io.rs index 4f917a3..5cb491e 100644 --- a/core/src/io.rs +++ b/core/src/io.rs
@@ -109,12 +109,19 @@ } let b = buf[*pos] as u64; *pos += 1; - val |= (b & 0x7F) << shift; + let payload = b & 0x7F; + if shift == 63 && payload > 1 { + return Err(io::Error::new( + io::ErrorKind::InvalidData, + "varint exceeds u64 range", + )); + } + val |= payload << shift; if b & 0x80 == 0 { break; } shift += 7; - if shift >= 64 { + if shift > 63 { return Err(io::Error::new( io::ErrorKind::InvalidData, "varint exceeds 64 bits", @@ -758,6 +765,14 @@ } #[test] + fn test_varint_above_u64_max_returns_error() { + let mut bytes = vec![0xFFu8; 9]; + bytes.push(0x02); // 10th byte with payload > 1 at shift=63 + let mut pos = 0; + assert!(decode_varint(&bytes, &mut pos).is_err()); + } + + #[test] fn test_delta_varint_ids_roundtrip() { let ids = vec![3i64, 7, 12, 15, 23, 100, 200]; let (base, encoded) = encode_delta_varint_ids(&ids);