diff options
| author | nsfisis <nsfisis@gmail.com> | 2024-04-28 20:38:01 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2024-04-29 10:45:58 +0900 |
| commit | e397e0e356384cedd20d40d46cf1a8ed8aadad24 (patch) | |
| tree | 3cf8a044985e7ff79cba5e6599407a32ec1957c5 /src/BinaryFormat/Decoder.php | |
| parent | 3cccb2957e219298ccb4d6958449307cec9043e1 (diff) | |
| download | php-waddiwasi-e397e0e356384cedd20d40d46cf1a8ed8aadad24.tar.gz php-waddiwasi-e397e0e356384cedd20d40d46cf1a8ed8aadad24.tar.zst php-waddiwasi-e397e0e356384cedd20d40d46cf1a8ed8aadad24.zip | |
fix: validate binary format
Diffstat (limited to 'src/BinaryFormat/Decoder.php')
| -rw-r--r-- | src/BinaryFormat/Decoder.php | 34 |
1 files changed, 33 insertions, 1 deletions
diff --git a/src/BinaryFormat/Decoder.php b/src/BinaryFormat/Decoder.php index c61fade..ce09b81 100644 --- a/src/BinaryFormat/Decoder.php +++ b/src/BinaryFormat/Decoder.php @@ -33,11 +33,13 @@ use Nsfisis\Waddiwasi\Structure\Types\ResultType; use Nsfisis\Waddiwasi\Structure\Types\TableType; use Nsfisis\Waddiwasi\Structure\Types\ValType; use Nsfisis\Waddiwasi\Structure\Types\VecType; +use function array_reduce; use function assert; use function count; use function get_class; use function in_array; use function is_float; +use function is_int; use function ord; use function strlen; @@ -76,12 +78,19 @@ final class Decoder throw new InvalidBinaryFormatException("eof"); } if ($dataCount === null) { - // TODO: dataidx(code) must be empty + foreach ($codes as $code) { + if ($this->countDataIndicesUsedInCode($code) !== 0) { + throw new InvalidBinaryFormatException("datacount section is required"); + } + } } else { if (count($datas) !== $dataCount) { throw new InvalidBinaryFormatException("datasec"); } } + if (count($typeIndices) !== count($codes)) { + throw new InvalidBinaryFormatException("number of funcs and codes does not match"); + } $funcs = []; foreach ($typeIndices as $i => $type) { @@ -597,6 +606,10 @@ final class Decoder private function decodeLocals(): Locals { $count = $this->decodeU32(); + // @todo Provide a way to configure the limit. + if (1024 < $count) { + throw new InvalidBinaryFormatException("too many local variables"); + } $type = $this->decodeValType(); return new Locals( $count, @@ -1172,4 +1185,23 @@ final class Decoder } return $s; } + + /** + * @return 0|positive-int + */ + private function countDataIndicesUsedInCode(Code $code): int + { + $result = array_reduce( + $code->body, + fn ($acc, $instr) => $acc + match ($instr::class) { + Instrs\Memory\DataDrop::class => 1, + Instrs\Memory\MemoryInit::class => 1, + default => 0, + }, + 0, + ); + assert(is_int($result), '$result is guaranteed not to exceed the maximum value of an integer because the number of instructions in $code is limited'); + assert(0 <= $result, '$result is guaranteed to be non-negative because it is the sum of non-negative integers'); + return $result; + } } |
