From aadc0a376d220e3d30c2ecca34ef5c05e8fbc7f6 Mon Sep 17 00:00:00 2001 From: pjh456 <147148383@qq.com> Date: Fri, 14 Aug 2026 21:54:48 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20session=5Fgc=20sweep=20=E6=B5=8B?= =?UTF-8?q?=E8=AF=95=E6=94=B9=E8=AF=BB=20rewrite=20=E5=90=8E=E6=96=B0?= =?UTF-8?q?=E6=8C=87=E9=92=88=E6=B6=88=E9=99=A4=20UAF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- crates/oxide_vm/src/session_gc.rs | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/crates/oxide_vm/src/session_gc.rs b/crates/oxide_vm/src/session_gc.rs index ecfedf23..8668f904 100644 --- a/crates/oxide_vm/src/session_gc.rs +++ b/crates/oxide_vm/src/session_gc.rs @@ -814,21 +814,29 @@ mod tests { (*arr).set_prop_at(0, JsValue::from_js_object(live_elem)); (*arr).set_prop_at(1, JsValue::from_js_object(dead_elem)); } - // 仅元素 0 的对象作为 GC 根:元素 1 的对象应被回收。 + // 晋升数组会把元素对象一并带入 session;随后断开元素 1 的引用,使其成为 + // mark 不可达的死对象,供 sweep 回收。 let arr_session = vm.promote_object(arr); + unsafe { + (*arr_session).set_prop_at(1, JsValue::undefined()); + } vm.regs[0] = JsValue::from_js_object(arr_session); - vm.regs[1] = JsValue::from_js_object(live_elem); let mut gc = std::mem::take(&mut vm.gc_state.session_gc); gc.mark(&vm); let _ = gc.sweep(&mut vm); vm.gc_state.session_gc = gc; - // 存活对象经克隆 + rewrite:数组元素 0 指向晋升后的 live_elem。 - let live_session = unsafe { (*arr_session).get_prop_at(0).as_js_object_ptr() }; + // sweep 复制存活对象并把 VM 根改写为新 arena 指针:regs[0] 是数组的新地址, + // 旧指针已随旧 arena 释放,不可再用。 + let arr_new = vm.regs[0].as_js_object_ptr(); + let live_session = unsafe { (*arr_new).get_prop_at(0).as_js_object_ptr() }; assert_eq!(unsafe { (*live_session).prop_count() }, 0); - assert_eq!(unsafe { (*arr_session).prop_count() }, 2); - assert_eq!(unsafe { (*arr_session).get_prop_at(0).as_js_object_ptr() }, live_session); + assert_eq!(unsafe { (*arr_new).prop_count() }, 2); + assert_eq!(unsafe { (*arr_new).get_prop_at(0).as_js_object_ptr() }, live_session); + // 元素 1 引用已断开:死元素对象被回收,存活集合只剩数组与元素 0 的对象。 + assert_eq!(unsafe { (*arr_new).get_prop_at(1) }, JsValue::undefined()); + assert_eq!(vm.gc_state.session_object_ptrs.len(), 2); } #[test]