From cc78e6b28f7daded5d94c18ae0a68b4c3ed76101 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E7=88=B1=E7=89=B9=E6=AF=8F=E7=BE=8A=E9=98=9F?= Date: Wed, 12 Aug 2026 13:07:32 +0800 Subject: [PATCH] =?UTF-8?q?fix:=20ArraySetLength=20=E6=94=B6=E7=BC=A9?= =?UTF-8?q?=E9=81=87=E4=B8=8D=E5=8F=AF=E9=85=8D=E7=BD=AE=E5=85=83=E7=B4=A0?= =?UTF-8?q?=E9=9D=99=E9=BB=98=E5=A4=B1=E8=B4=A5=E3=80=81ToPrimitive=20?= =?UTF-8?q?=E5=BC=82=E5=B8=B8=E9=80=8F=E4=BC=A0=E4=B8=8E=E6=97=A2=E6=9C=89?= =?UTF-8?q?=E5=B1=9E=E6=80=A7=E6=8F=8F=E8=BF=B0=E7=AC=A6=E7=BC=BA=E7=9C=81?= =?UTF-8?q?=E5=9B=9E=E5=A1=AB?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - arr.length 收缩时若 [newLen, oldLen) 内存在不可配置元素,整个收缩失败且不做任何修改(sloppy 赋值静默 no-op),不再抛错或截断 - length 赋值 ToPrimitive(valueOf/toString)抛错时按主 dispatch 约定直接返回,避免二次抛 RangeError 覆盖原异常(S15.4.5.1_A1.3_T2) - Object.defineProperty/defineProperties/create 对已有属性省略描述符字段时保持现有属性值(无显式 meta 按 DEFAULT_DATA 回填),修复 toReversed/toSorted/toSpliced/with length-decreased-while-iterating --- crates/oxide_builtins/src/object.rs | 9 +++++++-- crates/oxide_vm/src/vm_props.rs | 19 +++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/crates/oxide_builtins/src/object.rs b/crates/oxide_builtins/src/object.rs index ffe3bb7..03b0626 100644 --- a/crates/oxide_builtins/src/object.rs +++ b/crates/oxide_builtins/src/object.rs @@ -506,9 +506,14 @@ fn define_from_descriptor( let obj = unsafe { &*obj_ptr }; vm.get_own_property_slot(obj, key_si) }; - let existing_meta = existing_pos.and_then(|pos| { + let existing_meta = existing_pos.map(|pos| { let obj = unsafe { &*obj_ptr }; - obj.prop_meta_at(pos) + // 已有属性无显式 meta(普通数据属性/数组元素)时按默认属性回填: + // 描述符缺省字段保持现有值(writable/enumerable/configurable 均 true), + // 而非按新属性处理为 false(Object.defineProperty 省略字段不改已有属性)。 + obj.prop_meta_at(pos).unwrap_or_else(|| { + oxide_types::object::PropMetaEntry::data(PropAttributes::DEFAULT_DATA) + }) }); // 修改已有属性时缺省字段回填现有值,仅定义新属性时缺省才为 false。 diff --git a/crates/oxide_vm/src/vm_props.rs b/crates/oxide_vm/src/vm_props.rs index b1a7784..a3e1d8c 100644 --- a/crates/oxide_vm/src/vm_props.rs +++ b/crates/oxide_vm/src/vm_props.rs @@ -182,7 +182,14 @@ impl Vm { // prop_count/迭代/内置方法看到的长度不一致。 let length_si = self.kernel_core.perm_interner().intern("length").0; if obj.is_array() && prop_name_si == length_si { + let pc_before = self.pc; let number_len = self.coerce_number_bounded(val)?; + // ToPrimitive 抛错(valueOf/toString throw)已被 unwind 定向到外围 catch 时 + // pc 指向 catch 入口:主 dispatch 约定异常后 opcode 不得继续 raise,直接 + // 返回由 dispatch 继续执行 catch,避免二次抛错覆盖原异常。 + if self.pc != pc_before { + return Ok(()); + } let raw_new_len = if number_len == 0.0 || !number_len.is_finite() { 0 } else { @@ -192,7 +199,19 @@ impl Vm { if raw_new_len as f64 != number_len { return self.raise_error_kind("RangeError", "Invalid array length"); } + let old_logical = obj.logical_len() as usize; let old_count = obj.array_prop_count as usize; + // ArraySetLength:收缩时若 [newLen, oldLen) 内存在不可配置元素,整个收缩 + // 失败且不做任何修改(sloppy 赋值静默失败;VM 未实现 strict 标志,统一按 no-op)。 + if raw_new_len < old_logical { + for idx in raw_new_len..old_count { + if let Some(meta) = obj.prop_meta_at(idx) { + if !meta.attributes.configurable() { + return Ok(()); + } + } + } + } // Dense storage caps at MAX_DENSE_PROPS; larger lengths stay at the cap. let new_len_u = raw_new_len.min(oxide_types::object::MAX_DENSE_PROPS); obj.set_prop_count(new_len_u);