mirror of
https://github.com/denoland/deno.git
synced 2024-12-21 23:04:45 -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:
parent
2929d583d2
commit
ea9c3ffaa2
3 changed files with 49 additions and 11 deletions
|
@ -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]
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
|
|
|
@ -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(
|
||||
|
|
Loading…
Reference in a new issue