From 47d4d2a9218a4ff982857eb36a692eb7f0ed7f64 Mon Sep 17 00:00:00 2001 From: pjh456 <147148383@qq.com> Date: Sat, 15 Aug 2026 12:13:36 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20NEW=5FSPREAD/SUPER=5FSPREAD=20=E6=9E=84?= =?UTF-8?q?=E9=80=A0=E6=B7=B1=E9=80=92=E5=BD=92=E7=BB=9F=E4=B8=80=E8=B5=B0?= =?UTF-8?q?=E5=8E=8B=E5=B8=A7=E5=85=A5=E5=8F=A3=E5=8F=AF=E6=8D=95=E8=8E=B7?= =?UTF-8?q?=E6=B7=B1=E5=BA=A6=E6=A3=80=E6=9F=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 收敛后普通 NEW/SUPER 深递归经 push_bytecode_frame 深度检查抛可捕获 RangeError,而 NEW_SPREAD/SUPER_SPREAD 仍保留显式引擎 Err(不可捕获), 构造路径行为分叉。删除两处显式检查,交由统一入口处理:spread 变体与 普通路径一致抛可捕获 RangeError。补浅深度配置下 NEW/NEW_SPREAD 深递归 try/catch 可捕获断言(普通 NEW 作对照锚点)。 --- crates/oxide_vm/src/dispatch/call.rs | 6 ---- crates/oxide_vm/tests/regression_tests.rs | 42 +++++++++++++++++++++++ 2 files changed, 42 insertions(+), 6 deletions(-) diff --git a/crates/oxide_vm/src/dispatch/call.rs b/crates/oxide_vm/src/dispatch/call.rs index f49633e..38a8837 100644 --- a/crates/oxide_vm/src/dispatch/call.rs +++ b/crates/oxide_vm/src/dispatch/call.rs @@ -833,9 +833,6 @@ impl Vm { { return self.raise_type_error("g is not a constructor").map(|_| true); } - if self.frames.len() >= self.kernel_core.config.max_call_depth { - return Err(self.error_message_text("RangeError", "Maximum call stack size exceeded")); - } let this_value = if ctor_obj.is_derived_constructor() { JsValue::undefined() } else { @@ -926,9 +923,6 @@ impl Vm { } Ok(false) } else if super_obj.sub_module_index() > 0 { - if self.frames.len() >= self.kernel_core.config.max_call_depth { - return Err(self.error_message_text("RangeError", "Maximum call stack size exceeded")); - } self.push_bytecode_frame( super_ctor, derived_this, diff --git a/crates/oxide_vm/tests/regression_tests.rs b/crates/oxide_vm/tests/regression_tests.rs index 3dce886..6dfbf26 100644 --- a/crates/oxide_vm/tests/regression_tests.rs +++ b/crates/oxide_vm/tests/regression_tests.rs @@ -179,6 +179,48 @@ fn test_recursive_getter_throws_range_error() { ); } +/// 浅调用深度配置下执行源码:NEW/NEW_SPREAD 深递归无需堆满默认 1024 层即可命中 +/// 深度上限,输出与 `eval` 同构(字符串结果取其内容)。 +fn eval_shallow(source: &str, depth: usize) -> String { + let allocator = Allocator::default(); + let program = oxide_parser::parse(&allocator, source).unwrap(); + let module = Compiler::new().compile(&program).unwrap(); + let mut cfg = KernelConfig::minimal(); + cfg.max_call_depth = depth; + let mut vm = Vm::with_kernel_core(KernelCore::new(cfg)); + match vm.run(&module) { + Ok(val) => { + if val.is_string() { + vm.lookup_str(val).unwrap_or_default().to_string() + } else { + format!("{val}") + } + } + Err(e) => format!("vm error: {e}"), + } +} + +#[test] +fn test_new_deep_recursion_throws_catchable_range_error() { + // NEW 深递归经统一压帧入口抛可捕获 RangeError:try/catch 能接住(非引擎错误)。 + let result = eval_shallow( + "function f(){ return new f(); } try { f(); 'no-throw'; } catch(e){ 'caught:'+e.name; }", + 8, + ); + assert_eq!(result, "caught:RangeError", "NEW 深递归应可捕获,got: {result}"); +} + +#[test] +fn test_new_spread_deep_recursion_throws_catchable_range_error() { + // NEW_SPREAD 深递归与普通 NEW 同构:构造路径统一收敛到压帧入口的深度检查, + // 不得再走显式引擎 Err(不可捕获)。spread 变体与普通路径行为须一致。 + let result = eval_shallow( + "function f(){ return new f(...[1]); } try { f(); 'no-throw'; } catch(e){ 'caught:'+e.name; }", + 8, + ); + assert_eq!(result, "caught:RangeError", "NEW_SPREAD 深递归应可捕获,got: {result}"); +} + #[test] fn test_array_length_range_error() { let result = eval("new Array(4294967295)");