mirror of
https://github.com/pjh456/OxideJS.git
synced 2026-10-27 04:01:11 +08:00
fix: apply 非对象 argArray 抛 TypeError 并先查目标可调用
This commit is contained in:
@@ -193,10 +193,11 @@ pub fn function_call<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// `Function.prototype.apply(thisArg, argsArray)`:以指定 this 和参数对象调用
|
/// `Function.prototype.apply(thisArg, argsArray)`:以指定 this 和参数对象调用
|
||||||
/// 目标函数。argsArray 为 null/undefined → 无实参;对象(数组 / Arguments /
|
/// 目标函数。目标非可调用 → TypeError(先查,先于 argArray 检查);argsArray
|
||||||
/// 数组类对象)读 `length`(传播读,强转为长度)后逐下标传播读元素(空位取
|
/// 为 null/undefined → 无实参;非对象(非 nullish)→ TypeError;对象(数组 /
|
||||||
/// undefined);元素物化为实参切片经 TailCall 下发(帧参数区),不受寄存器
|
/// Arguments / 数组类对象)读 `length`(传播读,强转为长度)后逐下标传播读
|
||||||
/// 窗口限制。length/元素 getter 抛错时透传原异常值。
|
/// 元素(空位取 undefined);元素物化为实参切片经 TailCall 下发(帧参数区),
|
||||||
|
/// 不受寄存器窗口限制。length/元素 getter 抛错时透传原异常值。
|
||||||
pub fn function_apply<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
pub fn function_apply<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
||||||
if args.is_empty() {
|
if args.is_empty() {
|
||||||
return NativeResult::Err(JsValue::undefined());
|
return NativeResult::Err(JsValue::undefined());
|
||||||
@@ -204,9 +205,25 @@ pub fn function_apply<H: VmHost>(vm: &mut H, args: &[u8]) -> NativeResult {
|
|||||||
let target_val = vm.reg(args[0]);
|
let target_val = vm.reg(args[0]);
|
||||||
let this_val = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
|
let this_val = if args.len() > 1 { vm.reg(args[1]) } else { JsValue::undefined() };
|
||||||
|
|
||||||
|
// IsCallable 检查:目标非可调用先抛 TypeError,先于 argArray 检查。
|
||||||
|
if !target_val.is_object()
|
||||||
|
|| target_val.as_js_object_ptr().is_null()
|
||||||
|
|| !unsafe { &*target_val.as_js_object_ptr() }.is_function()
|
||||||
|
{
|
||||||
|
return NativeResult::Err(crate::error::create_type_error(vm, "CALL target is not callable"));
|
||||||
|
}
|
||||||
|
|
||||||
let mut call_args: Vec<JsValue> = Vec::new();
|
let mut call_args: Vec<JsValue> = Vec::new();
|
||||||
if args.len() > 2 {
|
if args.len() > 2 {
|
||||||
let arr_val = vm.reg(args[2]);
|
let arr_val = vm.reg(args[2]);
|
||||||
|
// CreateListFromArrayLike:非对象 argArray(非 nullish)抛 TypeError;
|
||||||
|
// null/undefined 为无实参。
|
||||||
|
if !arr_val.is_object() && !arr_val.is_nullish() {
|
||||||
|
return NativeResult::Err(crate::error::create_type_error(
|
||||||
|
vm,
|
||||||
|
"CreateListFromArrayLike called on non-object",
|
||||||
|
));
|
||||||
|
}
|
||||||
if arr_val.is_object() {
|
if arr_val.is_object() {
|
||||||
let arr_ptr = arr_val.as_js_object_ptr();
|
let arr_ptr = arr_val.as_js_object_ptr();
|
||||||
if !arr_ptr.is_null() {
|
if !arr_ptr.is_null() {
|
||||||
|
|||||||
@@ -257,6 +257,27 @@ fn function_apply_non_callable_this_throws_catchable_type_error() {
|
|||||||
assert_eq!(vm.lookup_str(name).unwrap_or_default(), "TypeError");
|
assert_eq!(vm.lookup_str(name).unwrap_or_default(), "TypeError");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn function_apply_non_object_argarray_throws_type_error() {
|
||||||
|
// CreateListFromArrayLike:非对象 argArray(非 nullish)抛可捕获 TypeError;
|
||||||
|
// 目标非可调用先抛(先于 argArray 检查);null/undefined argArray 为无实参不抛。
|
||||||
|
let mut vm = Vm::new();
|
||||||
|
for src in [
|
||||||
|
"try { function f(){} f.apply(null, true) } catch (e) { e.name }",
|
||||||
|
"try { function f(){} f.apply(null, NaN) } catch (e) { e.name }",
|
||||||
|
"try { function f(){} f.apply(null, '1,2,3') } catch (e) { e.name }",
|
||||||
|
"try { function f(){} f.apply(null, Symbol()) } catch (e) { e.name }",
|
||||||
|
"try { Function.prototype.apply.call(undefined, {}, true) } catch (e) { e.name }",
|
||||||
|
] {
|
||||||
|
let name = eval(&mut vm, src).unwrap();
|
||||||
|
assert_eq!(vm.lookup_str(name).unwrap_or_default(), "TypeError", "for {}", src);
|
||||||
|
}
|
||||||
|
let result = eval(&mut vm, "function f(){ return arguments.length; } f.apply(null, null)").unwrap();
|
||||||
|
assert_num(result, 0.0);
|
||||||
|
let result = eval(&mut vm, "function f(){ return arguments.length; } f.apply(null, undefined)").unwrap();
|
||||||
|
assert_num(result, 0.0);
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn function_call_non_callable_target_keeps_type_error_kind() {
|
fn function_call_non_callable_target_keeps_type_error_kind() {
|
||||||
// call 转发到非可调用目标(原始值 thisArg):内层递归无原值可恢复时,
|
// call 转发到非可调用目标(原始值 thisArg):内层递归无原值可恢复时,
|
||||||
|
|||||||
Reference in New Issue
Block a user