buffer: release buffers with free callbacks on env exit

Invoke the free callback for a given `Buffer` if it was created
with one, and mark the underlying `ArrayBuffer` as detached.

This makes sure that the memory is released e.g. when addons inside
Workers create such `Buffer`s.

PR-URL: https://github.com/nodejs/node/pull/30551
Reviewed-By: Gabriel Schulhof <gabriel.schulhof@intel.com>
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: Denys Otrishko <shishugi@gmail.com>
Reviewed-By: Michael Dawson <michael_dawson@ca.ibm.com>
This commit is contained in:
Anna Henningsen committed 2019-11-30 02:02:50 +01:00
1 parent ab2afa3379
commit b7ef593744
4 files changed
+95 -10

No files matched your search

+36 -9
View File
@@ -53,6 +53,7 @@ using v8::Context;
using v8::EscapableHandleScope;
using v8::FunctionCallbackInfo;
using v8::Global;
using v8::HandleScope;
using v8::Int32;
using v8::Integer;
using v8::Isolate;
@@ -73,8 +74,10 @@ namespace {
class CallbackInfo {
public:
~CallbackInfo();
static inline void Free(char* data, void* hint);
static inline CallbackInfo* New(Isolate* isolate,
static inline CallbackInfo* New(Environment* env,
Local<ArrayBuffer> object,
FreeCallback callback,
char* data,
@@ -84,9 +87,10 @@ class CallbackInfo {
CallbackInfo& operator=(const CallbackInfo&) = delete;
private:
static void CleanupHook(void* data);
static void WeakCallback(const WeakCallbackInfo<CallbackInfo>&);
inline void WeakCallback(Isolate* isolate);
inline CallbackInfo(Isolate* isolate,
inline CallbackInfo(Environment* env,
Local<ArrayBuffer> object,
FreeCallback callback,
char* data,
@@ -95,6 +99,7 @@ class CallbackInfo {
FreeCallback const callback_;
char* const data_;
void* const hint_;
Environment* const env_;
};
@@ -103,31 +108,53 @@ void CallbackInfo::Free(char* data, void*) {
}
CallbackInfo* CallbackInfo::New(Isolate* isolate,
CallbackInfo* CallbackInfo::New(Environment* env,
Local<ArrayBuffer> object,
FreeCallback callback,
char* data,
void* hint) {
return new CallbackInfo(isolate, object, callback, data, hint);
return new CallbackInfo(env, object, callback, data, hint);
}
CallbackInfo::CallbackInfo(Isolate* isolate,
CallbackInfo::CallbackInfo(Environment* env,
Local<ArrayBuffer> object,
FreeCallback callback,
char* data,
void* hint)
: persistent_(isolate, object),
: persistent_(env->isolate(), object),
callback_(callback),
data_(data),
hint_(hint) {
hint_(hint),
env_(env) {
ArrayBuffer::Contents obj_c = object->GetContents();
CHECK_EQ(data_, static_cast<char*>(obj_c.Data()));
if (object->ByteLength() != 0)
CHECK_NOT_NULL(data_);
persistent_.SetWeak(this, WeakCallback, v8::WeakCallbackType::kParameter);
isolate->AdjustAmountOfExternalAllocatedMemory(sizeof(*this));
env->AddCleanupHook(CleanupHook, this);
env->isolate()->AdjustAmountOfExternalAllocatedMemory(sizeof(*this));
}
CallbackInfo::~CallbackInfo() {
persistent_.Reset();
env_->RemoveCleanupHook(CleanupHook, this);
}
void CallbackInfo::CleanupHook(void* data) {
CallbackInfo* self = static_cast<CallbackInfo*>(data);
{
HandleScope handle_scope(self->env_->isolate());
Local<ArrayBuffer> ab = self->persistent_.Get(self->env_->isolate());
CHECK(!ab.IsEmpty());
ab->Detach();
}
self->WeakCallback(self->env_->isolate());
}
@@ -388,7 +415,7 @@ MaybeLocal<Object> New(Environment* env,
}
MaybeLocal<Uint8Array> ui = Buffer::New(env, ab, 0, length);
CallbackInfo::New(env->isolate(), ab, callback, data, hint);
CallbackInfo::New(env, ab, callback, data, hint);
if (ui.IsEmpty())
return MaybeLocal<Object>();