1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-11-21 15:04:11 -05:00

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

View file

@ -1,6 +1,6 @@
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license. // 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(); const callback = loadTestLibrary();
@ -36,3 +36,12 @@ Deno.test("napi callback run with args & recv", function () {
); );
assertEquals(result, 69); 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::ValueType::napi_undefined;
use napi_sys::*; use napi_sys::*;
use std::ptr; use std::ptr;
use Status::napi_pending_exception;
/// `test_callback_run((a, b) => a + b, [1, 2])` => 3 /// `test_callback_run((a, b) => a + b, [1, 2])` => 3
extern "C" fn test_callback_run( extern "C" fn test_callback_run(
@ -98,6 +99,34 @@ extern "C" fn test_callback_run_with_recv(
result 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) { pub fn init(env: napi_env, exports: napi_value) {
let properties = &[ let properties = &[
napi_new_property!(env, "test_callback_run", test_callback_run), 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",
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( assert_napi_ok!(napi_define_properties(