mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-24 18:51:13 +08:00
fix: 数组长度定义异常原值抛出并保留错误类型
This commit is contained in:
@@ -222,6 +222,10 @@ pub struct Vm {
|
||||
/// String 后,for-of 需要重新抛出原值。放在 VM 顶层字段(不在 InlineSyncState 中)
|
||||
/// 以便跨内联调用的恢复过程存活。
|
||||
pub(crate) last_uncaught_value: Option<JsValue>,
|
||||
/// 数组 length define 强转期用户代码抛出的原始异常:与 `last_uncaught_value`
|
||||
/// 分离,避免入口误取其它操作忽略调用残留的值。仅 `define_array_length` 写入,
|
||||
/// 由 Object/Reflect define 入口消费。
|
||||
pub(crate) pending_length_exception: Option<JsValue>,
|
||||
pub(crate) pending_exception: Option<JsValue>,
|
||||
pub(crate) pending_error_kind: Option<&'static str>,
|
||||
/// 控制流完成(break/continue/return)暂存,finally 执行后由 TRY_FINALLY_END 恢复。
|
||||
|
||||
@@ -52,6 +52,9 @@ impl oxide_runtime_api::VmHost for Vm {
|
||||
fn restore_uncaught_value(&mut self, value: Option<JsValue>) {
|
||||
self.last_uncaught_value = value;
|
||||
}
|
||||
fn take_pending_length_exception(&mut self) -> Option<JsValue> {
|
||||
self.pending_length_exception.take()
|
||||
}
|
||||
fn property_key_si(&mut self, val: JsValue) -> u32 {
|
||||
// 对象键转换(to_string_full)失败时降级为空键:本 trait 路径供
|
||||
// Reflect/Object 内置使用,这些内置按规范不传播键转换异常;计算属性
|
||||
|
||||
@@ -1060,17 +1060,39 @@ impl Vm {
|
||||
/// 可写位、bump 世代。
|
||||
///
|
||||
/// # 注意事项
|
||||
/// - 非法长度以 `"RangeError: "` 前缀标记 kind,由 Object/Reflect 入口各自投影;
|
||||
/// 其余失败投影为 TypeError。
|
||||
/// - 非法长度以 `"RangeError: "` 前缀标记 kind,强转失败以 `"TypeError: "`
|
||||
/// 前缀标记;用户代码抛出的原始异常值转存 VM 专用槽,由 Object/Reflect
|
||||
/// 入口取出并原值重抛。
|
||||
fn define_array_length(
|
||||
&mut self, obj: &mut JsObject, val: JsValue, attributes: PropAttributes,
|
||||
) -> Result<(), String> {
|
||||
// BigInt 无 ToNumber 语义(ToNumber(BigInt) 抛 TypeError):在强转前拦截,
|
||||
// 避免通用 to_number 的近似分支把 1n 当作 1.0 接受。
|
||||
if val.is_bigint() {
|
||||
return Err(self.error_message_text("TypeError", "Cannot convert a BigInt value to a number"));
|
||||
}
|
||||
|
||||
// [[Value]] 两次强转都要实际执行(可触发用户代码),且须早于描述符校验;
|
||||
// 两次强转之间用户代码可能把 length 收窄为不可写。
|
||||
let new_len = self.coerce_uint32_bounded(val)?;
|
||||
let number_len = self.coerce_number_bounded(val)?;
|
||||
// 两次强转之间用户代码可能把 length 收窄为不可写。清空未捕获槽后执行,
|
||||
// 槽内值必为本次强转产生;用户抛出时原值转存专用槽供入口原值重抛,
|
||||
// 引擎转换失败(如 Symbol)留空由消息前缀重建 TypeError。
|
||||
self.last_uncaught_value = None;
|
||||
let new_len = match self.coerce_uint32_bounded(val) {
|
||||
Ok(v) => v,
|
||||
Err(msg) => {
|
||||
self.pending_length_exception = self.last_uncaught_value.take();
|
||||
return Err(msg);
|
||||
}
|
||||
};
|
||||
let number_len = match self.coerce_number_bounded(val) {
|
||||
Ok(v) => v,
|
||||
Err(msg) => {
|
||||
self.pending_length_exception = self.last_uncaught_value.take();
|
||||
return Err(msg);
|
||||
}
|
||||
};
|
||||
if new_len as f64 != number_len {
|
||||
return Err("RangeError: Invalid array length".to_string());
|
||||
return Err(self.error_message_text("RangeError", "Invalid array length"));
|
||||
}
|
||||
|
||||
let old_logical = obj.logical_len();
|
||||
|
||||
@@ -87,6 +87,7 @@ impl Vm {
|
||||
try_stack: Vec::new(),
|
||||
exception_value: None,
|
||||
last_uncaught_value: None,
|
||||
pending_length_exception: None,
|
||||
pending_exception: None,
|
||||
pending_error_kind: None,
|
||||
pending_completion: None,
|
||||
@@ -216,6 +217,7 @@ impl Vm {
|
||||
try_stack: Vec::new(),
|
||||
exception_value: None,
|
||||
last_uncaught_value: None,
|
||||
pending_length_exception: None,
|
||||
pending_exception: None,
|
||||
pending_error_kind: None,
|
||||
pending_completion: None,
|
||||
@@ -513,6 +515,7 @@ impl Vm {
|
||||
// 未捕获异常侧通道持原始 epoch 对象指针:执行期状态,跨 run/reset 不保留,
|
||||
// 池回收后残留将悬垂。
|
||||
self.last_uncaught_value = None;
|
||||
self.pending_length_exception = None;
|
||||
self.pending_exception = None;
|
||||
self.pending_error_kind = None;
|
||||
self.pending_completion = None;
|
||||
|
||||
Reference in New Issue
Block a user