Skip to content

Commit 106b9f1

Browse files
authored
VarInt: fix data loss when reading large varlongs (#17)
The result of the bitwise AND was an integer, which when shifted left by more than 31, results in zero. This led to incorrect decoding of varlongs larger than 5 bytes.
1 parent 4a93947 commit 106b9f1

File tree

2 files changed

+34
-1
lines changed

2 files changed

+34
-1
lines changed

Serializers.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ static inline bool readUnsignedVarInt(unsigned char* bytes, size_t used, size_t&
112112
}
113113

114114
auto byte = bytes[offset++];
115-
result |= (byte & VarIntConstants::VALUE_MASK) << shift;
115+
result |= static_cast<TValue>(byte & VarIntConstants::VALUE_MASK) << shift;
116116
if ((byte & VarIntConstants::MSB_MASK) == 0) {
117117
return true;
118118
}

tests/read-varint-unsigned-long.phpt

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
--TEST--
2+
Test that reading varlongs (> 5 bytes) works correctly
3+
--DESCRIPTION--
4+
The result of the bitwise AND operation has a result of int regardless of the input.
5+
When shifting this to the left by more than 31, the result will be 0 if not explicitly
6+
casted to a larger type before shifting. For varlongs this led to all bits above 32
7+
to be discarded. This test verifies the result of the fix.
8+
--FILE--
9+
<?php
10+
11+
use pmmp\encoding\ByteBuffer;
12+
use pmmp\encoding\VarInt;
13+
14+
//unsigned
15+
$buffer_2 = str_repeat("\x81", 8) . "\x01";
16+
$buf_2 = new ByteBuffer($buffer_2);
17+
var_dump(VarInt::readUnsignedLong($buf_2));
18+
19+
//negative signed
20+
$buffer_3 = str_repeat("\x81", 8) . "\x01";
21+
$buf_3 = new ByteBuffer($buffer_3);
22+
var_dump(VarInt::readSignedLong($buf_3));
23+
24+
//positive signed
25+
$buffer_3 = "\x80" . str_repeat("\x81", 7) . "\x01";
26+
$buf_3 = new ByteBuffer($buffer_3);
27+
var_dump(VarInt::readSignedLong($buf_3));
28+
29+
?>
30+
--EXPECT--
31+
int(72624976668147841)
32+
int(-36312488334073921)
33+
int(36312488334073920)

0 commit comments

Comments
 (0)