diff --git a/src/api/environment.cc b/src/api/environment.cc index 3476f4355b3084..ab320f41103a90 100644 --- a/src/api/environment.cc +++ b/src/api/environment.cc @@ -71,7 +71,7 @@ static void OnMessage(Local message, Local error) { } } -void* ArrayBufferAllocator::Allocate(size_t size) { +void* NodeArrayBufferAllocator::Allocate(size_t size) { if (zero_fill_field_ || per_process::cli_options->zero_fill_all_buffers) return UncheckedCalloc(size); else @@ -84,14 +84,14 @@ DebuggingArrayBufferAllocator::~DebuggingArrayBufferAllocator() { void* DebuggingArrayBufferAllocator::Allocate(size_t size) { Mutex::ScopedLock lock(mutex_); - void* data = ArrayBufferAllocator::Allocate(size); + void* data = NodeArrayBufferAllocator::Allocate(size); RegisterPointerInternal(data, size); return data; } void* DebuggingArrayBufferAllocator::AllocateUninitialized(size_t size) { Mutex::ScopedLock lock(mutex_); - void* data = ArrayBufferAllocator::AllocateUninitialized(size); + void* data = NodeArrayBufferAllocator::AllocateUninitialized(size); RegisterPointerInternal(data, size); return data; } @@ -99,14 +99,14 @@ void* DebuggingArrayBufferAllocator::AllocateUninitialized(size_t size) { void DebuggingArrayBufferAllocator::Free(void* data, size_t size) { Mutex::ScopedLock lock(mutex_); UnregisterPointerInternal(data, size); - ArrayBufferAllocator::Free(data, size); + NodeArrayBufferAllocator::Free(data, size); } void* DebuggingArrayBufferAllocator::Reallocate(void* data, size_t old_size, size_t size) { Mutex::ScopedLock lock(mutex_); - void* ret = ArrayBufferAllocator::Reallocate(data, old_size, size); + void* ret = NodeArrayBufferAllocator::Reallocate(data, old_size, size); if (ret == nullptr) { if (size == 0) // i.e. equivalent to free(). UnregisterPointerInternal(data, old_size); @@ -149,11 +149,15 @@ void DebuggingArrayBufferAllocator::RegisterPointerInternal(void* data, allocations_[data] = size; } -ArrayBufferAllocator* CreateArrayBufferAllocator() { - if (per_process::cli_options->debug_arraybuffer_allocations) - return new DebuggingArrayBufferAllocator(); +std::unique_ptr ArrayBufferAllocator::Create(bool debug) { + if (debug || per_process::cli_options->debug_arraybuffer_allocations) + return std::make_unique(); else - return new ArrayBufferAllocator(); + return std::make_unique(); +} + +ArrayBufferAllocator* CreateArrayBufferAllocator() { + return ArrayBufferAllocator::Create().release(); } void FreeArrayBufferAllocator(ArrayBufferAllocator* allocator) { diff --git a/src/env-inl.h b/src/env-inl.h index 7c35b4e43feb05..afa744e0281667 100644 --- a/src/env-inl.h +++ b/src/env-inl.h @@ -56,7 +56,7 @@ inline v8::ArrayBuffer::Allocator* IsolateData::allocator() const { return allocator_; } -inline ArrayBufferAllocator* IsolateData::node_allocator() const { +inline NodeArrayBufferAllocator* IsolateData::node_allocator() const { return node_allocator_; } diff --git a/src/env.cc b/src/env.cc index 9feab1c0ca8448..302b0223830604 100644 --- a/src/env.cc +++ b/src/env.cc @@ -80,7 +80,8 @@ IsolateData::IsolateData(Isolate* isolate, : isolate_(isolate), event_loop_(event_loop), allocator_(isolate->GetArrayBufferAllocator()), - node_allocator_(node_allocator), + node_allocator_(node_allocator == nullptr ? + nullptr : node_allocator->GetImpl()), uses_node_allocator_(allocator_ == node_allocator_), platform_(platform) { CHECK_NOT_NULL(allocator_); diff --git a/src/env.h b/src/env.h index 2890da725c5e02..36f0d555819497 100644 --- a/src/env.h +++ b/src/env.h @@ -408,7 +408,7 @@ class IsolateData { inline bool uses_node_allocator() const; inline v8::ArrayBuffer::Allocator* allocator() const; - inline ArrayBufferAllocator* node_allocator() const; + inline NodeArrayBufferAllocator* node_allocator() const; #define VP(PropertyName, StringValue) V(v8::Private, PropertyName) #define VY(PropertyName, StringValue) V(v8::Symbol, PropertyName) @@ -445,7 +445,7 @@ class IsolateData { v8::Isolate* const isolate_; uv_loop_t* const event_loop_; v8::ArrayBuffer::Allocator* const allocator_; - ArrayBufferAllocator* const node_allocator_; + NodeArrayBufferAllocator* const node_allocator_; const bool uses_node_allocator_; MultiIsolatePlatform* platform_; std::shared_ptr options_; diff --git a/src/node.h b/src/node.h index 68cc41f3170a39..d4cde16e45e9c3 100644 --- a/src/node.h +++ b/src/node.h @@ -64,6 +64,8 @@ #include "v8-platform.h" // NOLINT(build/include_order) #include "node_version.h" // NODE_MODULE_VERSION +#include + #define NODE_MAKE_VERSION(major, minor, patch) \ ((major) * 0x1000 + (minor) * 0x100 + (patch)) @@ -217,8 +219,30 @@ NODE_EXTERN void Init(int* argc, int* exec_argc, const char*** exec_argv); -class ArrayBufferAllocator; +class NodeArrayBufferAllocator; + +// An ArrayBuffer::Allocator class with some Node.js-specific tweaks. If you do +// not have to use another allocator, using this class is recommended: +// - It supports Buffer.allocUnsafe() and Buffer.allocUnsafeSlow() with +// uninitialized memory. +// - It supports transferring, rather than copying, ArrayBuffers when using +// MessagePorts. +class NODE_EXTERN ArrayBufferAllocator : public v8::ArrayBuffer::Allocator { + public: + // If `always_debug` is true, create an ArrayBuffer::Allocator instance + // that performs additional integrity checks (e.g. make sure that only memory + // that was allocated by the it is also freed by it). + // This can also be set using the --debug-arraybuffer-allocations flag. + static std::unique_ptr Create( + bool always_debug = false); + + private: + virtual NodeArrayBufferAllocator* GetImpl() = 0; + + friend class IsolateData; +}; +// Legacy equivalents for ArrayBufferAllocator::Create(). NODE_EXTERN ArrayBufferAllocator* CreateArrayBufferAllocator(); NODE_EXTERN void FreeArrayBufferAllocator(ArrayBufferAllocator* allocator); diff --git a/src/node_buffer.cc b/src/node_buffer.cc index dfaa3541611b60..9379a4680c5454 100644 --- a/src/node_buffer.cc +++ b/src/node_buffer.cc @@ -1099,7 +1099,8 @@ void Initialize(Local target, // It can be a nullptr when running inside an isolate where we // do not own the ArrayBuffer allocator. - if (ArrayBufferAllocator* allocator = env->isolate_data()->node_allocator()) { + if (NodeArrayBufferAllocator* allocator = + env->isolate_data()->node_allocator()) { uint32_t* zero_fill_field = allocator->zero_fill_field(); Local array_buffer = ArrayBuffer::New( env->isolate(), zero_fill_field, sizeof(*zero_fill_field)); diff --git a/src/node_internals.h b/src/node_internals.h index 0a25d9a1a97c0f..cf796178a4dd82 100644 --- a/src/node_internals.h +++ b/src/node_internals.h @@ -101,7 +101,7 @@ namespace task_queue { void PromiseRejectCallback(v8::PromiseRejectMessage message); } // namespace task_queue -class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator { +class NodeArrayBufferAllocator : public ArrayBufferAllocator { public: inline uint32_t* zero_fill_field() { return &zero_fill_field_; } @@ -116,11 +116,13 @@ class ArrayBufferAllocator : public v8::ArrayBuffer::Allocator { virtual void RegisterPointer(void* data, size_t size) {} virtual void UnregisterPointer(void* data, size_t size) {} + NodeArrayBufferAllocator* GetImpl() final { return this; } + private: uint32_t zero_fill_field_ = 1; // Boolean but exposed as uint32 to JS land. }; -class DebuggingArrayBufferAllocator final : public ArrayBufferAllocator { +class DebuggingArrayBufferAllocator final : public NodeArrayBufferAllocator { public: ~DebuggingArrayBufferAllocator() override; void* Allocate(size_t size) override;