Skip to content

Commit f4bbfee

Browse files
authored
Refcount for v8impl::Reference should be unsigned (nodejs#207)
* Refcount for v8impl::Reference should be unsigned Add ```Reference::RefCount()``` and check the refcount value before trying to call ```Reference::Unref()``` to avoid underflowing the refcount. This allows us to continue returning an error from ```napi_reference_unref``` if it is called with a reference that already has refcount set to zero. * Add check for _refcount == 0 in Reference::Unref to avoid an underflow
1 parent 38aad51 commit f4bbfee

2 files changed

Lines changed: 23 additions & 15 deletions

File tree

‎src/node_api.cc‎

Lines changed: 20 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -144,7 +144,7 @@ class Reference : private Finalizer {
144144
private:
145145
Reference(v8::Isolate* isolate,
146146
v8::Local<v8::Value> value,
147-
int initial_refcount,
147+
uint32_t initial_refcount,
148148
bool delete_self,
149149
napi_finalize finalize_callback,
150150
void* finalize_data,
@@ -173,7 +173,7 @@ class Reference : private Finalizer {
173173
public:
174174
static Reference* New(v8::Isolate* isolate,
175175
v8::Local<v8::Value> value,
176-
int initial_refcount,
176+
uint32_t initial_refcount,
177177
bool delete_self,
178178
napi_finalize finalize_callback = nullptr,
179179
void* finalize_data = nullptr,
@@ -191,15 +191,18 @@ class Reference : private Finalizer {
191191
delete reference;
192192
}
193193

194-
int Ref() {
194+
uint32_t Ref() {
195195
if (++_refcount == 1) {
196196
_persistent.ClearWeak();
197197
}
198198

199199
return _refcount;
200200
}
201201

202-
int Unref() {
202+
uint32_t Unref() {
203+
if (_refcount == 0) {
204+
return 0;
205+
}
203206
if (--_refcount == 0) {
204207
_persistent.SetWeak(
205208
this, FinalizeCallback, v8::WeakCallbackType::kParameter);
@@ -209,6 +212,10 @@ class Reference : private Finalizer {
209212
return _refcount;
210213
}
211214

215+
uint32_t RefCount() {
216+
return _refcount;
217+
}
218+
212219
v8::Local<v8::Value> Get() {
213220
if (_persistent.IsEmpty()) {
214221
return v8::Local<v8::Value>();
@@ -239,7 +246,7 @@ class Reference : private Finalizer {
239246
}
240247

241248
v8::Persistent<v8::Value> _persistent;
242-
int _refcount;
249+
uint32_t _refcount;
243250
bool _delete_self;
244251
};
245252

@@ -1901,11 +1908,10 @@ napi_status napi_get_value_external(napi_env env,
19011908
// Set initial_refcount to 0 for a weak reference, >0 for a strong reference.
19021909
napi_status napi_create_reference(napi_env env,
19031910
napi_value value,
1904-
int initial_refcount,
1911+
uint32_t initial_refcount,
19051912
napi_ref* result) {
19061913
NAPI_PREAMBLE(env);
19071914
CHECK_ARG(result);
1908-
RETURN_STATUS_IF_FALSE(initial_refcount >= 0, napi_invalid_arg);
19091915

19101916
v8::Isolate* isolate = v8impl::V8IsolateFromJsEnv(env);
19111917

@@ -1933,12 +1939,12 @@ napi_status napi_delete_reference(napi_env env, napi_ref ref) {
19331939
// refcount is >0, and the referenced object is effectively "pinned".
19341940
// Calling this when the refcount is 0 and the object is unavailable
19351941
// results in an error.
1936-
napi_status napi_reference_ref(napi_env env, napi_ref ref, int* result) {
1942+
napi_status napi_reference_ref(napi_env env, napi_ref ref, uint32_t* result) {
19371943
NAPI_PREAMBLE(env);
19381944
CHECK_ARG(ref);
19391945

19401946
v8impl::Reference* reference = reinterpret_cast<v8impl::Reference*>(ref);
1941-
int count = reference->Ref();
1947+
uint32_t count = reference->Ref();
19421948

19431949
if (result != nullptr) {
19441950
*result = count;
@@ -1951,16 +1957,18 @@ napi_status napi_reference_ref(napi_env env, napi_ref ref, int* result) {
19511957
// the result is 0 the reference is now weak and the object may be GC'd at any
19521958
// time if there are no other references. Calling this when the refcount is
19531959
// already 0 results in an error.
1954-
napi_status napi_reference_unref(napi_env env, napi_ref ref, int* result) {
1960+
napi_status napi_reference_unref(napi_env env, napi_ref ref, uint32_t* result) {
19551961
NAPI_PREAMBLE(env);
19561962
CHECK_ARG(ref);
19571963

19581964
v8impl::Reference* reference = reinterpret_cast<v8impl::Reference*>(ref);
1959-
int count = reference->Unref();
1960-
if (count < 0) {
1965+
1966+
if (reference->RefCount() == 0) {
19611967
return napi_set_last_error(napi_generic_failure);
19621968
}
19631969

1970+
uint32_t count = reference->Unref();
1971+
19641972
if (result != nullptr) {
19651973
*result = count;
19661974
}

‎src/node_api.h‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -352,7 +352,7 @@ NAPI_EXTERN napi_status napi_get_value_external(napi_env env,
352352
// Set initial_refcount to 0 for a weak reference, >0 for a strong reference.
353353
NAPI_EXTERN napi_status napi_create_reference(napi_env env,
354354
napi_value value,
355-
int initial_refcount,
355+
uint32_t initial_refcount,
356356
napi_ref* result);
357357

358358
// Deletes a reference. The referenced value is released, and may
@@ -366,15 +366,15 @@ NAPI_EXTERN napi_status napi_delete_reference(napi_env env, napi_ref ref);
366366
// results in an error.
367367
NAPI_EXTERN napi_status napi_reference_ref(napi_env env,
368368
napi_ref ref,
369-
int* result);
369+
uint32_t* result);
370370

371371
// Decrements the reference count, optionally returning the resulting count.
372372
// If the result is 0 the reference is now weak and the object may be GC'd
373373
// at any time if there are no other references. Calling this when the
374374
// refcount is already 0 results in an error.
375375
NAPI_EXTERN napi_status napi_reference_unref(napi_env env,
376376
napi_ref ref,
377-
int* result);
377+
uint32_t* result);
378378

379379
// Attempts to get a referenced value. If the reference is weak,
380380
// the value might no longer be available, in that case the call

0 commit comments

Comments
 (0)