fix: 不可扩展对象设置原型返回失败

This commit is contained in:
2026-09-18 01:23:02 +00:00
parent a8b4191d0f
commit 4236290b45
6 changed files with 80 additions and 6 deletions
+14 -4
View File
@@ -1256,11 +1256,12 @@ pub fn object_get_prototype_of<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResu
/// - `obj` 为 null/undefined 抛 TypeError(RequireObjectCoercible);原始值原样返回,
/// 不装箱。
/// - `proto` 既非对象也非 null 时抛 TypeError。
/// - 目标不可设置(原型环)时抛 TypeError;普通对象恒可设置,与 Reflect 版
/// 按布尔返回的语义不同。
/// - 目标不可设置(原型环,或不可扩展且新旧原型不同)时抛 TypeError;与 Reflect
/// 版按布尔返回的语义不同。
///
/// # 副作用
/// - 目标为对象时改写其 proto 槽并递增 generation。
/// - 目标为对象且设置成功时改写其 proto 槽并递增 generation;新旧原型相同
/// (SameValue)时按规范直接成功。
pub fn object_set_prototype_of<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
let target_val = args.get(1).map(|reg| vm.reg(*reg)).unwrap_or_else(JsValue::undefined);
if target_val.is_null() || target_val.is_undefined() {
@@ -1280,7 +1281,16 @@ pub fn object_set_prototype_of<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResu
return NativeResult::Ok(target_val);
}
let target_ptr = target_val.as_js_object_ptr();
if unsafe { &mut *target_ptr }.set_proto(proto).is_err() {
let target = unsafe { &mut *target_ptr };
// OrdinarySetPrototypeOf 步 2-4:新旧原型 SameValue 时直接成功,可扩展标志
// 不参与判断;不可扩展且新旧不同才失败。set_proto 是裸写槽操作,不含该判定。
if !target.is_extensible() && target.proto() != proto {
return NativeResult::Err(crate::error::create_type_error(
vm,
"Object.setPrototypeOf: cannot set prototype of non-extensible object",
));
}
if target.set_proto(proto).is_err() {
return NativeResult::Err(crate::error::create_type_error(vm, "Object.setPrototypeOf: cannot set prototype"));
}
NativeResult::Ok(target_val)