nathanielc opened issue #11650:
The issue I am having is I get a trap for a failed cast when I try and run my component. The component is two composed components, one that links several core modules together generated by a compiler I have written. This is where the bug is found.
Here is the main core module:
(core module (;1;) (type (;0;) (func (param (ref struct) f64) (result f64))) (type (;1;) (sub (struct (field (ref 0))))) (type (;2;) (func (param (ref struct) f64) (result (ref 1)))) (type (;3;) (sub (struct (field (ref 2))))) (type (;4;) (func (param (ref struct) i64) (result (ref 3)))) (type (;5;) (func (param i64) (result f64))) (type (;6;) (sub (struct (field (ref 4))))) (type (;7;) (sub final 6 (struct (field (ref 4))))) (import "std::math" "compute" (func (;0;) (type 4))) (export "remote1" (func 0)) (export "main" (func 1)) (func (;1;) (type 5) (param i64) (result f64) (local (ref 6) (ref 3) (ref 1)) ref.func 0 struct.new 7 ref.cast (ref 6) local.tee 1 i64.const 1 local.get 1 struct.get 6 0 call_ref 4 local.tee 2 f64.const 0x1p+1 (;=2;) local.get 2 struct.get 3 0 call_ref 2 local.tee 3 f64.const 0x1.8p+1 (;=3;) local.get 3 struct.get 1 0 call_ref 0 return ) )The trap occurs on the call_ref 4 instruction. My DSL has curried closures so we are seeing a pattern of creating a struct (GC proposal) with a function reference as the first field and a its closed over env as the remaining fields.
Reading this code we create function ref to function 0 which is an imported function. Then after getting it out of the struct we call it with call_ref 4. We can easily see that the struct's field is of type 4 so this should be valid however I get the trap.
If I instead change the ref.func 0 to a locally defined function instead of an imported one it I do not get the trap.
(core module (;1;) (type (;0;) (func (param (ref struct) f64) (result f64))) (type (;1;) (sub (struct (field (ref 0))))) (type (;2;) (func (param (ref struct) f64) (result (ref 1)))) (type (;3;) (sub (struct (field (ref 2))))) (type (;4;) (func (param (ref struct) i64) (result (ref 3)))) (type (;5;) (func (param i64) (result f64))) (type (;6;) (sub (struct (field (ref 4))))) (type (;7;) (sub final 6 (struct (field (ref 4))))) (import "std::math" "compute" (func (;0;) (type 4))) (export "remote1" (func 0)) (export "main" (func 1)) (export "foo" (func 2)) (export "foo1" (func 3)) (export "foo2" (func 4)) (func (;1;) (type 5) (param i64) (result f64) (local (ref 6) (ref 3) (ref 1)) ref.func 2 struct.new 7 ref.cast (ref 6) local.tee 1 i64.const 1 local.get 1 struct.get 6 0 call_ref 4 local.tee 2 f64.const 0x1p+1 (;=2;) local.get 2 struct.get 3 0 call_ref 2 local.tee 3 f64.const 0x1.8p+1 (;=3;) local.get 3 struct.get 1 0 call_ref 0 return ) (func (;2;) (type 4) (param (ref struct) i64) (result (ref 3)) ref.func 3 struct.new 3 return ) (func (;3;) (type 2) (param (ref struct) f64) (result (ref 1)) ref.func 4 struct.new 1 return ) (func (;4;) (type 0) (param (ref struct) f64) (result f64) f64.const 0x1p+1 (;=2;) return ) )Again lots of currying so I need multiple local functions to make this type check.
Here is the complete component
I can invoke it with
wasmtime run -W gc=y,function-references=y,component-model-gc=y --invoke 'main(1)' blr.wat
I get this output:
Error: failed to run main module `blr.wat.txt` Caused by: 0: error while executing at wasm backtrace: 0: 0x17e517 - <unknown>!<wasm function 1> 1: 0x17e626 - <unknown>!<wasm function 1> 1: wasm trap: cast failure
nathanielc added the bug label to Issue #11650.
nathanielc edited issue #11650:
The issue I am having is I get a trap for a failed cast when I try and run my component. The component is two composed components, one that links several core modules together generated by a compiler I have written. This is where the bug is found.
Here is the main core module:
(core module (;1;) (type (;0;) (func (param (ref struct) f64) (result f64))) (type (;1;) (sub (struct (field (ref 0))))) (type (;2;) (func (param (ref struct) f64) (result (ref 1)))) (type (;3;) (sub (struct (field (ref 2))))) (type (;4;) (func (param (ref struct) i64) (result (ref 3)))) (type (;5;) (func (param i64) (result f64))) (type (;6;) (sub (struct (field (ref 4))))) (type (;7;) (sub final 6 (struct (field (ref 4))))) (import "std::math" "compute" (func (;0;) (type 4))) (export "remote1" (func 0)) (export "main" (func 1)) (func (;1;) (type 5) (param i64) (result f64) (local (ref 6) (ref 3) (ref 1)) ref.func 0 struct.new 7 ref.cast (ref 6) local.tee 1 i64.const 1 local.get 1 struct.get 6 0 call_ref 4 local.tee 2 f64.const 0x1p+1 (;=2;) local.get 2 struct.get 3 0 call_ref 2 local.tee 3 f64.const 0x1.8p+1 (;=3;) local.get 3 struct.get 1 0 call_ref 0 return ) )The trap occurs on the call_ref 4 instruction. My DSL has curried closures so we are seeing a pattern of creating a struct (GC proposal) with a function reference as the first field and a its closed over env as the remaining fields.
Reading this code we create function ref to function 0 which is an imported function. Then after getting it out of the struct we call it with call_ref 4. We can easily see that the struct's field is of type 4 so this should be valid however I get the trap.
If I instead change the ref.func 0 to a locally defined function instead of an imported one it I do not get the trap.
(core module (;1;) (type (;0;) (func (param (ref struct) f64) (result f64))) (type (;1;) (sub (struct (field (ref 0))))) (type (;2;) (func (param (ref struct) f64) (result (ref 1)))) (type (;3;) (sub (struct (field (ref 2))))) (type (;4;) (func (param (ref struct) i64) (result (ref 3)))) (type (;5;) (func (param i64) (result f64))) (type (;6;) (sub (struct (field (ref 4))))) (type (;7;) (sub final 6 (struct (field (ref 4))))) (import "std::math" "compute" (func (;0;) (type 4))) (export "remote1" (func 0)) (export "main" (func 1)) (export "foo" (func 2)) (export "foo1" (func 3)) (export "foo2" (func 4)) (func (;1;) (type 5) (param i64) (result f64) (local (ref 6) (ref 3) (ref 1)) ref.func 2 struct.new 7 ref.cast (ref 6) local.tee 1 i64.const 1 local.get 1 struct.get 6 0 call_ref 4 local.tee 2 f64.const 0x1p+1 (;=2;) local.get 2 struct.get 3 0 call_ref 2 local.tee 3 f64.const 0x1.8p+1 (;=3;) local.get 3 struct.get 1 0 call_ref 0 return ) (func (;2;) (type 4) (param (ref struct) i64) (result (ref 3)) ref.func 3 struct.new 3 return ) (func (;3;) (type 2) (param (ref struct) f64) (result (ref 1)) ref.func 4 struct.new 1 return ) (func (;4;) (type 0) (param (ref struct) f64) (result f64) f64.const 0x1p+1 (;=2;) return ) )Again lots of currying so I need multiple local functions to make this type check.
Here is the complete component
I can invoke it with
wasmtime run -W gc=y,function-references=y,component-model-gc=y --invoke 'main(1)' blr.watI get this output:
Error: failed to run main module `blr.wat.txt` Caused by: 0: error while executing at wasm backtrace: 0: 0x17e517 - <unknown>!<wasm function 1> 1: 0x17e626 - <unknown>!<wasm function 1> 1: wasm trap: cast failure
nathanielc edited issue #11650:
The issue I am having is I get a trap for a failed cast when I try and run my component. The component is two composed components, one that links several core modules together generated by a compiler I have written. This is where the bug is found.
Here is the main core module:
(core module (;1;) (type (;0;) (func (param (ref struct) f64) (result f64))) (type (;1;) (sub (struct (field (ref 0))))) (type (;2;) (func (param (ref struct) f64) (result (ref 1)))) (type (;3;) (sub (struct (field (ref 2))))) (type (;4;) (func (param (ref struct) i64) (result (ref 3)))) (type (;5;) (func (param i64) (result f64))) (type (;6;) (sub (struct (field (ref 4))))) (type (;7;) (sub final 6 (struct (field (ref 4))))) (import "std::math" "compute" (func (;0;) (type 4))) (export "remote1" (func 0)) (export "main" (func 1)) (func (;1;) (type 5) (param i64) (result f64) (local (ref 6) (ref 3) (ref 1)) ref.func 0 struct.new 7 ref.cast (ref 6) local.tee 1 i64.const 1 local.get 1 struct.get 6 0 call_ref 4 local.tee 2 f64.const 0x1p+1 (;=2;) local.get 2 struct.get 3 0 call_ref 2 local.tee 3 f64.const 0x1.8p+1 (;=3;) local.get 3 struct.get 1 0 call_ref 0 return ) )The trap occurs on the call_ref 4 instruction. My DSL has curried closures so we are seeing a pattern of creating a struct (GC proposal) with a function reference as the first field and a its closed over env as the remaining fields.
Reading this code we create function ref to function 0 which is an imported function. Then after getting it out of the struct we call it with call_ref 4. We can easily see that the struct's field is of type 4 so this should be valid however I get the trap.
If I instead change the ref.func 0 to a locally defined function instead of an imported one it I do not get the trap.
(core module (;1;) (type (;0;) (func (param (ref struct) f64) (result f64))) (type (;1;) (sub (struct (field (ref 0))))) (type (;2;) (func (param (ref struct) f64) (result (ref 1)))) (type (;3;) (sub (struct (field (ref 2))))) (type (;4;) (func (param (ref struct) i64) (result (ref 3)))) (type (;5;) (func (param i64) (result f64))) (type (;6;) (sub (struct (field (ref 4))))) (type (;7;) (sub final 6 (struct (field (ref 4))))) (import "std::math" "compute" (func (;0;) (type 4))) (export "remote1" (func 0)) (export "main" (func 1)) (export "foo" (func 2)) (export "foo1" (func 3)) (export "foo2" (func 4)) (func (;1;) (type 5) (param i64) (result f64) (local (ref 6) (ref 3) (ref 1)) ref.func 2 struct.new 7 ref.cast (ref 6) local.tee 1 i64.const 1 local.get 1 struct.get 6 0 call_ref 4 local.tee 2 f64.const 0x1p+1 (;=2;) local.get 2 struct.get 3 0 call_ref 2 local.tee 3 f64.const 0x1.8p+1 (;=3;) local.get 3 struct.get 1 0 call_ref 0 return ) (func (;2;) (type 4) (param (ref struct) i64) (result (ref 3)) ref.func 3 struct.new 3 return ) (func (;3;) (type 2) (param (ref struct) f64) (result (ref 1)) ref.func 4 struct.new 1 return ) (func (;4;) (type 0) (param (ref struct) f64) (result f64) f64.const 0x1p+1 (;=2;) return ) )Again lots of currying so I need multiple local functions to make this type check.
Here is the complete component
I can invoke it with
wasmtime run -W gc=y,function-references=y,component-model-gc=y --invoke 'main(1)' blr.wat.txtI get this output:
Error: failed to run main module `blr.wat.txt` Caused by: 0: error while executing at wasm backtrace: 0: 0x17e517 - <unknown>!<wasm function 1> 1: 0x17e626 - <unknown>!<wasm function 1> 1: wasm trap: cast failure
nathanielc edited issue #11650:
The issue I am having is I get a trap for a failed cast when I try and run my component. The component is two composed components, one that links several core modules together generated by a compiler I have written. This is where the bug is found.
Here is the main core module:
(core module (;1;) (type (;0;) (func (param (ref struct) f64) (result f64))) (type (;1;) (sub (struct (field (ref 0))))) (type (;2;) (func (param (ref struct) f64) (result (ref 1)))) (type (;3;) (sub (struct (field (ref 2))))) (type (;4;) (func (param (ref struct) i64) (result (ref 3)))) (type (;5;) (func (param i64) (result f64))) (type (;6;) (sub (struct (field (ref 4))))) (type (;7;) (sub final 6 (struct (field (ref 4))))) (import "std::math" "compute" (func (;0;) (type 4))) (export "remote1" (func 0)) (export "main" (func 1)) (func (;1;) (type 5) (param i64) (result f64) (local (ref 6) (ref 3) (ref 1)) ref.func 0 struct.new 7 ref.cast (ref 6) local.tee 1 i64.const 1 local.get 1 struct.get 6 0 call_ref 4 local.tee 2 f64.const 0x1p+1 (;=2;) local.get 2 struct.get 3 0 call_ref 2 local.tee 3 f64.const 0x1.8p+1 (;=3;) local.get 3 struct.get 1 0 call_ref 0 return ) )The trap occurs on the call_ref 4 instruction. My DSL has curried closures so we are seeing a pattern of creating a struct (GC proposal) with a function reference as the first field and a its closed over env as the remaining fields.
Reading this code we create function ref to function 0 which is an imported function. Then after getting it out of the struct we call it with call_ref 4. We can easily see that the struct's field is of type 4 so this should be valid however I get the trap.
If I instead change the ref.func 0 to a locally defined function instead of an imported one it I do not get the trap.
(core module (;1;) (type (;0;) (func (param (ref struct) f64) (result f64))) (type (;1;) (sub (struct (field (ref 0))))) (type (;2;) (func (param (ref struct) f64) (result (ref 1)))) (type (;3;) (sub (struct (field (ref 2))))) (type (;4;) (func (param (ref struct) i64) (result (ref 3)))) (type (;5;) (func (param i64) (result f64))) (type (;6;) (sub (struct (field (ref 4))))) (type (;7;) (sub final 6 (struct (field (ref 4))))) (import "std::math" "compute" (func (;0;) (type 4))) (export "remote1" (func 0)) (export "main" (func 1)) (export "foo" (func 2)) (export "foo1" (func 3)) (export "foo2" (func 4)) (func (;1;) (type 5) (param i64) (result f64) (local (ref 6) (ref 3) (ref 1)) ref.func 2 struct.new 7 ref.cast (ref 6) local.tee 1 i64.const 1 local.get 1 struct.get 6 0 call_ref 4 local.tee 2 f64.const 0x1p+1 (;=2;) local.get 2 struct.get 3 0 call_ref 2 local.tee 3 f64.const 0x1.8p+1 (;=3;) local.get 3 struct.get 1 0 call_ref 0 return ) (func (;2;) (type 4) (param (ref struct) i64) (result (ref 3)) ref.func 3 struct.new 3 return ) (func (;3;) (type 2) (param (ref struct) f64) (result (ref 1)) ref.func 4 struct.new 1 return ) (func (;4;) (type 0) (param (ref struct) f64) (result f64) f64.const 0x1p+1 (;=2;) return ) )Again lots of currying so I need multiple local functions to make this type check.
Here is the complete component
I can invoke it with
wasmtime run -W gc=y,function-references=y,component-model-gc=y --invoke 'main(1)' blr.wat.txtI get this output:
Error: failed to run main module `blr.wat.txt` Caused by: 0: error while executing at wasm backtrace: 0: 0x17e517 - <unknown>!<wasm function 1> 1: 0x17e626 - <unknown>!<wasm function 1> 1: wasm trap: cast failure
alexcrichton commented on issue #11650:
I followed up a bit on Zulip for this
nathanielc closed issue #11650:
The issue I am having is I get a trap for a failed cast when I try and run my component. The component is two composed components, one that links several core modules together generated by a compiler I have written. This is where the bug is found.
Here is the main core module:
(core module (;1;) (type (;0;) (func (param (ref struct) f64) (result f64))) (type (;1;) (sub (struct (field (ref 0))))) (type (;2;) (func (param (ref struct) f64) (result (ref 1)))) (type (;3;) (sub (struct (field (ref 2))))) (type (;4;) (func (param (ref struct) i64) (result (ref 3)))) (type (;5;) (func (param i64) (result f64))) (type (;6;) (sub (struct (field (ref 4))))) (type (;7;) (sub final 6 (struct (field (ref 4))))) (import "std::math" "compute" (func (;0;) (type 4))) (export "remote1" (func 0)) (export "main" (func 1)) (func (;1;) (type 5) (param i64) (result f64) (local (ref 6) (ref 3) (ref 1)) ref.func 0 struct.new 7 ref.cast (ref 6) local.tee 1 i64.const 1 local.get 1 struct.get 6 0 call_ref 4 local.tee 2 f64.const 0x1p+1 (;=2;) local.get 2 struct.get 3 0 call_ref 2 local.tee 3 f64.const 0x1.8p+1 (;=3;) local.get 3 struct.get 1 0 call_ref 0 return ) )The trap occurs on the call_ref 4 instruction. My DSL has curried closures so we are seeing a pattern of creating a struct (GC proposal) with a function reference as the first field and a its closed over env as the remaining fields.
Reading this code we create function ref to function 0 which is an imported function. Then after getting it out of the struct we call it with call_ref 4. We can easily see that the struct's field is of type 4 so this should be valid however I get the trap.
If I instead change the ref.func 0 to a locally defined function instead of an imported one it I do not get the trap.
(core module (;1;) (type (;0;) (func (param (ref struct) f64) (result f64))) (type (;1;) (sub (struct (field (ref 0))))) (type (;2;) (func (param (ref struct) f64) (result (ref 1)))) (type (;3;) (sub (struct (field (ref 2))))) (type (;4;) (func (param (ref struct) i64) (result (ref 3)))) (type (;5;) (func (param i64) (result f64))) (type (;6;) (sub (struct (field (ref 4))))) (type (;7;) (sub final 6 (struct (field (ref 4))))) (import "std::math" "compute" (func (;0;) (type 4))) (export "remote1" (func 0)) (export "main" (func 1)) (export "foo" (func 2)) (export "foo1" (func 3)) (export "foo2" (func 4)) (func (;1;) (type 5) (param i64) (result f64) (local (ref 6) (ref 3) (ref 1)) ref.func 2 struct.new 7 ref.cast (ref 6) local.tee 1 i64.const 1 local.get 1 struct.get 6 0 call_ref 4 local.tee 2 f64.const 0x1p+1 (;=2;) local.get 2 struct.get 3 0 call_ref 2 local.tee 3 f64.const 0x1.8p+1 (;=3;) local.get 3 struct.get 1 0 call_ref 0 return ) (func (;2;) (type 4) (param (ref struct) i64) (result (ref 3)) ref.func 3 struct.new 3 return ) (func (;3;) (type 2) (param (ref struct) f64) (result (ref 1)) ref.func 4 struct.new 1 return ) (func (;4;) (type 0) (param (ref struct) f64) (result f64) f64.const 0x1p+1 (;=2;) return ) )Again lots of currying so I need multiple local functions to make this type check.
Here is the complete component
I can invoke it with
wasmtime run -W gc=y,function-references=y,component-model-gc=y --invoke 'main(1)' blr.wat.txtI get this output:
Error: failed to run main module `blr.wat.txt` Caused by: 0: error while executing at wasm backtrace: 0: 0x17e517 - <unknown>!<wasm function 1> 1: 0x17e626 - <unknown>!<wasm function 1> 1: wasm trap: cast failure
nathanielc commented on issue #11650:
This is a bug on my side, I had the stacktrace backwards in my head and read the wrong code. The
call_ref 4instruction is working as expected but the passed struct doesn't match what the function is expecting. Thanks again
Last updated: Dec 06 2025 at 06:05 UTC