mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-23 18:21:13 +08:00
fix: ArrayBuffer slice BigInt 参改传播 TypeError
This commit is contained in:
@@ -4,6 +4,8 @@ use oxide_types::value::JsValue;
|
||||
|
||||
use oxide_runtime_api::{NativeResult, VmHost};
|
||||
|
||||
use crate::array::to_integer_or_infinity_bounded;
|
||||
|
||||
pub(crate) const MAX_ARRAY_BUFFER_LENGTH: usize = 1 << 30;
|
||||
|
||||
/// ArrayBuffer 载荷:字节缓冲与状态位。`data` 为 `None` 即缓冲区已 detach;
|
||||
@@ -64,21 +66,20 @@ fn to_integer_or_infinity<H: VmHost>(vm: &mut H, value: JsValue) -> Result<f64,
|
||||
Ok(if n.is_nan() { 0.0 } else { n.trunc() })
|
||||
}
|
||||
|
||||
fn normalize_index<H: VmHost>(vm: &mut H, value: JsValue, len: usize) -> usize {
|
||||
let n = vm.coerce_number_bounded(value).unwrap_or(f64::NAN);
|
||||
if n.is_nan() {
|
||||
return 0;
|
||||
}
|
||||
// ToIntegerOrInfinity:±Infinity 不截断,负无穷归 0、正无穷归 len,
|
||||
/// ToIntegerOrInfinity:ToNumber 传播式(BigInt/Symbol/转换异常向上传播),
|
||||
/// NaN → 0、trunc、±Infinity 保留——负值归 0、正值归 len 由调用侧折叠。
|
||||
fn normalize_index<H: VmHost>(vm: &mut H, value: JsValue, len: usize) -> Result<usize, JsValue> {
|
||||
let n = to_integer_or_infinity_bounded(vm, value)?;
|
||||
// ±Infinity 不截断,负无穷归 0、正无穷归 len,
|
||||
// 避免饱和成 isize::MIN 后取负溢出。
|
||||
if n.is_infinite() {
|
||||
return if n < 0.0 { 0 } else { len };
|
||||
return Ok(if n < 0.0 { 0 } else { len });
|
||||
}
|
||||
let int = n.trunc() as isize;
|
||||
if int < 0 {
|
||||
len.saturating_sub(int.unsigned_abs())
|
||||
Ok(len.saturating_sub(int.unsigned_abs()))
|
||||
} else {
|
||||
(int as usize).min(len)
|
||||
Ok((int as usize).min(len))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -358,8 +359,16 @@ pub fn array_buffer_slice<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||
return NativeResult::Err(crate::error::create_type_error(vm, "ArrayBuffer internal state invalid"));
|
||||
};
|
||||
let len = data.len();
|
||||
let start = if args.len() > 1 { normalize_index(vm, vm.reg(args[1]), len) } else { 0 };
|
||||
let end = if args.len() > 2 { normalize_index(vm, vm.reg(args[2]), len) } else { len };
|
||||
let start = if args.len() > 1 {
|
||||
native_try!(normalize_index(vm, vm.reg(args[1]), len))
|
||||
} else {
|
||||
0
|
||||
};
|
||||
let end = if args.len() > 2 {
|
||||
native_try!(normalize_index(vm, vm.reg(args[2]), len))
|
||||
} else {
|
||||
len
|
||||
};
|
||||
let end = end.max(start);
|
||||
// 切片产物恒定长,原型取默认 %ArrayBuffer.prototype%。
|
||||
let proto = default_array_buffer_proto(vm);
|
||||
|
||||
@@ -412,7 +412,65 @@ fn ab_resizable_accessor_pins() {
|
||||
var t1 = false, t2 = false; \
|
||||
try { getter.call({}); } catch (e) { t1 = e instanceof TypeError; } \
|
||||
try { getter.call(undefined); } catch (e) { t2 = e instanceof TypeError; } \
|
||||
ok && fixed.resizable === false && resizable.resizable === true && t1 && t2",
|
||||
ok && fixed.resizable === false && resizable.resizable === true && t1 && t2",
|
||||
)
|
||||
.unwrap();
|
||||
assert!(result.as_bool());
|
||||
}
|
||||
|
||||
/// BigInt 参钉:ctor 与 slice 单参/双参/中间参四形均抛 TypeError。
|
||||
#[test]
|
||||
fn ab_bigint_argument_type_error() {
|
||||
let mut vm = Vm::new();
|
||||
let err = eval(&mut vm, "new ArrayBuffer(8n)").unwrap_err();
|
||||
assert!(err.contains("TypeError"), "ctor: {}", err);
|
||||
for src in [
|
||||
"new ArrayBuffer(8).slice(2n)",
|
||||
"new ArrayBuffer(8).slice(2n, 4n)",
|
||||
"new ArrayBuffer(8).slice(1n, 2n)",
|
||||
] {
|
||||
let err = eval(&mut vm, src).unwrap_err();
|
||||
assert!(err.contains("TypeError"), "{}: {}", src, err);
|
||||
}
|
||||
}
|
||||
|
||||
/// valueOf 异常透传钉:ctor 与 slice 的转换异常保留原异常值。
|
||||
#[test]
|
||||
fn ab_value_of_abort_passes_through() {
|
||||
let mut vm = Vm::new();
|
||||
let v = eval(&mut vm, "try { new ArrayBuffer({valueOf(){ throw 42 }}) } catch (e) { e }").unwrap();
|
||||
assert_eq!(v.as_int(), 42);
|
||||
let v = eval(&mut vm, "try { new ArrayBuffer(8).slice({valueOf(){ throw 7 }}) } catch (e) { e }").unwrap();
|
||||
assert_eq!(v.as_int(), 7);
|
||||
}
|
||||
|
||||
/// fold 保留钉:slice ±Infinity 饱和 0/len,Number 分支语义不回退。
|
||||
#[test]
|
||||
fn ab_slice_infinity_fold_preserved() {
|
||||
let mut vm = Vm::new();
|
||||
let result = eval(
|
||||
&mut vm,
|
||||
"new ArrayBuffer(8).slice(Infinity).byteLength === 0 \
|
||||
&& new ArrayBuffer(8).slice(-Infinity).byteLength === 8 \
|
||||
&& new ArrayBuffer(8).slice(-Infinity, 3).byteLength === 3 \
|
||||
&& new ArrayBuffer(8).slice(2, Infinity).byteLength === 6",
|
||||
)
|
||||
.unwrap();
|
||||
assert!(result.as_bool());
|
||||
}
|
||||
|
||||
/// RangeError 不回退钉:负值/超引擎上限抛 RangeError,分数截断、字符串强转。
|
||||
#[test]
|
||||
fn ab_length_range_error_not_regressed() {
|
||||
let mut vm = Vm::new();
|
||||
let result = eval(
|
||||
&mut vm,
|
||||
"var t1 = false, t2 = false; \
|
||||
try { new ArrayBuffer(-1); } catch (e) { t1 = e instanceof RangeError; } \
|
||||
try { new ArrayBuffer(2 ** 40); } catch (e) { t2 = e instanceof RangeError; } \
|
||||
t1 && t2 \
|
||||
&& new ArrayBuffer(4.9).byteLength === 4 \
|
||||
&& new ArrayBuffer('8').byteLength === 8",
|
||||
)
|
||||
.unwrap();
|
||||
assert!(result.as_bool());
|
||||
|
||||
Reference in New Issue
Block a user