mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
fix: 还原代理 gOPD 不变量检查的 writable 位方向并补值检查
This commit is contained in:
Generated
+21
-21
@@ -1160,7 +1160,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_builtins"
|
||||
version = "0.20.12"
|
||||
version = "0.20.13"
|
||||
dependencies = [
|
||||
"chrono",
|
||||
"fast-float",
|
||||
@@ -1185,7 +1185,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_bytecode"
|
||||
version = "0.20.12"
|
||||
version = "0.20.13"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"oxide_log",
|
||||
@@ -1193,7 +1193,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_cfg"
|
||||
version = "0.20.12"
|
||||
version = "0.20.13"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_emit",
|
||||
@@ -1204,7 +1204,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_cli"
|
||||
version = "0.20.12"
|
||||
version = "0.20.13"
|
||||
dependencies = [
|
||||
"ansi_term",
|
||||
"bumpalo",
|
||||
@@ -1228,7 +1228,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_code_cache"
|
||||
version = "0.20.12"
|
||||
version = "0.20.13"
|
||||
dependencies = [
|
||||
"lru",
|
||||
"oxide_bytecode",
|
||||
@@ -1237,7 +1237,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_compiler"
|
||||
version = "0.20.12"
|
||||
version = "0.20.13"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_cfg",
|
||||
@@ -1258,7 +1258,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_dce"
|
||||
version = "0.20.12"
|
||||
version = "0.20.13"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_cfg",
|
||||
@@ -1272,7 +1272,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_emit"
|
||||
version = "0.20.12"
|
||||
version = "0.20.13"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"oxc_allocator",
|
||||
@@ -1288,7 +1288,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_engine"
|
||||
version = "0.20.12"
|
||||
version = "0.20.13"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_compiler",
|
||||
@@ -1300,7 +1300,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_fold"
|
||||
version = "0.20.12"
|
||||
version = "0.20.13"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"oxide_bytecode",
|
||||
@@ -1312,7 +1312,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_ir"
|
||||
version = "0.20.12"
|
||||
version = "0.20.13"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_log",
|
||||
@@ -1321,7 +1321,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_kernel"
|
||||
version = "0.20.12"
|
||||
version = "0.20.13"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"dashmap",
|
||||
@@ -1335,7 +1335,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_liveness"
|
||||
version = "0.20.12"
|
||||
version = "0.20.13"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_cfg",
|
||||
@@ -1347,7 +1347,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_log"
|
||||
version = "0.20.12"
|
||||
version = "0.20.13"
|
||||
dependencies = [
|
||||
"tracing",
|
||||
"tracing-appender",
|
||||
@@ -1356,11 +1356,11 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_net"
|
||||
version = "0.20.12"
|
||||
version = "0.20.13"
|
||||
|
||||
[[package]]
|
||||
name = "oxide_parser"
|
||||
version = "0.20.12"
|
||||
version = "0.20.13"
|
||||
dependencies = [
|
||||
"oxc_allocator",
|
||||
"oxc_ast",
|
||||
@@ -1375,7 +1375,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_regalloc"
|
||||
version = "0.20.12"
|
||||
version = "0.20.13"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_cfg",
|
||||
@@ -1391,7 +1391,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_runtime_api"
|
||||
version = "0.20.12"
|
||||
version = "0.20.13"
|
||||
dependencies = [
|
||||
"num-bigint",
|
||||
"num-traits",
|
||||
@@ -1404,7 +1404,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_test262"
|
||||
version = "0.20.12"
|
||||
version = "0.20.13"
|
||||
dependencies = [
|
||||
"oxide_bytecode",
|
||||
"oxide_compiler",
|
||||
@@ -1424,7 +1424,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_types"
|
||||
version = "0.20.12"
|
||||
version = "0.20.13"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"dashmap",
|
||||
@@ -1437,7 +1437,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "oxide_vm"
|
||||
version = "0.20.12"
|
||||
version = "0.20.13"
|
||||
dependencies = [
|
||||
"bumpalo",
|
||||
"chrono",
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ members = [
|
||||
]
|
||||
|
||||
[workspace.package]
|
||||
version = "0.20.12"
|
||||
version = "0.20.13"
|
||||
edition = "2021"
|
||||
license = "MIT"
|
||||
rust-version = "1.80"
|
||||
|
||||
@@ -1439,7 +1439,8 @@ fn own_descriptor_of<H: VmHost>(vm: &mut H, obj: &JsObject, key_si: u32) -> Resu
|
||||
// 调用;trap 缺失落穿 target 的自身描述符(target 自身为代理时经递归再
|
||||
// 路由);trap 返 undefined 表示无属性(target 自身属性不可配置或 target
|
||||
// 不可扩展时抛 TypeError);trap 返非对象按规范抛 TypeError;trap 返对象
|
||||
// 时与 target 自身描述符做不变量交叉检查(target 不可扩展时)。
|
||||
// 时与 target 自身描述符做不变量交叉检查(targetDesc 缺失仅在 target
|
||||
// 不可扩展时抛;targetDesc 不可配置时全量交叉检查与可扩展性无关)。
|
||||
if obj.is_proxy_obj() {
|
||||
let target = crate::proxy::proxy_state_ref(obj).expect("状态盒").target;
|
||||
// SAFETY: target 由构造器校验为非空对象指针。
|
||||
@@ -1600,12 +1601,13 @@ fn proxy_is_extensible<H: VmHost>(vm: &mut H, obj: &JsObject) -> Result<bool, St
|
||||
}
|
||||
|
||||
/// Proxy [[GetOwnProperty]] trap 返回值的不变量检查(规范 [[GetOwnProperty]]
|
||||
/// 步 11-12 形态):结果描述符不可配置时 target 自身属性必须存在且不可配置
|
||||
/// (与可扩展性无关);target 不可扩展时 target 自身属性必须存在且不可配置,
|
||||
/// 并经 `IsCompatiblePropertyDescriptor` 全量交叉检查(enumerable 须一致、
|
||||
/// 访问器 get/set 须一致、数据描述符不得由不可写放宽为可写、可写放宽为不可写
|
||||
/// 时值须 SameValue、形态须一致);writable 与 value 交叉检查按 target 不可
|
||||
/// 配置限定(target 可配置时放宽)。违反抛 TypeError。
|
||||
/// 步 14-16 形态):`IsCompatiblePropertyDescriptor`(三参形态)在 targetDesc
|
||||
/// 缺失且 target 不可扩展时抛 TypeError;targetDesc 不可配置时执行全量交叉检查
|
||||
/// (与可扩展性无关):result 可配置抛、enumerable 须一致、数据与访问器形态须
|
||||
/// 一致、访问器 get/set 须一致、target 不可写时 result 不得放宽为可写且值须
|
||||
/// SameValue;targetDesc 可配置时无约束。结果描述符不可配置时 targetDesc 必须
|
||||
/// 存在且不可配置,且 result 不可写时 target 不得可写(无条件抛,无值相等豁免)。
|
||||
/// 违反抛 TypeError。
|
||||
fn proxy_gopd_invariant_check<H: VmHost>(
|
||||
vm: &mut H, target: &JsObject, key_si: u32, result_desc: JsValue,
|
||||
) -> Result<(), JsValue> {
|
||||
@@ -1617,90 +1619,102 @@ fn proxy_gopd_invariant_check<H: VmHost>(
|
||||
let value_si = vm.perm_intern("value");
|
||||
let extensible = proxy_is_extensible(vm, target).map_err(|msg| crate::error::create_from_text(vm, &msg))?;
|
||||
let target_desc = own_descriptor_of(vm, target, key_si)?;
|
||||
// IsCompatiblePropertyDescriptor:仅 target 不可扩展时执行。
|
||||
if !extensible {
|
||||
let Some(td) = target_desc else {
|
||||
return Err(crate::error::create_type_error(
|
||||
vm,
|
||||
"getOwnPropertyDescriptor trap reported a property that does not exist on a non-extensible target",
|
||||
));
|
||||
};
|
||||
if desc_field_bool(vm, td, cfg_si)? {
|
||||
return Err(crate::error::create_type_error(
|
||||
vm,
|
||||
"getOwnPropertyDescriptor trap reported a descriptor for a configurable target property of a non-extensible target",
|
||||
));
|
||||
}
|
||||
if desc_field_bool(vm, result_desc, cfg_si)? {
|
||||
return Err(crate::error::create_type_error(
|
||||
vm,
|
||||
"getOwnPropertyDescriptor trap reported a configurable descriptor for a non-extensible target property",
|
||||
));
|
||||
}
|
||||
if desc_field_bool(vm, result_desc, enum_si)? != desc_field_bool(vm, td, enum_si)? {
|
||||
return Err(crate::error::create_type_error(
|
||||
vm,
|
||||
"getOwnPropertyDescriptor trap reported a different enumerable flag for a non-configurable target property",
|
||||
));
|
||||
}
|
||||
let result_get = own_field(vm, result_desc, get_si)?;
|
||||
let target_get = own_field(vm, td, get_si)?;
|
||||
if target_get.is_some() {
|
||||
if result_get.is_none() || result_get != target_get {
|
||||
// IsCompatiblePropertyDescriptor(三参形态):targetDesc 缺失仅在 target
|
||||
// 不可扩展时抛;targetDesc 不可配置时执行全量交叉检查(与可扩展性无关);
|
||||
// targetDesc 可配置时无约束。
|
||||
match target_desc {
|
||||
None => {
|
||||
if !extensible {
|
||||
return Err(crate::error::create_type_error(
|
||||
vm,
|
||||
"getOwnPropertyDescriptor trap reported a different getter for a non-configurable target accessor",
|
||||
"getOwnPropertyDescriptor trap reported a property that does not exist on a non-extensible target",
|
||||
));
|
||||
}
|
||||
let target_set = own_field(vm, td, set_si)?;
|
||||
let result_set = own_field(vm, result_desc, set_si)?;
|
||||
if target_set.is_some() {
|
||||
if result_set.is_none() || result_set != target_set {
|
||||
return Err(crate::error::create_type_error(
|
||||
vm,
|
||||
"getOwnPropertyDescriptor trap reported a different setter for a non-configurable target accessor",
|
||||
));
|
||||
}
|
||||
Some(td) => {
|
||||
if !desc_field_bool(vm, td, cfg_si)? {
|
||||
// targetDesc 不可配置:result 可配置抛。
|
||||
if let Some(cfg) = own_field(vm, result_desc, cfg_si)? {
|
||||
if oxide_runtime_api::to_boolean(cfg) {
|
||||
return Err(crate::error::create_type_error(
|
||||
vm,
|
||||
"getOwnPropertyDescriptor trap reported a configurable descriptor for a non-configurable target property",
|
||||
));
|
||||
}
|
||||
}
|
||||
} else if result_set.is_some() {
|
||||
return Err(crate::error::create_type_error(
|
||||
vm,
|
||||
"getOwnPropertyDescriptor trap reported a setter for a target accessor without setter",
|
||||
));
|
||||
}
|
||||
} else {
|
||||
if result_get.is_some() {
|
||||
return Err(crate::error::create_type_error(
|
||||
vm,
|
||||
"getOwnPropertyDescriptor trap reported a getter for a non-configurable target data property",
|
||||
));
|
||||
}
|
||||
if own_field(vm, result_desc, set_si)?.is_some() {
|
||||
return Err(crate::error::create_type_error(
|
||||
vm,
|
||||
"getOwnPropertyDescriptor trap reported a setter for a non-configurable target data property",
|
||||
));
|
||||
}
|
||||
let target_writable = desc_field_bool(vm, td, writable_si)?;
|
||||
let result_writable = desc_field_bool(vm, result_desc, writable_si)?;
|
||||
if !target_writable && result_writable {
|
||||
return Err(crate::error::create_type_error(
|
||||
vm,
|
||||
"getOwnPropertyDescriptor trap reported a writable descriptor for a non-writable target property",
|
||||
));
|
||||
}
|
||||
if !result_writable && target_writable {
|
||||
let result_value = own_field(vm, result_desc, value_si)?.unwrap_or(JsValue::undefined());
|
||||
let target_value = own_field(vm, td, value_si)?.unwrap_or(JsValue::undefined());
|
||||
if !oxide_runtime_api::same_value(result_value, target_value) {
|
||||
return Err(crate::error::create_type_error(
|
||||
vm,
|
||||
"getOwnPropertyDescriptor trap reported a non-writable descriptor with a different value for a writable target property",
|
||||
));
|
||||
// targetDesc 不可配置:enumerable 须一致(字段缺失不检查)。
|
||||
if let Some(en) = own_field(vm, result_desc, enum_si)? {
|
||||
if oxide_runtime_api::to_boolean(en) != desc_field_bool(vm, td, enum_si)? {
|
||||
return Err(crate::error::create_type_error(
|
||||
vm,
|
||||
"getOwnPropertyDescriptor trap reported a different enumerable flag for a non-configurable target property",
|
||||
));
|
||||
}
|
||||
}
|
||||
let result_get = own_field(vm, result_desc, get_si)?;
|
||||
let target_get = own_field(vm, td, get_si)?;
|
||||
if target_get.is_some() {
|
||||
if result_get.is_none() || result_get != target_get {
|
||||
return Err(crate::error::create_type_error(
|
||||
vm,
|
||||
"getOwnPropertyDescriptor trap reported a different getter for a non-configurable target accessor",
|
||||
));
|
||||
}
|
||||
let target_set = own_field(vm, td, set_si)?;
|
||||
let result_set = own_field(vm, result_desc, set_si)?;
|
||||
if target_set.is_some() {
|
||||
if result_set.is_none() || result_set != target_set {
|
||||
return Err(crate::error::create_type_error(
|
||||
vm,
|
||||
"getOwnPropertyDescriptor trap reported a different setter for a non-configurable target accessor",
|
||||
));
|
||||
}
|
||||
} else if result_set.is_some() {
|
||||
return Err(crate::error::create_type_error(
|
||||
vm,
|
||||
"getOwnPropertyDescriptor trap reported a setter for a target accessor without setter",
|
||||
));
|
||||
}
|
||||
} else {
|
||||
if result_get.is_some() {
|
||||
return Err(crate::error::create_type_error(
|
||||
vm,
|
||||
"getOwnPropertyDescriptor trap reported a getter for a non-configurable target data property",
|
||||
));
|
||||
}
|
||||
if own_field(vm, result_desc, set_si)?.is_some() {
|
||||
return Err(crate::error::create_type_error(
|
||||
vm,
|
||||
"getOwnPropertyDescriptor trap reported a setter for a non-configurable target data property",
|
||||
));
|
||||
}
|
||||
// target 不可写:result 不得放宽为可写,result 有值字段时
|
||||
// 值须 SameValue。
|
||||
if !desc_field_bool(vm, td, writable_si)? {
|
||||
if let Some(w) = own_field(vm, result_desc, writable_si)? {
|
||||
if oxide_runtime_api::to_boolean(w) {
|
||||
return Err(crate::error::create_type_error(
|
||||
vm,
|
||||
"getOwnPropertyDescriptor trap reported a writable descriptor for a non-writable target property",
|
||||
));
|
||||
}
|
||||
}
|
||||
if let Some(v) = own_field(vm, result_desc, value_si)? {
|
||||
let target_value = own_field(vm, td, value_si)?.unwrap_or(JsValue::undefined());
|
||||
if !oxide_runtime_api::same_value(v, target_value) {
|
||||
return Err(crate::error::create_type_error(
|
||||
vm,
|
||||
"getOwnPropertyDescriptor trap reported a different value for a non-writable target property",
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// 结果描述符不可配置:target 自身属性必须存在且不可配置(与可扩展性无关)。
|
||||
// 结果描述符不可配置:target 自身属性必须存在且不可配置;result 不可写且
|
||||
// target 可写无条件抛(无值相等豁免)。
|
||||
if !desc_field_bool(vm, result_desc, cfg_si)? {
|
||||
match target_desc {
|
||||
None => {
|
||||
@@ -1716,6 +1730,14 @@ fn proxy_gopd_invariant_check<H: VmHost>(
|
||||
"getOwnPropertyDescriptor trap reported a non-configurable descriptor for a configurable target property",
|
||||
));
|
||||
}
|
||||
if let Some(w) = own_field(vm, result_desc, writable_si)? {
|
||||
if !oxide_runtime_api::to_boolean(w) && desc_field_bool(vm, td, writable_si)? {
|
||||
return Err(crate::error::create_type_error(
|
||||
vm,
|
||||
"getOwnPropertyDescriptor trap reported a non-writable descriptor for a writable target property",
|
||||
));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -11,8 +11,10 @@ fn eval(vm: &mut Vm, source: &str) -> Result<JsValue, String> {
|
||||
vm.run(&Arc::new(module))
|
||||
}
|
||||
|
||||
// gOPD 不变量检查(writable 位方向与 value 一致性):target 不可写加 result
|
||||
// 可写时抛 TypeError(规范 ValidateAndApplyPropertyDescriptor 步 5.5.1 口径)。
|
||||
// gOPD 不变量检查(writable 位方向与值一致性):target 不可写且 result 可写时
|
||||
// 抛 TypeError(规范 ValidateAndApplyPropertyDescriptor 步 5e.i,与可扩展性
|
||||
// 无关);result 不可配置且不可写、target 可写时抛 TypeError(规范
|
||||
// [[GetOwnProperty]] 步 16b 形态,无值相等豁免)。
|
||||
#[test]
|
||||
fn gopd_trap_writable_relaxation_throws() {
|
||||
let mut vm = Vm::new();
|
||||
@@ -33,7 +35,28 @@ fn gopd_trap_writable_relaxation_throws() {
|
||||
assert_eq!(vm.lookup_str(result).unwrap_or_default(), "TypeError");
|
||||
}
|
||||
|
||||
// target 可配置时放宽:writable 交叉检查不执行,result 可写不抛。
|
||||
// 5e.i 可扩展 target 情形:target 可扩展、targetDesc 不可写且不可配置、
|
||||
// result 可写时同样抛 TypeError。
|
||||
#[test]
|
||||
fn gopd_trap_writable_relaxation_extensible_target_throws() {
|
||||
let mut vm = Vm::new();
|
||||
let result = eval(
|
||||
&mut vm,
|
||||
"(() => { \
|
||||
var t = { a: 1 }; \
|
||||
Object.defineProperty(t, 'a', { value: 1, writable: false, configurable: false, enumerable: false }); \
|
||||
var p = new Proxy(t, { getOwnPropertyDescriptor: function (tt, k) { \
|
||||
return { value: 1, writable: true, enumerable: false, configurable: false }; \
|
||||
} }); \
|
||||
try { Object.getOwnPropertyDescriptor(p, 'a'); return 'no-throw'; } \
|
||||
catch (e) { return e.name; } \
|
||||
})()",
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(vm.lookup_str(result).unwrap_or_default(), "TypeError");
|
||||
}
|
||||
|
||||
// targetDesc 可配置时放宽:交叉检查不执行,result 可写且可配置不抛。
|
||||
#[test]
|
||||
fn gopd_trap_configurable_target_relaxed() {
|
||||
let mut vm = Vm::new();
|
||||
@@ -53,7 +76,71 @@ fn gopd_trap_configurable_target_relaxed() {
|
||||
assert_eq!(vm.lookup_str(result).unwrap_or_default(), "ok");
|
||||
}
|
||||
|
||||
// value 一致性:target 可写加 result 不可写且值不同抛 TypeError。
|
||||
// target 不可扩展且 targetDesc 可配置、result 可配置:规范对 current 可配置
|
||||
// 无约束,不抛。
|
||||
#[test]
|
||||
fn gopd_trap_nonextensible_configurable_target_relaxed() {
|
||||
let mut vm = Vm::new();
|
||||
let result = eval(
|
||||
&mut vm,
|
||||
"(() => { \
|
||||
var t = { a: 1 }; \
|
||||
Object.defineProperty(t, 'a', { value: 1, writable: false, configurable: true, enumerable: false }); \
|
||||
Object.preventExtensions(t); \
|
||||
var p = new Proxy(t, { getOwnPropertyDescriptor: function (tt, k) { \
|
||||
return { value: 1, writable: true, enumerable: false, configurable: true }; \
|
||||
} }); \
|
||||
try { Object.getOwnPropertyDescriptor(p, 'a'); return 'ok'; } \
|
||||
catch (e) { return e.name; } \
|
||||
})()",
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(vm.lookup_str(result).unwrap_or_default(), "ok");
|
||||
}
|
||||
|
||||
// 步 16b 方向:result 不可配置且不可写、target 可写时抛 TypeError(与值无关)。
|
||||
#[test]
|
||||
fn gopd_trap_nonwritable_result_writable_target_throws() {
|
||||
let mut vm = Vm::new();
|
||||
let result = eval(
|
||||
&mut vm,
|
||||
"(() => { \
|
||||
var t = { a: 1 }; \
|
||||
Object.defineProperty(t, 'a', { value: 1, writable: true, configurable: false, enumerable: false }); \
|
||||
var p = new Proxy(t, { getOwnPropertyDescriptor: function (tt, k) { \
|
||||
return { configurable: false, writable: false }; \
|
||||
} }); \
|
||||
try { Object.getOwnPropertyDescriptor(p, 'a'); return 'no-throw'; } \
|
||||
catch (e) { return e.name; } \
|
||||
})()",
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(vm.lookup_str(result).unwrap_or_default(), "TypeError");
|
||||
}
|
||||
|
||||
// 步 16b 无值相等豁免:target 可写、result 不可配置且不可写且值 SameValue
|
||||
// 时同样抛 TypeError。
|
||||
#[test]
|
||||
fn gopd_trap_nonwritable_result_same_value_throws() {
|
||||
let mut vm = Vm::new();
|
||||
let result = eval(
|
||||
&mut vm,
|
||||
"(() => { \
|
||||
var t = { a: 1 }; \
|
||||
Object.defineProperty(t, 'a', { value: 1, writable: true, configurable: false, enumerable: false }); \
|
||||
Object.preventExtensions(t); \
|
||||
var p = new Proxy(t, { getOwnPropertyDescriptor: function (tt, k) { \
|
||||
return { value: 1, writable: false, enumerable: false, configurable: false }; \
|
||||
} }); \
|
||||
try { Object.getOwnPropertyDescriptor(p, 'a'); return 'no-throw'; } \
|
||||
catch (e) { return e.name; } \
|
||||
})()",
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(vm.lookup_str(result).unwrap_or_default(), "TypeError");
|
||||
}
|
||||
|
||||
// 步 16b 方向:target 可写、result 不可写且值不一致时抛 TypeError。
|
||||
#[test]
|
||||
fn gopd_trap_value_mismatch_throws() {
|
||||
let mut vm = Vm::new();
|
||||
@@ -74,16 +161,36 @@ fn gopd_trap_value_mismatch_throws() {
|
||||
assert_eq!(vm.lookup_str(result).unwrap_or_default(), "TypeError");
|
||||
}
|
||||
|
||||
// value 一致性:target 可写加 result 不可写且值 SameValue 不抛。
|
||||
// 5e.ii 值检查:target 不可写且 result 有值字段、值不一致时抛 TypeError
|
||||
// (target 不可写时步 16b 不触发,此情形独立钉 5e.ii)。
|
||||
#[test]
|
||||
fn gopd_trap_value_same_ok() {
|
||||
fn gopd_trap_nonwritable_target_value_mismatch_throws() {
|
||||
let mut vm = Vm::new();
|
||||
let result = eval(
|
||||
&mut vm,
|
||||
"(() => { \
|
||||
var t = { a: 1 }; \
|
||||
Object.defineProperty(t, 'a', { writable: true, configurable: false, enumerable: false }); \
|
||||
Object.preventExtensions(t); \
|
||||
Object.defineProperty(t, 'a', { value: 1, writable: false, configurable: false, enumerable: false }); \
|
||||
var p = new Proxy(t, { getOwnPropertyDescriptor: function (tt, k) { \
|
||||
return { value: 2, writable: false, enumerable: false, configurable: false }; \
|
||||
} }); \
|
||||
try { Object.getOwnPropertyDescriptor(p, 'a'); return 'no-throw'; } \
|
||||
catch (e) { return e.name; } \
|
||||
})()",
|
||||
)
|
||||
.unwrap();
|
||||
assert_eq!(vm.lookup_str(result).unwrap_or_default(), "TypeError");
|
||||
}
|
||||
|
||||
// 5e.ii 值检查通过侧:target 不可写且 result 有值字段、值 SameValue 时不抛。
|
||||
#[test]
|
||||
fn gopd_trap_nonwritable_target_value_same_ok() {
|
||||
let mut vm = Vm::new();
|
||||
let result = eval(
|
||||
&mut vm,
|
||||
"(() => { \
|
||||
var t = { a: 1 }; \
|
||||
Object.defineProperty(t, 'a', { value: 1, writable: false, configurable: false, enumerable: false }); \
|
||||
var p = new Proxy(t, { getOwnPropertyDescriptor: function (tt, k) { \
|
||||
return { value: 1, writable: false, enumerable: false, configurable: false }; \
|
||||
} }); \
|
||||
|
||||
Reference in New Issue
Block a user