@@ -707,7 +707,7 @@ pub fn create_wasm_jump_table(patch: &Path, cache: &HotpatchModuleCache) -> Resu
707707 continue ;
708708 } ;
709709
710- if name . contains ( "wasm_bindgen4__rt8wbg_cast" ) && ! name. contains ( "breaks_if_inline" ) {
710+ if name_is_wbg_cast_symbol ( name) {
711711 let name = name. to_string ( ) ;
712712 let old_idx = name_to_ifunc_old
713713 . get ( & name)
@@ -1526,6 +1526,21 @@ pub fn prepare_wasm_base_module(bytes: &[u8]) -> Result<Vec<u8>> {
15261526/// backrefs (`NtB5_` etc.) routinely compress the path away. If any of these slip through, the
15271527/// describe functions get pinned into the ifunc table, wasm-bindgen's GC can't delete them, and
15281528/// the final module ships an unsatisfiable `__wbindgen_placeholder__.__wbindgen_describe` import.
1529+ /// Check if the name is a `wasm_bindgen::__rt::wbg_cast` instantiation (excluding its inner
1530+ /// `breaks_if_inlined` helper). These functions need their bodies rewritten to call the base
1531+ /// module's JS-bound versions via the ifunc table — if one slips through, the patch keeps its
1532+ /// local copy, which calls `breaks_if_inlined` → `describe::inform` → the stubbed
1533+ /// `__wbindgen_describe` import and traps with "null function" the first time the patched code
1534+ /// casts a value (e.g. creating an event-listener closure).
1535+ ///
1536+ /// In legacy mangling the path appears as `wasm_bindgen4__rt8wbg_cast`; in v0 (default since
1537+ /// rustc 1.97) identifiers starting with `_` get a `_` separator after their length, so `__rt`
1538+ /// encodes as `4___rt`.
1539+ fn name_is_wbg_cast_symbol ( name : & str ) -> bool {
1540+ ( name. contains ( "wasm_bindgen4__rt8wbg_cast" ) || name. contains ( "wasm_bindgen4___rt8wbg_cast" ) )
1541+ && !name. contains ( "breaks_if_inline" )
1542+ }
1543+
15291544fn name_is_bindgen_symbol ( name : & str ) -> bool {
15301545 name. contains ( "__wbindgen_describe" )
15311546 || name. contains ( "__wbindgen_externref" )
@@ -1590,6 +1605,25 @@ fn bindgen_symbol_catch() {
15901605 ) ) ;
15911606}
15921607
1608+ #[ test]
1609+ fn wbg_cast_symbol_catch ( ) {
1610+ // legacy mangling: wbg_cast instantiation matches, its breaks_if_inlined helper does not
1611+ assert ! ( name_is_wbg_cast_symbol(
1612+ "_ZN12wasm_bindgen4__rt8wbg_cast17h1234567890abcdefE"
1613+ ) ) ;
1614+ assert ! ( !name_is_wbg_cast_symbol(
1615+ "_ZN12wasm_bindgen4__rt8wbg_cast17breaks_if_inlined17h1234567890abcdefE"
1616+ ) ) ;
1617+
1618+ // v0 mangling: `__rt` encodes as `4___rt` (length 4, `_` separator, then `__rt`)
1619+ assert ! ( name_is_wbg_cast_symbol(
1620+ "_RINvNtCsa7akE1TfegA_12wasm_bindgen4___rt8wbg_castINtB4_7closure12OwnedClosureDINtNtNtCs9WN6KVdqFxk_4core3ops8function5FnMutTNtNtNtCs5qlPUvWaqlJ_7web_sys8features14gen_MouseEvent10MouseEventEEp6OutputuEL_Kb1_ENtBO_9JsClosureECsjFep1nV9Dzo_32dioxus_playwright_web_patch_test"
1621+ ) ) ;
1622+ assert ! ( !name_is_wbg_cast_symbol(
1623+ "_RINvNvNtCsa7akE1TfegA_12wasm_bindgen4___rt8wbg_cast17breaks_if_inlinedINtNtB6_7closure12OwnedClosureDINtNtNtCs9WN6KVdqFxk_4core3ops8function5FnMutTNtNtNtCs5qlPUvWaqlJ_7web_sys8features14gen_MouseEvent10MouseEventEEp6OutputuEL_Kb1_ENtB19_9JsClosureECsjFep1nV9Dzo_32dioxus_playwright_web_patch_test"
1624+ ) ) ;
1625+ }
1626+
15931627/// Manually parse the data section from a wasm module
15941628///
15951629/// We need to do this for data symbols because walrus doesn't provide the right range and offset
0 commit comments