fix: 数组元素访问器属性触发 getter 并透传异常

This commit is contained in:
2026-08-07 15:05:44 +08:00
parent de67cc8eee
commit 192b697335
2 changed files with 44 additions and 11 deletions
+26 -11
View File
@@ -91,8 +91,10 @@ pub fn iterator_wrapper_next<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult
_ => return NativeResult::Err(crate::error::create_type_error(vm, "Iterator wrapper has no inner iterator")),
};
if let Some(result) = next_array_like(vm, wrapper, inner, index_si) {
return NativeResult::Ok(result);
match next_array_like(vm, wrapper, inner, index_si) {
Ok(Some(result)) => return NativeResult::Ok(result),
Ok(None) => {}
Err(original) => return NativeResult::Err(original),
}
if inner.is_object() {
@@ -158,16 +160,29 @@ fn get_iterator<H: VmHost>(vm: &mut H, value: JsValue) -> Result<JsValue, JsValu
Err(crate::error::create_type_error(vm, "value is not iterable"))
}
fn next_array_like<H: VmHost>(vm: &mut H, wrapper: &mut JsObject, inner: JsValue, index_si: u32) -> Option<JsValue> {
fn next_array_like<H: VmHost>(
vm: &mut H, wrapper: &mut JsObject, inner: JsValue, index_si: u32,
) -> Result<Option<JsValue>, JsValue> {
if is_array_value(inner) {
let index = current_index(vm, wrapper, index_si);
let arr = unsafe { &*inner.as_js_object_ptr() };
if index < arr.prop_count() as usize {
let value = arr.get_prop_at(index);
// 数组元素读取走 GetValue:普通数据属性返回槽值,访问器属性
// (defineProperty getter)触发 getter 并透传异常。
let key_si = vm.kernel_core().perm_interner().intern(&index.to_string()).0;
let value = match vm.ordinary_get(arr, key_si, inner) {
Ok(v) => v,
Err(err) => {
let exc = vm
.take_uncaught_value()
.unwrap_or_else(|| crate::error::create_error(vm, &err));
return Err(exc);
}
};
vm.set_or_create_prop_value(wrapper, index_si, JsValue::int((index + 1) as i32));
return Some(make_iter_result(vm, value, false));
return Ok(Some(make_iter_result(vm, value, false)));
}
return Some(make_iter_result(vm, JsValue::undefined(), true));
return Ok(Some(make_iter_result(vm, JsValue::undefined(), true)));
}
if inner.is_string() {
@@ -177,20 +192,20 @@ fn next_array_like<H: VmHost>(vm: &mut H, wrapper: &mut JsObject, inner: JsValue
if let Some(ch) = chars.nth(index) {
vm.set_or_create_prop_value(wrapper, index_si, JsValue::int((index + 1) as i32));
let value = vm.new_string(&ch.to_string());
return Some(make_iter_result(vm, value, false));
return Ok(Some(make_iter_result(vm, value, false)));
}
return Some(make_iter_result(vm, JsValue::undefined(), true));
return Ok(Some(make_iter_result(vm, JsValue::undefined(), true)));
}
// for-of 循环默认迭代:Map 产出 [key, value] 对,Set 产出值。
if is_map_value(inner) {
return Some(map_set_step(vm, wrapper, inner, index_si, MapSetMode::MapEntries));
return Ok(Some(map_set_step(vm, wrapper, inner, index_si, MapSetMode::MapEntries)));
}
if is_set_value(inner) {
return Some(map_set_step(vm, wrapper, inner, index_si, MapSetMode::SetValues));
return Ok(Some(map_set_step(vm, wrapper, inner, index_si, MapSetMode::SetValues)));
}
None
Ok(None)
}
fn current_index<H: VmHost>(vm: &mut H, wrapper: &JsObject, index_si: u32) -> usize {
+18
View File
@@ -31,6 +31,24 @@ impl Vm {
if obj.is_array() {
if let Some(index) = self.array_index_from_property_key(prop_name_si) {
if index < obj.prop_vec_len() as u32 {
// 数组元素为访问器属性(defineProperty getter)时须触发
// getter,而非直接读数据槽。
if let Some(meta) = obj.prop_meta_at(index) {
if meta.is_accessor {
return if meta.get.is_undefined() {
Ok(JsValue::undefined())
} else if let Some(tr) = target_reg {
let getter = meta.get;
let pushed = self.push_bytecode_getter_frame(getter, receiver, tr)?;
if pushed {
return Ok(JsValue::undefined());
}
Ok(self.regs[tr as usize])
} else {
self.call_function_sync(meta.get, receiver, &[])
};
}
}
return Ok(obj.get_prop_at(index));
}
}