summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlon Zakai <azakai@google.com>2024-11-07 09:04:36 -0800
committerGitHub <noreply@github.com>2024-11-07 09:04:36 -0800
commite409660a5b4dff9891ddb7d4786cc510a5761d3e (patch)
tree7a6c907f6aaca91f72c0a4e0642c57ad3dd1cd29
parent0af8f1f2d7ff304837ee0698265c84985420fcae (diff)
downloadbinaryen-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.h7
-rw-r--r--src/tools/execution-results.h4
-rw-r--r--src/tools/wasm-ctor-eval.cpp7
-rw-r--r--src/wasm-interpreter.h34
-rw-r--r--test/lit/exec/table64.wast55
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