Skip to content

Commit a76b8ad

Browse files
authored
Fix cross-module call_indirects in the interpreter (#7964)
It was using the name of the function to look up the funcref in the current module. Instead, use doCall so we can call another module's function.
1 parent 2010baa commit a76b8ad

File tree

3 files changed

+62
-3
lines changed

3 files changed

+62
-3
lines changed

src/tools/wasm-ctor-eval.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -368,6 +368,9 @@ struct CtorEvalExternalInterface : EvallingModuleRunner::ExternalInterface {
368368
if (!Properties::isConstantExpression(value)) {
369369
throw FailToEvalException("tableLoad of non-literal");
370370
}
371+
if (auto* r = value->dynCast<RefFunc>()) {
372+
return instance->makeFuncData(r->func, r->type.getHeapType());
373+
}
371374
return Properties::getLiteral(value);
372375
}
373376

src/wasm-interpreter.h

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3561,15 +3561,16 @@ class ModuleRunnerBase : public ExpressionRunner<SubType> {
35613561
trap("non-function target in call_indirect");
35623562
}
35633563

3564-
auto* func = self()->getModule()->getFunction(funcref.getFunc());
3565-
if (!HeapType::isSubType(func->type, curr->heapType)) {
3564+
// TODO: Throw a non-constant exception if the reference is to an imported
3565+
// function that has a supertype of the expected type.
3566+
if (!HeapType::isSubType(funcref.type.getHeapType(), curr->heapType)) {
35663567
trap("callIndirect: non-subtype");
35673568
}
35683569

35693570
#if WASM_INTERPRETER_DEBUG
35703571
std::cout << self()->indent() << "(calling table)\n";
35713572
#endif
3572-
Flow ret = callFunction(funcref.getFunc(), arguments);
3573+
Flow ret = funcref.getFuncData()->doCall(arguments);
35733574
#if WASM_INTERPRETER_DEBUG
35743575
std::cout << self()->indent() << "(returned to " << scope->function->name
35753576
<< ")\n";
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
2+
;; Test for confusion regarding internal function names when using
3+
;; call_indirect.
4+
5+
(module $primary
6+
(import "spectest" "print_i32" (func $log (param i32)))
7+
8+
(func $run (export "run") (result funcref)
9+
(call $log (i32.const -1))
10+
(ref.func $run)
11+
)
12+
)
13+
14+
(register "primary")
15+
16+
(module $secondary
17+
(type $func (func (result funcref)))
18+
19+
(import "spectest" "print_i32" (func $log (param i32)))
20+
21+
(import "primary" "run" (func $primary_run (result funcref)))
22+
23+
(table $table 10 20 funcref)
24+
25+
(global $sum (mut i32) (i32.const 0))
26+
27+
(func $run (export "secondary_run") (result funcref)
28+
(global.set $sum
29+
(i32.add
30+
(global.get $sum)
31+
(i32.const 1)
32+
)
33+
)
34+
(call $log (i32.const 10))
35+
(table.set $table
36+
(i32.const 0)
37+
(call $primary_run)
38+
)
39+
(call $log (i32.const 20))
40+
;; This should call primary's $run, not ours. The overlap in internal name
41+
;; should not confuse us. If we do get confused, we'd recurse here and keep
42+
;; incrementing $sum.
43+
(call_indirect (type $func)
44+
(i32.const 0)
45+
)
46+
)
47+
48+
(func $sum (export "secondary_sum") (result i32)
49+
(global.get $sum)
50+
)
51+
)
52+
53+
(invoke "secondary_run")
54+
(assert_return (invoke "secondary_sum") (i32.const 1))
55+

0 commit comments

Comments
 (0)