Skip to content

Commit 524daf8

Browse files
mhdawsoncodebytere
authored andcommitted
n-api: ensure scope present for finalization
Refs: nodejs/node-addon-api#722 Ensure a scope is on stack during finalization as finalization functions can create JS Objects Signed-off-by: Michael Dawson <[email protected]> PR-URL: #33508 Reviewed-By: Gabriel Schulhof <[email protected]> Reviewed-By: James M Snell <[email protected]>
1 parent e3a5332 commit 524daf8

File tree

4 files changed

+75
-0
lines changed

4 files changed

+75
-0
lines changed

src/js_native_api_v8.cc

+1
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,7 @@ class RefBase : protected Finalizer, RefTracker {
267267
protected:
268268
inline void Finalize(bool is_env_teardown = false) override {
269269
if (_finalize_callback != nullptr) {
270+
v8::HandleScope handle_scope(_env->isolate);
270271
_env->CallIntoModule([&](napi_env env) {
271272
_finalize_callback(
272273
env,
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
{
2+
"targets": [
3+
{
4+
"target_name": "test_worker_terminate_finalization",
5+
"sources": [ "test_worker_terminate_finalization.c" ]
6+
}
7+
]
8+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
'use strict';
2+
const common = require('../../common');
3+
const { Worker, isMainThread } = require('worker_threads');
4+
5+
if (isMainThread) {
6+
const worker = new Worker(__filename);
7+
worker.on('error', common.mustNotCall());
8+
} else {
9+
const { Test } =
10+
require(`./build/${common.buildType}/test_worker_terminate_finalization`);
11+
12+
// Spin up thread and call add-on create the right sequence
13+
// of rerences to hit the case reported in
14+
// https://github.com/nodejs/node-addon-api/issues/722
15+
// will crash if run under debug and its not possible to
16+
// create object in the specific finalizer
17+
Test(new Object());
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
#include <stdio.h>
2+
#include <node_api.h>
3+
#include <assert.h>
4+
#include <stdlib.h>
5+
#include "../../js-native-api/common.h"
6+
7+
#define BUFFER_SIZE 4
8+
9+
int wrappedNativeData;
10+
napi_ref ref;
11+
void WrapFinalizer(napi_env env, void* data, void* hint) {
12+
uint32_t count;
13+
NAPI_CALL_RETURN_VOID(env, napi_reference_unref(env, ref, &count));
14+
NAPI_CALL_RETURN_VOID(env, napi_delete_reference(env, ref));
15+
}
16+
17+
void BufferFinalizer(napi_env env, void* data, void* hint) {
18+
free(hint);
19+
}
20+
21+
napi_value Test(napi_env env, napi_callback_info info) {
22+
size_t argc = 1;
23+
napi_value argv[1];
24+
napi_value result;
25+
napi_ref ref;
26+
void* bufferData = malloc(BUFFER_SIZE);
27+
28+
NAPI_CALL(env, napi_get_cb_info(env, info, &argc, argv, NULL, NULL));
29+
NAPI_CALL(env, napi_create_external_buffer(env, BUFFER_SIZE, bufferData, BufferFinalizer, bufferData, &result));
30+
NAPI_CALL(env, napi_create_reference(env, result, 1, &ref));
31+
NAPI_CALL(env, napi_wrap(env, argv[0], (void*) &wrappedNativeData, WrapFinalizer, NULL, NULL));
32+
return NULL;
33+
}
34+
35+
napi_value Init(napi_env env, napi_value exports) {
36+
napi_property_descriptor properties[] = {
37+
DECLARE_NAPI_PROPERTY("Test", Test)
38+
};
39+
40+
NAPI_CALL(env, napi_define_properties(
41+
env, exports, sizeof(properties) / sizeof(*properties), properties));
42+
43+
return exports;
44+
}
45+
46+
// Do not start using NAPI_MODULE_INIT() here, so that we can test
47+
// compatibility of Workers with NAPI_MODULE().
48+
NAPI_MODULE(NODE_GYP_MODULE_NAME, Init)

0 commit comments

Comments
 (0)