aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
-rw-r--r--src/BinaryFormat/Decoder.php58
-rw-r--r--tests/src/SpecTestsuites/SpecTestsuiteBase.php23
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']}");
}
}
}