fix: node-api function call should use preamble (#26297)

`napi_call_function` should use our equiv of NAPI_PREAMBLE (`&mut Env`
instead of `*mut Env`) since it needs to set error codes based on
whether the body of the function raised a JS exception.

Fixes: https://github.com/denoland/deno/issues/26282
This commit is contained in:
snek 2024-10-16 12:30:19 +02:00 committed by GitHub
parent 2929d583d2
commit ea9c3ffaa2
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 49 additions and 11 deletions

View File

@ -1694,15 +1694,14 @@ fn napi_get_new_target(
}
#[napi_sym]
fn napi_call_function(
env_ptr: *mut Env,
recv: napi_value,
func: napi_value,
fn napi_call_function<'s>(
env: &'s mut Env,
recv: napi_value<'s>,
func: napi_value<'s>,
argc: usize,
argv: *const napi_value,
result: *mut napi_value,
argv: *const napi_value<'s>,
result: *mut napi_value<'s>,
) -> napi_status {
let env = check_env!(env_ptr);
check_arg!(env, recv);
let args = if argc > 0 {
check_arg!(env, argv);
@ -1716,11 +1715,11 @@ fn napi_call_function(
let Some(func) =
func.and_then(|f| v8::Local::<v8::Function>::try_from(f).ok())
else {
return napi_set_last_error(env, napi_function_expected);
return napi_function_expected;
};
let Some(v) = func.call(&mut env.scope(), recv.unwrap(), args) else {
return napi_set_last_error(env_ptr, napi_generic_failure);
return napi_generic_failure;
};
if !result.is_null() {
@ -1729,7 +1728,7 @@ fn napi_call_function(
}
}
return napi_clear_last_error(env_ptr);
napi_ok
}
#[napi_sym]

View File

@ -1,6 +1,6 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
import { assertEquals, loadTestLibrary } from "./common.js";
import { assertEquals, assertThrows, loadTestLibrary } from "./common.js";
const callback = loadTestLibrary();
@ -36,3 +36,12 @@ Deno.test("napi callback run with args & recv", function () {
);
assertEquals(result, 69);
});
Deno.test("napi callback handles errors correctly", function () {
const e = new Error("hi!");
assertThrows(() => {
callback.test_callback_throws(() => {
throw e;
});
}, e);
});

View File

@ -8,6 +8,7 @@ use napi_sys::ValueType::napi_object;
use napi_sys::ValueType::napi_undefined;
use napi_sys::*;
use std::ptr;
use Status::napi_pending_exception;
/// `test_callback_run((a, b) => a + b, [1, 2])` => 3
extern "C" fn test_callback_run(
@ -98,6 +99,34 @@ extern "C" fn test_callback_run_with_recv(
result
}
extern "C" fn test_callback_throws(
env: napi_env,
info: napi_callback_info,
) -> napi_value {
let (args, ..) = napi_get_callback_info!(env, info, 1);
let mut global: napi_value = ptr::null_mut();
assert_napi_ok!(napi_get_global(env, &mut global));
let mut argv = vec![];
let mut result: napi_value = ptr::null_mut();
assert_eq!(
unsafe {
napi_call_function(
env,
global, // recv
args[0], // cb
argv.len(),
argv.as_mut_ptr(),
&mut result,
)
},
napi_pending_exception
);
result
}
pub fn init(env: napi_env, exports: napi_value) {
let properties = &[
napi_new_property!(env, "test_callback_run", test_callback_run),
@ -106,6 +135,7 @@ pub fn init(env: napi_env, exports: napi_value) {
"test_callback_run_with_recv",
test_callback_run_with_recv
),
napi_new_property!(env, "test_callback_throws", test_callback_throws),
];
assert_napi_ok!(napi_define_properties(