aboutsummaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
authornsfisis <nsfisis@gmail.com>2024-04-28 20:38:01 +0900
committernsfisis <nsfisis@gmail.com>2024-04-29 10:45:58 +0900
commite397e0e356384cedd20d40d46cf1a8ed8aadad24 (patch)
tree3cf8a044985e7ff79cba5e6599407a32ec1957c5 /src
parent3cccb2957e219298ccb4d6958449307cec9043e1 (diff)
downloadphp-waddiwasi-e397e0e356384cedd20d40d46cf1a8ed8aadad24.tar.gz
php-waddiwasi-e397e0e356384cedd20d40d46cf1a8ed8aadad24.tar.zst
php-waddiwasi-e397e0e356384cedd20d40d46cf1a8ed8aadad24.zip
fix: validate binary format
Diffstat (limited to 'src')
-rw-r--r--src/BinaryFormat/Decoder.php34
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;
+ }
}