diff options
| -rw-r--r-- | src/BinaryFormat/Decoder.php | 58 | ||||
| -rw-r--r-- | tests/src/SpecTestsuites/SpecTestsuiteBase.php | 23 |
2 files changed, 45 insertions, 36 deletions
diff --git a/src/BinaryFormat/Decoder.php b/src/BinaryFormat/Decoder.php index ce09b81..4b47b19 100644 --- a/src/BinaryFormat/Decoder.php +++ b/src/BinaryFormat/Decoder.php @@ -407,10 +407,7 @@ final class Decoder private function decodeMem(): Mem { - $type = $this->decodeMemType(); - return new Mem( - $type, - ); + return new Mem($this->decodeMemType()); } private function decodeGlobal(): Global_ @@ -1041,46 +1038,49 @@ final class Decoder private function decodeUnsignedLeb128(int $maxBits): int { $result = 0; - $shiftBits = 0; - while (true) { + for ($shiftBits = 0; $shiftBits < $maxBits; $shiftBits += 7) { $b = $this->decodeByte(); + $leftBitsCount = $maxBits - $shiftBits; + if ($leftBitsCount < 7) { + if ((($b & 0b01111111) >> $leftBitsCount) !== 0) { + throw new InvalidBinaryFormatException("unsigned leb128 ($maxBits): too large"); + } + } $result |= ($b & 0b01111111) << $shiftBits; - if ($b < 0b10000000) { + if (($b & 0b10000000) === 0) { return $result; } - $shiftBits += 7; - if ($maxBits <= $shiftBits) { - throw new InvalidBinaryFormatException("unsigned leb128"); - } } + throw new InvalidBinaryFormatException("unsigned leb128 ($maxBits): too large"); } - private function decodeSignedLeb128(int $bits): int + private function decodeSignedLeb128(int $maxBits): int { $result = 0; - $shiftBits = 0; - while (true) { + for ($shiftBits = 0; $shiftBits < $maxBits; $shiftBits += 7) { $b = $this->decodeByte(); - $result |= ($b & 0b01111111) << $shiftBits; - $shiftBits += 7; - if ($b < 0b10000000) { - if (($b & 0b01000000) !== 0) { - if ($bits === 32) { - $result |= (-1) ^ (1 << $shiftBits) - 1; - } else { - if ($shiftBits < $bits - 1) { - $result |= -(1 << $shiftBits); - } else { - $result |= 1 << $shiftBits; - } + $leftBitsCount = $maxBits - $shiftBits; + if ($leftBitsCount < 7) { + if (($b & (1 << ($leftBitsCount - 1))) === 0) { + if ((($b & 0b01111111) >> $leftBitsCount) !== 0) { + throw new InvalidBinaryFormatException("signed leb128 ($maxBits): too large"); + } + } else { + if ((($b & 0b01111111) >> $leftBitsCount) + 1 !== (1 << (7 - $leftBitsCount))) { + throw new InvalidBinaryFormatException("signed leb128 ($maxBits): too large"); } } - return $result; } - if ($bits <= $shiftBits) { - throw new InvalidBinaryFormatException("signed leb128"); + $result |= ($b & 0b01111111) << $shiftBits; + if (($b & 0b10000000) === 0) { + if (($b & 0b01000000) === 0) { + return $result; + } else { + return $result | (~0 << ($shiftBits + 7)); + } } } + throw new InvalidBinaryFormatException("signed leb128 ($maxBits): too large"); } /** diff --git a/tests/src/SpecTestsuites/SpecTestsuiteBase.php b/tests/src/SpecTestsuites/SpecTestsuiteBase.php index b215a16..285ce12 100644 --- a/tests/src/SpecTestsuites/SpecTestsuiteBase.php +++ b/tests/src/SpecTestsuites/SpecTestsuiteBase.php @@ -194,7 +194,21 @@ abstract class SpecTestsuiteBase extends TestCase for ($i = 0; $i < count($expectedResults); $i++) { $expectedResult = $expectedResults[$i]; $actualResult = $actualResults[$i]; - if ($expectedResult['type'] === 'f32') { + if ($expectedResult['type'] === 'i32') { + $expectedValue = unpack('l', pack('l', (int)$expectedResult['value']))[1]; + $this->assertSame( + $expectedValue, + $actualResult, + "result $i mismatch" . $message, + ); + } elseif ($expectedResult['type'] === 'i64') { + $expectedValue = unpack('q', pack('q', (int)$expectedResult['value']))[1]; + $this->assertSame( + $expectedValue, + $actualResult, + "result $i mismatch" . $message, + ); + } elseif ($expectedResult['type'] === 'f32') { $expectedValue = unpack('g', pack('l', (int)$expectedResult['value']))[1]; if (is_nan($expectedValue)) { // @todo check NaN bit pattern. @@ -225,12 +239,7 @@ abstract class SpecTestsuiteBase extends TestCase ); } } else { - $expectedValue = (int)$expectedResult['value']; - $this->assertSame( - $expectedValue, - $actualResult, - "result $i mismatch" . $message, - ); + $this->assertTrue(false, "unknown result type: {$expectedResult['type']}"); } } } |
