Validator: thread table limits through `OnReturnCallIndirect` (#2744)
`SharedValidator::OnCallIndirect` passes `table_type.limits` to
`TypeChecker::OnCallIndirect`, which expects i64 vs i32 for the
table-index based on `is_64`. `OnReturnCallIndirect` doesn't — so under
`table64`, plain `call_indirect` with an i64 index validates, but the
matching `return_call_indirect` rejects it with `expected [i32] but got
[i64]`.
Mirrors the signature. Adds a `test/typecheck/` regression for the
negative case.
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
diff --git a/include/wabt/type-checker.h b/include/wabt/type-checker.h
index 25b2a42..1033b5b 100644
--- a/include/wabt/type-checker.h
+++ b/include/wabt/type-checker.h
@@ -106,7 +106,8 @@
Result OnReturnCall(const TypeVector& param_types,
const TypeVector& result_types);
Result OnReturnCallIndirect(const TypeVector& param_types,
- const TypeVector& result_types);
+ const TypeVector& result_types,
+ const Limits& table_limits);
Result OnReturnCallRef(Type type,
const TypeVector& param_types,
const TypeVector& result_types);
diff --git a/src/shared-validator.cc b/src/shared-validator.cc
index b7b748e..243b653 100644
--- a/src/shared-validator.cc
+++ b/src/shared-validator.cc
@@ -1225,8 +1225,8 @@
"type mismatch: return_call_indirect must reference "
"table of funcref type");
}
- result |=
- typechecker_.OnReturnCallIndirect(func_type.params, func_type.results);
+ result |= typechecker_.OnReturnCallIndirect(
+ func_type.params, func_type.results, table_type.limits);
IgnoreLocalRefs();
return result;
}
diff --git a/src/type-checker.cc b/src/type-checker.cc
index bb0e4d7..e309190 100644
--- a/src/type-checker.cc
+++ b/src/type-checker.cc
@@ -722,8 +722,10 @@
}
Result TypeChecker::OnReturnCallIndirect(const TypeVector& param_types,
- const TypeVector& result_types) {
- Result result = PopAndCheck1Type(Type::I32, "return_call_indirect");
+ const TypeVector& result_types,
+ const Limits& table_limits) {
+ Result result = PopAndCheck1Type(table_limits.is_64 ? Type::I64 : Type::I32,
+ "return_call_indirect");
result |= PopAndCheckSignature(param_types, "return_call_indirect");
result |= PopAndCheckReturnCall(result_types, "return_call_indirect");
diff --git a/test/typecheck/bad-returncallindirect-table64-type-mismatch.txt b/test/typecheck/bad-returncallindirect-table64-type-mismatch.txt
new file mode 100644
index 0000000..940c333
--- /dev/null
+++ b/test/typecheck/bad-returncallindirect-table64-type-mismatch.txt
@@ -0,0 +1,16 @@
+;;; TOOL: wat2wasm
+;;; ARGS: --enable-tail-call --enable-memory64
+;;; ERROR: 1
+(module
+ (type $t (func))
+ (func $f)
+ (table i64 1 1 funcref)
+ (elem (i64.const 0) $f)
+ (func
+ i32.const 0
+ return_call_indirect (type $t)))
+(;; STDERR ;;;
+out/test/typecheck/bad-returncallindirect-table64-type-mismatch.txt:11:5: error: type mismatch in return_call_indirect, expected [i64] but got [i32]
+ return_call_indirect (type $t)))
+ ^^^^^^^^^^^^^^^^^^^^
+;;; STDERR ;;)