fix: defineProperty 内部错误不触发 unwind + enumerable/configurable 缺省回填
This commit is contained in:
@@ -252,12 +252,23 @@ pub fn object_define_property<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResul
|
||||
let get_field = own_field(vm, desc, get_si);
|
||||
let set_field = own_field(vm, desc, set_si);
|
||||
let writable_field = own_field(vm, desc, writable_si);
|
||||
|
||||
let existing_pos = {
|
||||
let obj = unsafe { &*obj_ptr };
|
||||
vm.get_own_property_slot(obj, si)
|
||||
};
|
||||
let existing_meta = existing_pos.and_then(|pos| {
|
||||
let obj = unsafe { &*obj_ptr };
|
||||
obj.prop_meta_at(pos)
|
||||
});
|
||||
|
||||
// 修改已有属性时缺省字段回填现有值,仅定义新属性时缺省才为 false。
|
||||
let enumerable = own_field(vm, desc, enumerable_si)
|
||||
.map(oxide_runtime_api::to_boolean)
|
||||
.unwrap_or(false);
|
||||
.unwrap_or_else(|| existing_meta.map(|m| m.attributes.enumerable()).unwrap_or(false));
|
||||
let configurable = own_field(vm, desc, configurable_si)
|
||||
.map(oxide_runtime_api::to_boolean)
|
||||
.unwrap_or(false);
|
||||
.unwrap_or_else(|| existing_meta.map(|m| m.attributes.configurable()).unwrap_or(false));
|
||||
|
||||
let has_data = value_field.is_some() || writable_field.is_some();
|
||||
let has_accessor = get_field.is_some() || set_field.is_some();
|
||||
@@ -268,14 +279,6 @@ pub fn object_define_property<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResul
|
||||
));
|
||||
}
|
||||
|
||||
let existing_pos = {
|
||||
let obj = unsafe { &*obj_ptr };
|
||||
vm.get_own_property_slot(obj, si)
|
||||
};
|
||||
let existing_meta = existing_pos.and_then(|pos| {
|
||||
let obj = unsafe { &*obj_ptr };
|
||||
obj.prop_meta_at(pos)
|
||||
});
|
||||
let existing_value = existing_pos.map_or(JsValue::undefined(), |pos| {
|
||||
let obj = unsafe { &*obj_ptr };
|
||||
obj.get_prop_at(pos)
|
||||
@@ -301,11 +304,9 @@ pub fn object_define_property<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResul
|
||||
"accessor descriptor get/set must be callable or undefined",
|
||||
));
|
||||
}
|
||||
if vm
|
||||
.define_accessor_property(obj, si, get, set, PropAttributes::new(false, enumerable, configurable))
|
||||
.is_err()
|
||||
if let Err(e) = vm.define_accessor_property(obj, si, get, set, PropAttributes::new(false, enumerable, configurable))
|
||||
{
|
||||
return NativeResult::Err(crate::error::create_type_error(vm, "Cannot define property"));
|
||||
return NativeResult::Err(crate::error::create_type_error(vm, &e));
|
||||
}
|
||||
} else if has_data {
|
||||
let value = if existing_pos.is_some() {
|
||||
@@ -320,24 +321,18 @@ pub fn object_define_property<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResul
|
||||
} else {
|
||||
writable_field.map(oxide_runtime_api::to_boolean).unwrap_or(false)
|
||||
};
|
||||
if vm
|
||||
.define_data_property(obj, si, value, PropAttributes::new(writable, enumerable, configurable))
|
||||
.is_err()
|
||||
{
|
||||
return NativeResult::Err(crate::error::create_type_error(vm, "Cannot define property"));
|
||||
if let Err(e) = vm.define_data_property(obj, si, value, PropAttributes::new(writable, enumerable, configurable)) {
|
||||
return NativeResult::Err(crate::error::create_type_error(vm, &e));
|
||||
}
|
||||
} else {
|
||||
if existing_pos.is_none() {
|
||||
if vm
|
||||
.define_data_property(
|
||||
obj,
|
||||
si,
|
||||
JsValue::undefined(),
|
||||
PropAttributes::new(false, enumerable, configurable),
|
||||
)
|
||||
.is_err()
|
||||
{
|
||||
return NativeResult::Err(crate::error::create_type_error(vm, "Cannot define property"));
|
||||
if let Err(e) = vm.define_data_property(
|
||||
obj,
|
||||
si,
|
||||
JsValue::undefined(),
|
||||
PropAttributes::new(false, enumerable, configurable),
|
||||
) {
|
||||
return NativeResult::Err(crate::error::create_type_error(vm, &e));
|
||||
}
|
||||
return NativeResult::Ok(obj_val);
|
||||
}
|
||||
@@ -347,13 +342,11 @@ pub fn object_define_property<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResul
|
||||
if is_accessor {
|
||||
let get = existing_meta.map(|m| m.get).unwrap_or(JsValue::undefined());
|
||||
let set = existing_meta.map(|m| m.set).unwrap_or(JsValue::undefined());
|
||||
if vm.define_accessor_property(obj, si, get, set, attrs).is_err() {
|
||||
return NativeResult::Err(crate::error::create_type_error(vm, "Cannot define property"));
|
||||
}
|
||||
} else {
|
||||
if vm.define_data_property(obj, si, existing_value, attrs).is_err() {
|
||||
return NativeResult::Err(crate::error::create_type_error(vm, "Cannot define property"));
|
||||
if let Err(e) = vm.define_accessor_property(obj, si, get, set, attrs) {
|
||||
return NativeResult::Err(crate::error::create_type_error(vm, &e));
|
||||
}
|
||||
} else if let Err(e) = vm.define_data_property(obj, si, existing_value, attrs) {
|
||||
return NativeResult::Err(crate::error::create_type_error(vm, &e));
|
||||
}
|
||||
}
|
||||
NativeResult::Ok(obj_val)
|
||||
|
||||
@@ -157,12 +157,18 @@ impl Vm {
|
||||
|
||||
// length:实参个数,可写、不可枚举、可配置。
|
||||
let length_si = self.kernel_core.perm_interner().intern("length").0;
|
||||
self.define_data_property(obj, length_si, JsValue::int(count as i32), PropAttributes::new(true, false, true))?;
|
||||
if let Err(msg) =
|
||||
self.define_data_property(obj, length_si, JsValue::int(count as i32), PropAttributes::new(true, false, true))
|
||||
{
|
||||
return self.raise_error_kind("TypeError", &msg);
|
||||
}
|
||||
|
||||
// callee:当前执行函数,可写、不可枚举、可配置(严格模式应抛 TypeError,未支持)。
|
||||
let callee_si = self.kernel_core.perm_interner().intern("callee").0;
|
||||
let callee = self.current_callee().unwrap_or(JsValue::undefined());
|
||||
self.define_data_property(obj, callee_si, callee, PropAttributes::new(true, false, true))?;
|
||||
if let Err(msg) = self.define_data_property(obj, callee_si, callee, PropAttributes::new(true, false, true)) {
|
||||
return self.raise_error_kind("TypeError", &msg);
|
||||
}
|
||||
|
||||
self.regs[rd] = JsValue::from_js_object(obj_ptr);
|
||||
Ok(())
|
||||
|
||||
@@ -118,7 +118,10 @@ impl Vm {
|
||||
} else {
|
||||
setter
|
||||
};
|
||||
self.define_accessor_property(obj, prop_name_si, get, set, PropAttributes::DEFAULT_DATA)
|
||||
match self.define_accessor_property(obj, prop_name_si, get, set, PropAttributes::DEFAULT_DATA) {
|
||||
Ok(()) => Ok(()),
|
||||
Err(msg) => self.raise_error_kind("TypeError", &msg),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn dispatch_return(&mut self, rd: usize) -> Result<Option<JsValue>, String> {
|
||||
|
||||
@@ -346,18 +346,18 @@ impl Vm {
|
||||
if let Some(current) = obj.prop_meta_at(pos) {
|
||||
if !current.attributes.configurable() {
|
||||
if current.is_accessor {
|
||||
return self.raise_type_error("cannot redefine non-configurable property");
|
||||
return Err("cannot redefine non-configurable property".to_string());
|
||||
}
|
||||
if current.attributes.enumerable() != attributes.enumerable() {
|
||||
return self.raise_type_error("cannot redefine non-configurable property");
|
||||
return Err("cannot redefine non-configurable property".to_string());
|
||||
}
|
||||
if !current.attributes.writable()
|
||||
&& (attributes.writable() || !coercion::same_value(obj.get_prop_at(pos), val))
|
||||
{
|
||||
return self.raise_type_error("cannot redefine non-configurable property");
|
||||
return Err("cannot redefine non-configurable property".to_string());
|
||||
}
|
||||
if current.attributes.configurable() != attributes.configurable() {
|
||||
return self.raise_type_error("cannot redefine non-configurable property");
|
||||
return Err("cannot redefine non-configurable property".to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -399,7 +399,7 @@ impl Vm {
|
||||
|| current.get != get
|
||||
|| current.set != set)
|
||||
{
|
||||
return self.raise_type_error("cannot redefine non-configurable property");
|
||||
return Err("cannot redefine non-configurable property".to_string());
|
||||
}
|
||||
}
|
||||
obj.set_prop_storage(pos, JsValue::undefined());
|
||||
@@ -422,28 +422,28 @@ impl Vm {
|
||||
) -> Result<(), String> {
|
||||
let pos = index as usize;
|
||||
if pos > oxide_types::object::MAX_DENSE_PROPS {
|
||||
return self.raise_type_error("array index out of dense range");
|
||||
return Err("array index out of dense range".to_string());
|
||||
}
|
||||
let pos = pos as u32;
|
||||
if let Some(current) = obj.prop_meta_at(pos) {
|
||||
if !current.attributes.configurable() {
|
||||
if current.is_accessor != is_accessor {
|
||||
return self.raise_type_error("cannot redefine non-configurable property");
|
||||
return Err("cannot redefine non-configurable property".to_string());
|
||||
}
|
||||
if current.attributes.enumerable() != attributes.enumerable() {
|
||||
return self.raise_type_error("cannot redefine non-configurable property");
|
||||
return Err("cannot redefine non-configurable property".to_string());
|
||||
}
|
||||
if current.attributes.configurable() != attributes.configurable() {
|
||||
return self.raise_type_error("cannot redefine non-configurable property");
|
||||
return Err("cannot redefine non-configurable property".to_string());
|
||||
}
|
||||
if is_accessor {
|
||||
if current.get != get || current.set != set {
|
||||
return self.raise_type_error("cannot redefine non-configurable property");
|
||||
return Err("cannot redefine non-configurable property".to_string());
|
||||
}
|
||||
} else if !current.attributes.writable()
|
||||
&& (attributes.writable() || !coercion::same_value(obj.get_prop_at(pos), val))
|
||||
{
|
||||
return self.raise_type_error("cannot redefine non-configurable property");
|
||||
return Err("cannot redefine non-configurable property".to_string());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user