Commit f23869c6 authored by Paul Yang's avatar Paul Yang

Bug fix: When encoding, negative int32 values should be padded to int64 (#2660)

in order to be wire compatible.
parent 014a5507
...@@ -10759,7 +10759,7 @@ static size_t encode_strbuf(void *c, const void *hd, const char *buf, ...@@ -10759,7 +10759,7 @@ static size_t encode_strbuf(void *c, const void *hd, const char *buf,
T(double, double, dbl2uint64, encode_fixed64) T(double, double, dbl2uint64, encode_fixed64)
T(float, float, flt2uint32, encode_fixed32) T(float, float, flt2uint32, encode_fixed32)
T(int64, int64_t, uint64_t, encode_varint) T(int64, int64_t, uint64_t, encode_varint)
T(int32, int32_t, uint32_t, encode_varint) T(int32, int32_t, int64_t, encode_varint)
T(fixed64, uint64_t, uint64_t, encode_fixed64) T(fixed64, uint64_t, uint64_t, encode_fixed64)
T(fixed32, uint32_t, uint32_t, encode_fixed32) T(fixed32, uint32_t, uint32_t, encode_fixed32)
T(bool, bool, bool, encode_varint) T(bool, bool, bool, encode_varint)
......
...@@ -403,11 +403,15 @@ class GPBWire ...@@ -403,11 +403,15 @@ class GPBWire
return self::varint32Size($tag); return self::varint32Size($tag);
} }
public static function varint32Size($value) public static function varint32Size($value, $sign_extended = false)
{ {
if ($value < 0) { if ($value < 0) {
if ($sign_extended) {
return 10;
} else {
return 5; return 5;
} }
}
if ($value < (1 << 7)) { if ($value < (1 << 7)) {
return 1; return 1;
} }
......
...@@ -70,7 +70,6 @@ class InputStream ...@@ -70,7 +70,6 @@ class InputStream
private $total_bytes_read; private $total_bytes_read;
const MAX_VARINT_BYTES = 10; const MAX_VARINT_BYTES = 10;
const MAX_VARINT32_BYTES = 5;
const DEFAULT_RECURSION_LIMIT = 100; const DEFAULT_RECURSION_LIMIT = 100;
const DEFAULT_TOTAL_BYTES_LIMIT = 33554432; // 32 << 20, 32MB const DEFAULT_TOTAL_BYTES_LIMIT = 33554432; // 32 << 20, 32MB
......
...@@ -772,9 +772,11 @@ class Message ...@@ -772,9 +772,11 @@ class Message
case GPBType::SFIXED64: case GPBType::SFIXED64:
$size += 8; $size += 8;
break; break;
case GPBType::UINT32:
case GPBType::INT32: case GPBType::INT32:
case GPBType::ENUM: case GPBType::ENUM:
$size += GPBWire::varint32Size($value, true);
break;
case GPBType::UINT32:
$size += GPBWire::varint32Size($value); $size += GPBWire::varint32Size($value);
break; break;
case GPBType::UINT64: case GPBType::UINT64:
......
...@@ -39,7 +39,6 @@ class OutputStream ...@@ -39,7 +39,6 @@ class OutputStream
private $buffer_size; private $buffer_size;
private $current; private $current;
const MAX_VARINT32_BYTES = 5;
const MAX_VARINT64_BYTES = 10; const MAX_VARINT64_BYTES = 10;
public function __construct($size) public function __construct($size)
...@@ -56,8 +55,8 @@ class OutputStream ...@@ -56,8 +55,8 @@ class OutputStream
public function writeVarint32($value) public function writeVarint32($value)
{ {
$bytes = str_repeat(chr(0), self::MAX_VARINT32_BYTES); $bytes = str_repeat(chr(0), self::MAX_VARINT64_BYTES);
$size = self::writeVarintToArray($value, $bytes, true); $size = self::writeVarintToArray($value, $bytes);
return $this->writeRaw($bytes, $size); return $this->writeRaw($bytes, $size);
} }
...@@ -102,21 +101,17 @@ class OutputStream ...@@ -102,21 +101,17 @@ class OutputStream
return true; return true;
} }
private static function writeVarintToArray($value, &$buffer, $trim = false) private static function writeVarintToArray($value, &$buffer)
{ {
$current = 0; $current = 0;
$high = 0; $high = 0;
$low = 0; $low = 0;
if (PHP_INT_SIZE == 4) { if (PHP_INT_SIZE == 4) {
GPBUtil::divideInt64ToInt32($value, $high, $low, $trim); GPBUtil::divideInt64ToInt32($value, $high, $low);
} else {
if ($trim) {
$low = $value & 0xFFFFFFFF;
} else { } else {
$low = $value; $low = $value;
} }
}
while ($low >= 0x80 || $low < 0) { while ($low >= 0x80 || $low < 0) {
$buffer[$current] = chr($low | 0x80); $buffer[$current] = chr($low | 0x80);
......
...@@ -190,6 +190,27 @@ class EncodeDecodeTest extends TestBase ...@@ -190,6 +190,27 @@ class EncodeDecodeTest extends TestBase
$m->mergeFromString($data); $m->mergeFromString($data);
} }
public function testEncodeNegativeInt32()
{
$m = new TestMessage();
$m->setOptionalInt32(-1);
$data = $m->encode();
$this->assertSame("08ffffffffffffffffff01", bin2hex($data));
}
public function testDecodeNegativeInt32()
{
$m = new TestMessage();
$this->assertEquals(0, $m->getOptionalInt32());
$m->decode(hex2bin("08ffffffffffffffffff01"));
$this->assertEquals(-1, $m->getOptionalInt32());
$m = new TestMessage();
$this->assertEquals(0, $m->getOptionalInt32());
$m->decode(hex2bin("08ffffffff0f"));
$this->assertEquals(-1, $m->getOptionalInt32());
}
# TODO(teboring): Add test back when php implementation is ready for json # TODO(teboring): Add test back when php implementation is ready for json
# encode/decode. # encode/decode.
# public function testJsonEncode() # public function testJsonEncode()
......
...@@ -469,6 +469,11 @@ class ImplementationTest extends TestBase ...@@ -469,6 +469,11 @@ class ImplementationTest extends TestBase
$output = new OutputStream(3); $output = new OutputStream(3);
$output->writeVarint32(16384); $output->writeVarint32(16384);
$this->assertSame(hex2bin('808001'), $output->getData()); $this->assertSame(hex2bin('808001'), $output->getData());
// Negative numbers are padded to be compatible with int64.
$output = new OutputStream(10);
$output->writeVarint32(-43);
$this->assertSame(hex2bin('D5FFFFFFFFFFFFFFFF01'), $output->getData());
} }
public function testWriteVarint64() public function testWriteVarint64()
...@@ -496,13 +501,13 @@ class ImplementationTest extends TestBase ...@@ -496,13 +501,13 @@ class ImplementationTest extends TestBase
{ {
$m = new TestMessage(); $m = new TestMessage();
TestUtil::setTestMessage($m); TestUtil::setTestMessage($m);
$this->assertSame(481, $m->byteSize()); $this->assertSame(506, $m->byteSize());
} }
public function testPackedByteSize() public function testPackedByteSize()
{ {
$m = new TestPackedMessage(); $m = new TestPackedMessage();
TestUtil::setTestPackedMessage($m); TestUtil::setTestPackedMessage($m);
$this->assertSame(156, $m->byteSize()); $this->assertSame(166, $m->byteSize());
} }
} }
...@@ -321,7 +321,7 @@ class TestUtil ...@@ -321,7 +321,7 @@ class TestUtil
public static function getGoldenTestMessage() public static function getGoldenTestMessage()
{ {
return hex2bin( return hex2bin(
"08D6FFFFFF0F" . "08D6FFFFFFFFFFFFFFFF01" .
"10D5FFFFFFFFFFFFFFFF01" . "10D5FFFFFFFFFFFFFFFF01" .
"182A" . "182A" .
"202B" . "202B" .
...@@ -339,8 +339,8 @@ class TestUtil ...@@ -339,8 +339,8 @@ class TestUtil
"800101" . "800101" .
"8A01020821" . "8A01020821" .
"F801D6FFFFFF0F" . "F801D6FFFFFFFFFFFFFFFF01" .
"F801CCFFFFFF0F" . "F801CCFFFFFFFFFFFFFFFF01" .
"8002D5FFFFFFFFFFFFFFFF01" . "8002D5FFFFFFFFFFFFFFFF01" .
"8002CBFFFFFFFFFFFFFFFF01" . "8002CBFFFFFFFFFFFFFFFF01" .
"88022A" . "88022A" .
...@@ -374,7 +374,7 @@ class TestUtil ...@@ -374,7 +374,7 @@ class TestUtil
"FA02020822" . "FA02020822" .
"FA02020823" . "FA02020823" .
"BA040C08C2FFFFFF0F10C2FFFFFF0F" . "BA041608C2FFFFFFFFFFFFFFFF0110C2FFFFFFFFFFFFFFFF01" .
"C2041608C1FFFFFFFFFFFFFFFF0110C1FFFFFFFFFFFFFFFF01" . "C2041608C1FFFFFFFFFFFFFFFF0110C1FFFFFFFFFFFFFFFF01" .
"CA0404083E103E" . "CA0404083E103E" .
"D20404083F103F" . "D20404083F103F" .
...@@ -489,7 +489,7 @@ class TestUtil ...@@ -489,7 +489,7 @@ class TestUtil
public static function getGoldenTestPackedMessage() public static function getGoldenTestPackedMessage()
{ {
return hex2bin( return hex2bin(
"D2050AD6FFFFFF0FCCFFFFFF0F" . "D20514D6FFFFFFFFFFFFFFFF01CCFFFFFFFFFFFFFFFF01" .
"DA0514D5FFFFFFFFFFFFFFFF01CBFFFFFFFFFFFFFFFF01" . "DA0514D5FFFFFFFFFFFFFFFF01CBFFFFFFFFFFFFFFFF01" .
"E205022A34" . "E205022A34" .
"EA05022B35" . "EA05022B35" .
...@@ -509,7 +509,7 @@ class TestUtil ...@@ -509,7 +509,7 @@ class TestUtil
public static function getGoldenTestUnpackedMessage() public static function getGoldenTestUnpackedMessage()
{ {
return hex2bin( return hex2bin(
"D005D6FFFFFF0FD005CCFFFFFF0F" . "D005D6FFFFFFFFFFFFFFFF01D005CCFFFFFFFFFFFFFFFF01" .
"D805D5FFFFFFFFFFFFFFFF01D805CBFFFFFFFFFFFFFFFF01" . "D805D5FFFFFFFFFFFFFFFF01D805CBFFFFFFFFFFFFFFFF01" .
"E0052AE00534" . "E0052AE00534" .
"E8052BE80535" . "E8052BE80535" .
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment