diff options
author | Alon Zakai <azakai@google.com> | 2024-11-07 09:04:36 -0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-11-07 09:04:36 -0800 |
commit | e409660a5b4dff9891ddb7d4786cc510a5761d3e (patch) | |
tree | 7a6c907f6aaca91f72c0a4e0642c57ad3dd1cd29 | |
parent | 0af8f1f2d7ff304837ee0698265c84985420fcae (diff) | |
download | binaryen-e409660a5b4dff9891ddb7d4786cc510a5761d3e.tar.gz binaryen-e409660a5b4dff9891ddb7d4786cc510a5761d3e.tar.bz2 binaryen-e409660a5b4dff9891ddb7d4786cc510a5761d3e.zip |
[wasm64] Make interpreter table methods operate on Address, not Index (#7062)
This allows 64-bit bounds checking to work properly.
-rw-r--r-- | src/shell-interface.h | 7 | ||||
-rw-r--r-- | src/tools/execution-results.h | 4 | ||||
-rw-r--r-- | src/tools/wasm-ctor-eval.cpp | 7 | ||||
-rw-r--r-- | src/wasm-interpreter.h | 34 | ||||
-rw-r--r-- | test/lit/exec/table64.wast | 55 |
5 files changed, 68 insertions, 39 deletions
diff --git a/src/shell-interface.h b/src/shell-interface.h index 6101df29a..35f5772cf 100644 --- a/src/shell-interface.h +++ b/src/shell-interface.h @@ -151,7 +151,7 @@ struct ShellExternalInterface : ModuleRunner::ExternalInterface { } Literals callTable(Name tableName, - Index index, + Address index, HeapType sig, Literals& arguments, Type results, @@ -287,7 +287,8 @@ struct ShellExternalInterface : ModuleRunner::ExternalInterface { return (Index)tables[tableName].size(); } - void tableStore(Name tableName, Index index, const Literal& entry) override { + void + tableStore(Name tableName, Address index, const Literal& entry) override { auto& table = tables[tableName]; if (index >= table.size()) { trap("out of bounds table access"); @@ -296,7 +297,7 @@ struct ShellExternalInterface : ModuleRunner::ExternalInterface { } } - Literal tableLoad(Name tableName, Index index) override { + Literal tableLoad(Name tableName, Address index) override { auto it = tables.find(tableName); if (it == tables.end()) { trap("tableGet on non-existing table"); diff --git a/src/tools/execution-results.h b/src/tools/execution-results.h index eb302b4b2..78cc5af1f 100644 --- a/src/tools/execution-results.h +++ b/src/tools/execution-results.h @@ -84,7 +84,7 @@ public: if (!exportedTable) { throwEmptyException(); } - Index index = arguments[0].geti32(); + auto index = arguments[0].getUnsigned(); if (index >= tables[exportedTable].size()) { throwEmptyException(); } @@ -93,7 +93,7 @@ public: if (!exportedTable) { throwEmptyException(); } - Index index = arguments[0].geti32(); + auto index = arguments[0].getUnsigned(); if (index >= tables[exportedTable].size()) { throwEmptyException(); } diff --git a/src/tools/wasm-ctor-eval.cpp b/src/tools/wasm-ctor-eval.cpp index 499c1bf6c..52c83b053 100644 --- a/src/tools/wasm-ctor-eval.cpp +++ b/src/tools/wasm-ctor-eval.cpp @@ -290,7 +290,7 @@ struct CtorEvalExternalInterface : EvallingModuleRunner::ExternalInterface { // We assume the table is not modified FIXME Literals callTable(Name tableName, - Index index, + Address index, HeapType sig, Literals& arguments, Type result, @@ -363,12 +363,13 @@ struct CtorEvalExternalInterface : EvallingModuleRunner::ExternalInterface { return wasm->getTableOrNull(tableName)->initial; } - Literal tableLoad(Name tableName, Index index) override { + Literal tableLoad(Name tableName, Address index) override { throw FailToEvalException("table.get: TODO"); } // called during initialization - void tableStore(Name tableName, Index index, const Literal& value) override { + void + tableStore(Name tableName, Address index, const Literal& value) override { // We allow stores to the table during initialization, but not after, as we // assume the table does not change at runtime. // TODO: Allow table changes by updating the table later like we do with the diff --git a/src/wasm-interpreter.h b/src/wasm-interpreter.h index 7f1cf9054..1513b8f45 100644 --- a/src/wasm-interpreter.h +++ b/src/wasm-interpreter.h @@ -2598,7 +2598,7 @@ public: virtual Literals callImport(Function* import, const Literals& arguments) = 0; virtual Literals callTable(Name tableName, - Index index, + Address index, HeapType sig, Literals& arguments, Type result, @@ -2789,10 +2789,11 @@ public: virtual Index tableSize(Name tableName) = 0; - virtual void tableStore(Name tableName, Index index, const Literal& entry) { + virtual void + tableStore(Name tableName, Address index, const Literal& entry) { WASM_UNREACHABLE("unimp"); } - virtual Literal tableLoad(Name tableName, Index index) { + virtual Literal tableLoad(Name tableName, Address index) { WASM_UNREACHABLE("unimp"); } }; @@ -3141,13 +3142,11 @@ public: } auto index = target.getSingleValue().getUnsigned(); - auto info = getTableInstanceInfo(curr->table); if (curr->isReturn) { // Return calls are represented by their arguments followed by a reference // to the function to be called. - // TODO: switch tableLoad index from Index to Address, to support table64. auto funcref = info.interface()->tableLoad(info.name, index); if (!Type::isSubType(funcref.type, Type(curr->heapType, NonNullable))) { trap("cast failure in call_indirect"); @@ -3201,29 +3200,22 @@ public: return index; } auto info = getTableInstanceInfo(curr->table); - auto* table = info.instance->wasm.getTable(info.name); - auto address = table->indexType == Type::i64 - ? index.getSingleValue().geti64() - : index.getSingleValue().geti32(); + auto address = index.getSingleValue().getUnsigned(); return info.interface()->tableLoad(info.name, address); } Flow visitTableSet(TableSet* curr) { NOTE_ENTER("TableSet"); - Flow indexFlow = self()->visit(curr->index); - if (indexFlow.breaking()) { - return indexFlow; + Flow index = self()->visit(curr->index); + if (index.breaking()) { + return index; } - Flow valueFlow = self()->visit(curr->value); - if (valueFlow.breaking()) { - return valueFlow; + Flow value = self()->visit(curr->value); + if (value.breaking()) { + return value; } auto info = getTableInstanceInfo(curr->table); - auto* table = info.instance->wasm.getTable(info.name); - auto address = table->indexType == Type::i64 - ? indexFlow.getSingleValue().geti64() - : indexFlow.getSingleValue().geti32(); - info.interface()->tableStore( - info.name, address, valueFlow.getSingleValue()); + auto address = index.getSingleValue().getUnsigned(); + info.interface()->tableStore(info.name, address, value.getSingleValue()); return Flow(); } diff --git a/test/lit/exec/table64.wast b/test/lit/exec/table64.wast index e24741838..646634c0e 100644 --- a/test/lit/exec/table64.wast +++ b/test/lit/exec/table64.wast @@ -6,21 +6,34 @@ (type $i32 (func (result i32))) (table $table i64 10 funcref) - (elem (i64.const 0) $i32) + (elem (i64.const 0) $i32-a $i32-b) - (func $i32 (result i32) + (func $i32-a (result i32) (i32.const 42) ) - ;; CHECK: [fuzz-exec] calling call - ;; CHECK-NEXT: [fuzz-exec] note result: call => 42 - (func $call (export "call") (result i32) - ;; This call succeeds, and calls $i32 which returns 42. + (func $i32-b (result i32) + (i32.const 1337) + ) + + ;; CHECK: [fuzz-exec] calling call-a + ;; CHECK-NEXT: [fuzz-exec] note result: call-a => 42 + (func $call-a (export "call-a") (result i32) + ;; This call succeeds, and calls $i32-a which returns 42. (call_indirect (type $i32) (i64.const 0) ) ) + ;; CHECK: [fuzz-exec] calling call-b + ;; CHECK-NEXT: [fuzz-exec] note result: call-b => 1337 + (func $call-b (export "call-b") (result i32) + ;; This call succeeds, and calls $i32-b which returns 1337. + (call_indirect (type $i32) + (i64.const 1) + ) + ) + ;; CHECK: [fuzz-exec] calling oob ;; CHECK-NEXT: [trap callTable overflow] (func $oob (export "oob") (result i32) @@ -30,24 +43,46 @@ ) ) + ;; CHECK: [fuzz-exec] calling oob-huge + ;; CHECK-NEXT: [trap callTable overflow] + (func $oob-huge (export "oob-huge") (result i32) + ;; This call traps on oob with a value over 32 bits, 2**32 + 1, which if we + ;; truncated to 32 bits, would seem in bounds, and end up calling a valid + ;; function. + (call_indirect (type $i32) + (i64.add + (i64.const 0x100000000) + (i64.const 1) + ) + ) + ) + ;; CHECK: [fuzz-exec] calling null ;; CHECK-NEXT: [trap uninitialized table element] (func $null (export "null") (result i32) ;; This call traps on null (call_indirect (type $i32) - (i64.const 1) + (i64.const 2) ) ) ) -;; CHECK: [fuzz-exec] calling call -;; CHECK-NEXT: [fuzz-exec] note result: call => 42 +;; CHECK: [fuzz-exec] calling call-a +;; CHECK-NEXT: [fuzz-exec] note result: call-a => 42 + +;; CHECK: [fuzz-exec] calling call-b +;; CHECK-NEXT: [fuzz-exec] note result: call-b => 1337 ;; CHECK: [fuzz-exec] calling oob ;; CHECK-NEXT: [trap callTable overflow] +;; CHECK: [fuzz-exec] calling oob-huge +;; CHECK-NEXT: [trap callTable overflow] + ;; CHECK: [fuzz-exec] calling null ;; CHECK-NEXT: [trap uninitialized table element] -;; CHECK-NEXT: [fuzz-exec] comparing call +;; CHECK-NEXT: [fuzz-exec] comparing call-a +;; CHECK-NEXT: [fuzz-exec] comparing call-b ;; CHECK-NEXT: [fuzz-exec] comparing null ;; CHECK-NEXT: [fuzz-exec] comparing oob +;; CHECK-NEXT: [fuzz-exec] comparing oob-huge |