• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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