1 #include <js_native_api.h>
2 #include <stdlib.h>
3 #include "../common.h"
4 #include "../entry_point.h"
5
6 static size_t g_call_count = 0;
7
Destructor(napi_env env,void * data,void * nothing)8 static void Destructor(napi_env env, void* data, void* nothing) {
9 napi_ref* ref = data;
10 NODE_API_CALL_RETURN_VOID(env, napi_delete_reference(env, *ref));
11 free(ref);
12 }
13
NoDeleteDestructor(napi_env env,void * data,void * hint)14 static void NoDeleteDestructor(napi_env env, void* data, void* hint) {
15 napi_ref* ref = data;
16 size_t* call_count = hint;
17
18 // This destructor must be called exactly once.
19 if ((*call_count) > 0) abort();
20 *call_count = ((*call_count) + 1);
21 free(ref);
22 }
23
New(napi_env env,napi_callback_info info)24 static napi_value New(napi_env env, napi_callback_info info) {
25 size_t argc = 1;
26 napi_value js_this, js_delete;
27 bool delete;
28 napi_ref* ref = malloc(sizeof(*ref));
29
30 NODE_API_CALL(env,
31 napi_get_cb_info(env, info, &argc, &js_delete, &js_this, NULL));
32 NODE_API_CALL(env, napi_get_value_bool(env, js_delete, &delete));
33
34 if (delete) {
35 NODE_API_CALL(env,
36 napi_wrap(env, js_this, ref, Destructor, NULL, ref));
37 } else {
38 NODE_API_CALL(env,
39 napi_wrap(env, js_this, ref, NoDeleteDestructor, &g_call_count, ref));
40 }
41 NODE_API_CALL(env, napi_reference_ref(env, *ref, NULL));
42
43 return js_this;
44 }
45
NoopDeleter(napi_env env,void * data,void * hint)46 static void NoopDeleter(napi_env env, void* data, void* hint) {}
47
48 // Tests that calling napi_remove_wrap and napi_delete_reference consecutively
49 // doesn't crash the process.
50 // This is analogous to the test https://github.com/nodejs/node-addon-api/blob/main/test/objectwrap_constructor_exception.cc.
51 // In which the Napi::ObjectWrap<> is being destructed immediately after napi_wrap.
52 // As Napi::ObjectWrap<> is a subclass of Napi::Reference<>, napi_remove_wrap
53 // in the destructor of Napi::ObjectWrap<> is called before napi_delete_reference
54 // in the destructor of Napi::Reference<>.
DeleteImmediately(napi_env env,napi_callback_info info)55 static napi_value DeleteImmediately(napi_env env, napi_callback_info info) {
56 size_t argc = 1;
57 napi_value js_obj;
58 napi_ref ref;
59 napi_valuetype type;
60
61 NODE_API_CALL(env, napi_get_cb_info(env, info, &argc, &js_obj, NULL, NULL));
62
63 NODE_API_CALL(env, napi_typeof(env, js_obj, &type));
64 NODE_API_ASSERT(env, type == napi_object, "Expected object parameter");
65
66 NODE_API_CALL(env, napi_wrap(env, js_obj, NULL, NoopDeleter, NULL, &ref));
67 NODE_API_CALL(env, napi_remove_wrap(env, js_obj, NULL));
68 NODE_API_CALL(env, napi_delete_reference(env, ref));
69
70 return NULL;
71 }
72
73 EXTERN_C_START
Init(napi_env env,napi_value exports)74 napi_value Init(napi_env env, napi_value exports) {
75 napi_value myobj_ctor;
76 NODE_API_CALL(env,
77 napi_define_class(
78 env, "MyObject", NAPI_AUTO_LENGTH, New, NULL, 0, NULL, &myobj_ctor));
79 NODE_API_CALL(env,
80 napi_set_named_property(env, exports, "MyObject", myobj_ctor));
81
82 napi_property_descriptor descriptors[] = {
83 DECLARE_NODE_API_PROPERTY("deleteImmediately", DeleteImmediately),
84 };
85 NODE_API_CALL(env, napi_define_properties(
86 env, exports, sizeof(descriptors) / sizeof(*descriptors), descriptors));
87
88 return exports;
89 }
90 EXTERN_C_END
91