Skip to content

Commit 5cdef4d

Browse files
Pure PHP: cleanly ignore bits in the 10-byte varints with bit above LSB set.
Still error out if the MSB in that is set (implying it would be an 11+ byte varint). This is not a functional change; today this flow is just silently 'weird' since php silently promotes the type to double instead of int64 when it sees the the bits are too large. PiperOrigin-RevId: 899065019
1 parent 0cf9608 commit 5cdef4d

2 files changed

Lines changed: 29 additions & 1 deletion

File tree

php/src/Google/Protobuf/Internal/CodedInputStream.php

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,15 @@ public function readVarint64(&$var)
138138
return false;
139139
}
140140
$b = ord($this->buffer[$this->current]);
141+
if ($count === 9) {
142+
// If the 10th byte has a continuation bit set, immediately
143+
// fail.
144+
if ($b & 0x80) {
145+
return false;
146+
}
147+
// Discard bits above bit 0 in the 10th byte.
148+
$b &= 0x01;
149+
}
141150
$bits = 7 * $count;
142151
if ($bits >= 32) {
143152
$high |= (($b & 0x7F) << ($bits - 32));
@@ -170,7 +179,20 @@ public function readVarint64(&$var)
170179
}
171180

172181
$byte = ord($this->buffer[$this->current]);
173-
$result |= ($byte & 0x7f) << $shift;
182+
183+
if ($count === 9) {
184+
// If the 10th byte has a continuation bit set, fail.
185+
if ($byte & 0x80) {
186+
return false;
187+
}
188+
// Silently discards bits above bit 0 in the 10th byte.
189+
if ($byte & 1) {
190+
$result |= PHP_INT_MIN;
191+
}
192+
} else {
193+
$result |= ($byte & 0x7f) << $shift;
194+
}
195+
174196
$shift += 7;
175197
$this->advance(1);
176198
$count += 1;

php/tests/PhpImplementationTest.php

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,12 @@ public function testReadVarint64()
383383
$input = new CodedInputStream(hex2bin('8080808080808080808001'));
384384
$this->assertFalse($input->readVarint64($var));
385385

386+
// 10-byte varint with high bits set in the 10th byte.
387+
// Bits above bit 0 in the 10th byte are discarded.
388+
$input = new CodedInputStream(hex2bin('87808080808080808002'));
389+
$this->assertTrue($input->readVarint64($var));
390+
$this->assertSame(7, $var);
391+
386392
// Corrupted varint.
387393
$input = new CodedInputStream(hex2bin('808080'));
388394
$this->assertFalse($input->readVarint64($var));

0 commit comments

Comments
 (0)