From e520b0dd934d893a9ebb62973afd272623805094 Mon Sep 17 00:00:00 2001 From: pjh456 <147148383@qq.com> Date: Sat, 12 Sep 2026 08:27:42 +0000 Subject: [PATCH] =?UTF-8?q?fix:=20full=20reset=20=E6=B8=85=E7=A9=BA?= =?UTF-8?q?=E6=9C=AA=E6=8D=95=E8=8E=B7=E5=BC=82=E5=B8=B8=E4=BE=A7=E9=80=9A?= =?UTF-8?q?=E9=81=93=EF=BC=88=E8=B7=A8=20epoch=20=E6=AE=8B=E7=95=99?= =?UTF-8?q?=E6=82=AC=E5=9E=82=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit clear_execution_state 漏清 last_uncaught_value:原生错误后残留的原值 持 epoch 对象指针,reset/full_reset 的池回收后悬垂,后续原生错误经 raise_call_error 消费残留值即 UAF。侧通道属执行期状态,随异常状态一并 清空;补 reset/full_reset 两边界钉。 --- crates/oxide_vm/src/vm_support.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/crates/oxide_vm/src/vm_support.rs b/crates/oxide_vm/src/vm_support.rs index d2f98d67..89214c1f 100644 --- a/crates/oxide_vm/src/vm_support.rs +++ b/crates/oxide_vm/src/vm_support.rs @@ -474,6 +474,9 @@ impl Vm { self.cell_stack.clear(); self.try_stack.clear(); self.exception_value = None; + // 未捕获异常侧通道持原始 epoch 对象指针:执行期状态,跨 run/reset 不保留, + // 池回收后残留将悬垂。 + self.last_uncaught_value = None; self.pending_exception = None; self.pending_error_kind = None; self.pending_completion = None; @@ -1260,6 +1263,22 @@ mod tests { assert!(unsafe { *session_ptr } == 123); } + /// 未捕获异常侧通道是执行期状态:原生错误后可能残留原值,reset/full_reset + /// 边界须随执行状态一并清空——否则其持有的 epoch 对象指针在池回收后悬垂 + /// (后续原生错误经 raise_call_error 消费残留值即 UAF)。 + #[test] + fn reset_drops_stale_uncaught_value() { + let mut vm = Vm::new(); + let _ = run_source(&mut vm, "0"); + vm.last_uncaught_value = Some(JsValue::float(42.0)); + vm.reset(); + assert!(vm.last_uncaught_value.is_none(), "reset 应清空未捕获异常侧通道"); + + vm.last_uncaught_value = Some(JsValue::float(42.0)); + vm.full_reset(); + assert!(vm.last_uncaught_value.is_none(), "full_reset 应清空未捕获异常侧通道"); + } + /// run 边界换新 Bump 后双 arena 保留锚恰 0:重源 run 冲高水位, /// full_reset 后 epoch/session 两 arena 均空(容量不跨 reset 保留)。 #[test]