diff --git a/napi-inl.h b/napi-inl.h index 5ecdd5046..5866fd89c 100644 --- a/napi-inl.h +++ b/napi-inl.h @@ -1530,6 +1530,20 @@ inline size_t ArrayBuffer::ByteLength() { return length; } +#if NAPI_VERSION >= 7 +inline bool ArrayBuffer::IsDetached() const { + bool detached; + napi_status status = napi_is_detached_arraybuffer(_env, _value, &detached); + NAPI_THROW_IF_FAILED(_env, status, false); + return detached; +} + +inline void ArrayBuffer::Detach() { + napi_status status = napi_detach_arraybuffer(_env, _value); + NAPI_THROW_IF_FAILED_VOID(_env, status); +} +#endif // NAPI_VERSION >= 7 + //////////////////////////////////////////////////////////////////////////////// // DataView class //////////////////////////////////////////////////////////////////////////////// diff --git a/napi.h b/napi.h index 76a62f659..945aac55e 100644 --- a/napi.h +++ b/napi.h @@ -822,6 +822,11 @@ namespace Napi { void* Data(); ///< Gets a pointer to the data buffer. size_t ByteLength(); ///< Gets the length of the array buffer in bytes. + +#if NAPI_VERSION >= 7 + bool IsDetached() const; + void Detach(); +#endif // NAPI_VERSION >= 7 }; /// A JavaScript typed-array value with unknown array type. diff --git a/test/arraybuffer.cc b/test/arraybuffer.cc index cc4f1f51c..4a1b2a34e 100644 --- a/test/arraybuffer.cc +++ b/test/arraybuffer.cc @@ -157,19 +157,43 @@ void CheckDetachUpdatesData(const CallbackInfo& info) { return; } - if (!info[1].IsFunction()) { - Error::New(info.Env(), "A function was expected.").ThrowAsJavaScriptException(); - return; - } - ArrayBuffer buffer = info[0].As(); - Function detach = info[1].As(); // This potentially causes the buffer to cache its data pointer and length. buffer.Data(); buffer.ByteLength(); - detach.Call({}); +#if NAPI_VERSION >= 7 + if (buffer.IsDetached()) { + Error::New(info.Env(), "Buffer should not be detached.").ThrowAsJavaScriptException(); + return; + } +#endif + + if (info.Length() == 2) { + // Detach externally (in JavaScript). + if (!info[1].IsFunction()) { + Error::New(info.Env(), "A function was expected.").ThrowAsJavaScriptException(); + return; + } + + Function detach = info[1].As(); + detach.Call({}); + } else { +#if NAPI_VERSION >= 7 + // Detach directly. + buffer.Detach(); +#else + return; +#endif + } + +#if NAPI_VERSION >= 7 + if (!buffer.IsDetached()) { + Error::New(info.Env(), "Buffer should be detached.").ThrowAsJavaScriptException(); + return; + } +#endif if (buffer.Data() != nullptr) { Error::New(info.Env(), "Incorrect data pointer.").ThrowAsJavaScriptException(); diff --git a/test/arraybuffer.js b/test/arraybuffer.js index 38d35d1e7..363de17d9 100644 --- a/test/arraybuffer.js +++ b/test/arraybuffer.js @@ -58,8 +58,13 @@ function test(binding) { 'ArrayBuffer updates data pointer and length when detached', () => { + // Detach the ArrayBuffer in JavaScript. const mem = new WebAssembly.Memory({ initial: 1 }); binding.arraybuffer.checkDetachUpdatesData(mem.buffer, () => mem.grow(1)); + + // Let C++ detach the ArrayBuffer. + const extBuffer = binding.arraybuffer.createExternalBuffer(); + binding.arraybuffer.checkDetachUpdatesData(extBuffer); }, ]); }