@@ -18,4 +18,64 @@ final class HostModuleTests: XCTestCase {
18
18
// Ensure the allocated address is valid
19
19
_ = runtime. store. memory ( at: memoryAddr)
20
20
}
21
+
22
+ func testReentrancy( ) throws {
23
+ let runtime = Runtime ( )
24
+ let voidSignature = FunctionType ( parameters: [ ] , results: [ ] )
25
+ let module = Module (
26
+ types: [ voidSignature] ,
27
+ functions: [
28
+ // [0] (import "env" "bar" func)
29
+ // [1] (import "env" "qux" func)
30
+ // [2] "foo"
31
+ GuestFunction (
32
+ type: 0 , locals: [ ] ,
33
+ body: [
34
+ . control( . call( functionIndex: 0 ) ) ,
35
+ . control( . call( functionIndex: 0 ) ) ,
36
+ . control( . call( functionIndex: 0 ) ) ,
37
+ ] ) ,
38
+ // [3] "bar"
39
+ GuestFunction (
40
+ type: 0 , locals: [ ] ,
41
+ body: [
42
+ . control( . call( functionIndex: 1 ) )
43
+ ] ) ,
44
+ ] ,
45
+ imports: [
46
+ Import ( module: " env " , name: " bar " , descriptor: . function( 0 ) ) ,
47
+ Import ( module: " env " , name: " qux " , descriptor: . function( 0 ) ) ,
48
+ ] ,
49
+ exports: [
50
+ Export ( name: " foo " , descriptor: . function( 2 ) ) ,
51
+ Export ( name: " baz " , descriptor: . function( 3 ) ) ,
52
+ ]
53
+ )
54
+
55
+ var isExecutingFoo = false
56
+ var isQuxCalled = false
57
+ let hostModule = HostModule (
58
+ functions: [
59
+ " bar " : HostFunction ( type: voidSignature) { caller, _ in
60
+ // Ensure "invoke" executes instructions under the current call
61
+ XCTAssertFalse ( isExecutingFoo, " bar should not be called recursively " )
62
+ isExecutingFoo = true
63
+ defer { isExecutingFoo = false }
64
+ let foo = try XCTUnwrap ( caller. instance. exportedFunction ( name: " baz " ) )
65
+ _ = try foo. invoke ( [ ] , runtime: caller. runtime)
66
+ return [ ]
67
+ } ,
68
+ " qux " : HostFunction ( type: voidSignature) { _, _ in
69
+ XCTAssertTrue ( isExecutingFoo)
70
+ isQuxCalled = true
71
+ return [ ]
72
+ } ,
73
+ ]
74
+ )
75
+ try runtime. store. register ( hostModule, as: " env " )
76
+ let instance = try runtime. instantiate ( module: module)
77
+ // Check foo(wasm) -> bar(host) -> baz(wasm) -> qux(host)
78
+ _ = try runtime. invoke ( instance, function: " foo " )
79
+ XCTAssertTrue ( isQuxCalled)
80
+ }
21
81
}
0 commit comments