From 8747614c2f29e94888e88d52478d5dc5bf8c0e74 Mon Sep 17 00:00:00 2001 From: Roy Wright Date: Tue, 12 May 2020 20:16:20 -0400 Subject: [PATCH] src: fix use of Reference with typed arrays Fixes: https://github.com/nodejs/node-addon-api/issues/702 Previously calling Value() on a Reference for a TypedArray that the enderlying object had been collected would result in an error due to a failure in creating the return value. Signed-off-by: Michael Dawson PR-URL: https://github.com/nodejs/node-addon-api/pull/726 Fixes: https://github.com/nodejs/node-addon-api/issues/702 Reviewed-By: Chengzhong Wu --- napi-inl.h | 10 ++++++++-- test/binding.cc | 2 ++ test/binding.gyp | 1 + test/index.js | 1 + test/reference.cc | 24 ++++++++++++++++++++++++ test/reference.js | 15 +++++++++++++++ 6 files changed, 51 insertions(+), 2 deletions(-) create mode 100644 test/reference.cc create mode 100644 test/reference.js diff --git a/napi-inl.h b/napi-inl.h index 90a2950..649be98 100644 --- a/napi-inl.h +++ b/napi-inl.h @@ -1740,8 +1740,14 @@ inline TypedArrayOf::TypedArrayOf() : TypedArray(), _data(nullptr) { template inline TypedArrayOf::TypedArrayOf(napi_env env, napi_value value) : TypedArray(env, value), _data(nullptr) { - napi_status status = napi_get_typedarray_info( - _env, _value, &_type, &_length, reinterpret_cast(&_data), nullptr, nullptr); + napi_status status = napi_ok; + if (value != nullptr) { + status = napi_get_typedarray_info( + _env, _value, &_type, &_length, reinterpret_cast(&_data), nullptr, nullptr); + } else { + _type = TypedArrayTypeForPrimitiveType(); + _length = 0; + } NAPI_THROW_IF_FAILED_VOID(_env, status); } diff --git a/test/binding.cc b/test/binding.cc index 829b45e..0eb22ab 100644 --- a/test/binding.cc +++ b/test/binding.cc @@ -55,6 +55,7 @@ Object InitObjectWrapConstructorException(Env env); Object InitObjectWrapRemoveWrap(Env env); Object InitObjectWrapMultipleInheritance(Env env); Object InitObjectReference(Env env); +Object InitReference(Env env); Object InitVersionManagement(Env env); Object InitThunkingManual(Env env); @@ -114,6 +115,7 @@ Object Init(Env env, Object exports) { exports.Set("objectwrap_removewrap", InitObjectWrapRemoveWrap(env)); exports.Set("objectwrap_multiple_inheritance", InitObjectWrapMultipleInheritance(env)); exports.Set("objectreference", InitObjectReference(env)); + exports.Set("reference", InitReference(env)); exports.Set("version_management", InitVersionManagement(env)); exports.Set("thunking_manual", InitThunkingManual(env)); return exports; diff --git a/test/binding.gyp b/test/binding.gyp index 2c6f791..797d811 100644 --- a/test/binding.gyp +++ b/test/binding.gyp @@ -47,6 +47,7 @@ 'objectwrap-removewrap.cc', 'objectwrap_multiple_inheritance.cc', 'objectreference.cc', + 'reference.cc', 'version_management.cc', 'thunking_manual.cc', ], diff --git a/test/index.js b/test/index.js index 09b40c2..e930eab 100644 --- a/test/index.js +++ b/test/index.js @@ -55,6 +55,7 @@ let testModules = [ 'objectwrap-removewrap', 'objectwrap_multiple_inheritance', 'objectreference', + 'reference', 'version_management' ]; diff --git a/test/reference.cc b/test/reference.cc new file mode 100644 index 0000000..f932632 --- /dev/null +++ b/test/reference.cc @@ -0,0 +1,24 @@ +#include "napi.h" + +using namespace Napi; + +static Reference> weak; + +void CreateWeakArray(const CallbackInfo& info) { + weak = Weak(Buffer::New(info.Env(), 1)); + weak.SuppressDestruct(); +} + +napi_value AccessWeakArrayEmpty(const CallbackInfo& info) { + Buffer value = weak.Value(); + return Napi::Boolean::New(info.Env(), value.IsEmpty()); +} + +Object InitReference(Env env) { + Object exports = Object::New(env); + + exports["createWeakArray"] = Function::New(env, CreateWeakArray); + exports["accessWeakArrayEmpty"] = Function::New(env, AccessWeakArrayEmpty); + + return exports; +} diff --git a/test/reference.js b/test/reference.js new file mode 100644 index 0000000..3a59e85 --- /dev/null +++ b/test/reference.js @@ -0,0 +1,15 @@ +'use strict'; + + +const buildType = process.config.target_defaults.default_configuration; +const assert = require('assert'); +const testUtil = require('./testUtil'); + +test(require(`./build/${buildType}/binding.node`)); +test(require(`./build/${buildType}/binding_noexcept.node`)); + +function test(binding) { + binding.reference.createWeakArray(); + global.gc(); + assert.strictEqual(true, binding.reference.accessWeakArrayEmpty()); +};