@@ -461,8 +461,25 @@ pub extern "C" fn js_suppressed_error_new(error: f64, suppressed: f64, message:
461461 // properties { writable:true, enumerable:false, configurable:true }. The
462462 // `name` default ("SuppressedError") lives on `SuppressedError.prototype`,
463463 // so it is *not* set as an own property here.
464+ // #6949(b): `obj` is a raw Rust local — neither a GC root nor a shadow slot
465+ // — and everything below it allocates: `js_string_from_bytes` per key,
466+ // `js_object_set_field_by_name` when the object grows, and
467+ // `js_string_coerce` on the message. Any of those can collect and EVACUATE.
468+ //
469+ // A single rebind after the coercion would not be enough here for two
470+ // reasons: the closure captures `obj` BY VALUE, so every `set_nonenum` call
471+ // would keep using the address captured at definition time; and
472+ // `object_set_static_prototype` at the end keys a SIDE TABLE on
473+ // `obj as usize`, so a stale address does not fault — it files the
474+ // prototype under an address nothing will look up, and `instanceof
475+ // SuppressedError` quietly stops resolving.
476+ //
477+ // So root once and re-read at every use, which is what the handle gives.
478+ let scope = crate :: gc:: RuntimeHandleScope :: new ( ) ;
479+ let obj_handle = scope. root_raw_mut_ptr ( obj) ;
464480 let set_nonenum = |key : & str , value : f64 | {
465481 let key_ptr = js_string_from_bytes ( key. as_ptr ( ) , key. len ( ) as u32 ) ;
482+ let obj = obj_handle. get_raw_mut_ptr :: < crate :: object:: ObjectHeader > ( ) ;
466483 js_object_set_field_by_name ( obj, key_ptr, value) ;
467484 crate :: object:: set_property_attrs (
468485 obj as usize ,
@@ -484,11 +501,13 @@ pub extern "C" fn js_suppressed_error_new(error: f64, suppressed: f64, message:
484501 } ;
485502 set_nonenum ( "message" , message_val) ;
486503 }
504+ let obj = obj_handle. get_raw_mut_ptr :: < crate :: object:: ObjectHeader > ( ) ;
487505 let result = js_nanbox_pointer ( obj as i64 ) ;
488506 // Link the instance to `SuppressedError.prototype` so `name`/`message`
489507 // defaults and `instanceof SuppressedError` resolve through the chain.
490508 let proto = crate :: object:: builtin_prototype_value ( "SuppressedError" ) ;
491509 if proto. to_bits ( ) != TAG_UNDEFINED && js_nanbox_get_pointer ( proto) != 0 {
510+ let obj = obj_handle. get_raw_mut_ptr :: < crate :: object:: ObjectHeader > ( ) ;
492511 crate :: object:: prototype_chain:: object_set_static_prototype ( obj as usize , proto. to_bits ( ) ) ;
493512 }
494513 result
0 commit comments