Skip to content

Commit a55092f

Browse files
committed
src: allocate Buffer memory using ArrayBuffer allocator
Always use the right allocator for memory that is turned into an `ArrayBuffer` at a later point. This enables embedders to use their own `ArrayBuffer::Allocator`s, and is inspired by Electron’s electron/node@f61bae3440e. It should render their downstream patch unnecessary. Refs: electron/node@f61bae3
1 parent 5854771 commit a55092f

16 files changed

+256
-319
lines changed

src/node_buffer.cc

+40-58
Original file line numberDiff line numberDiff line change
@@ -54,17 +54,6 @@
5454
size_t length = end - start;
5555

5656
namespace node {
57-
58-
namespace {
59-
60-
inline void* BufferMalloc(size_t length) {
61-
return per_process::cli_options->zero_fill_all_buffers ?
62-
node::UncheckedCalloc(length) :
63-
node::UncheckedMalloc(length);
64-
}
65-
66-
} // namespace
67-
6857
namespace Buffer {
6958

7059
using v8::ArrayBuffer;
@@ -260,7 +249,7 @@ MaybeLocal<Object> New(Isolate* isolate,
260249
char* data = nullptr;
261250

262251
if (length > 0) {
263-
data = static_cast<char*>(BufferMalloc(length));
252+
data = UncheckedMalloc(length);
264253

265254
if (data == nullptr) {
266255
THROW_ERR_MEMORY_ALLOCATION_FAILED(isolate);
@@ -278,13 +267,7 @@ MaybeLocal<Object> New(Isolate* isolate,
278267
}
279268
}
280269

281-
Local<Object> buf;
282-
if (New(isolate, data, actual).ToLocal(&buf))
283-
return scope.Escape(buf);
284-
285-
// Object failed to be created. Clean up resources.
286-
free(data);
287-
return Local<Object>();
270+
return scope.EscapeMaybe(New(isolate, data, actual));
288271
}
289272

290273

@@ -311,26 +294,16 @@ MaybeLocal<Object> New(Environment* env, size_t length) {
311294
return Local<Object>();
312295
}
313296

314-
void* data;
297+
AllocatedBuffer ret(env);
315298
if (length > 0) {
316-
data = BufferMalloc(length);
317-
if (data == nullptr) {
299+
ret = env->AllocateManaged(length, false);
300+
if (ret.data() == nullptr) {
318301
THROW_ERR_MEMORY_ALLOCATION_FAILED(env);
319302
return Local<Object>();
320303
}
321-
} else {
322-
data = nullptr;
323304
}
324305

325-
Local<ArrayBuffer> ab =
326-
ArrayBuffer::New(env->isolate(),
327-
data,
328-
length,
329-
ArrayBufferCreationMode::kInternalized);
330-
Local<Object> obj;
331-
if (Buffer::New(env, ab, 0, length).ToLocal(&obj))
332-
return scope.Escape(obj);
333-
return Local<Object>();
306+
return scope.EscapeMaybe(ret.ToBuffer());
334307
}
335308

336309

@@ -357,28 +330,18 @@ MaybeLocal<Object> Copy(Environment* env, const char* data, size_t length) {
357330
return Local<Object>();
358331
}
359332

360-
void* new_data;
333+
AllocatedBuffer ret(env);
361334
if (length > 0) {
362335
CHECK_NOT_NULL(data);
363-
new_data = node::UncheckedMalloc(length);
364-
if (new_data == nullptr) {
336+
ret = env->AllocateManaged(length, false);
337+
if (ret.data() == nullptr) {
365338
THROW_ERR_MEMORY_ALLOCATION_FAILED(env);
366339
return Local<Object>();
367340
}
368-
memcpy(new_data, data, length);
369-
} else {
370-
new_data = nullptr;
341+
memcpy(ret.data(), data, length);
371342
}
372343

373-
Local<ArrayBuffer> ab =
374-
ArrayBuffer::New(env->isolate(),
375-
new_data,
376-
length,
377-
ArrayBufferCreationMode::kInternalized);
378-
Local<Object> obj;
379-
if (Buffer::New(env, ab, 0, length).ToLocal(&obj))
380-
return scope.Escape(obj);
381-
return Local<Object>();
344+
return scope.EscapeMaybe(ret.ToBuffer());
382345
}
383346

384347

@@ -425,7 +388,8 @@ MaybeLocal<Object> New(Environment* env,
425388
return scope.Escape(ui.ToLocalChecked());
426389
}
427390

428-
391+
// Warning: This function needs `data` to be allocated with malloc() and not
392+
// necessarily isolate's ArrayBuffer::Allocator.
429393
MaybeLocal<Object> New(Isolate* isolate, char* data, size_t length) {
430394
EscapableHandleScope handle_scope(isolate);
431395
Environment* env = Environment::GetCurrent(isolate);
@@ -435,18 +399,37 @@ MaybeLocal<Object> New(Isolate* isolate, char* data, size_t length) {
435399
return MaybeLocal<Object>();
436400
}
437401
Local<Object> obj;
438-
if (Buffer::New(env, data, length).ToLocal(&obj))
402+
if (Buffer::New(env, data, length, true).ToLocal(&obj))
439403
return handle_scope.Escape(obj);
440404
return Local<Object>();
441405
}
442406

443-
444-
MaybeLocal<Object> New(Environment* env, char* data, size_t length) {
407+
// Warning: If this call comes through the public node_buffer.h API,
408+
// the contract for this function is that `data` is allocated with malloc()
409+
// and not necessarily isolate's ArrayBuffer::Allocator.
410+
MaybeLocal<Object> New(Environment* env,
411+
char* data,
412+
size_t length,
413+
bool uses_malloc) {
445414
if (length > 0) {
446415
CHECK_NOT_NULL(data);
447416
CHECK(length <= kMaxLength);
448417
}
449418

419+
if (uses_malloc) {
420+
if (env->isolate_data()->uses_node_allocator()) {
421+
// We don't know for sure that the allocator is malloc()-based, so we need
422+
// to fall back to the FreeCallback variant.
423+
auto free_callback = [](char* data, void* hint) { free(data); };
424+
return New(env, data, length, free_callback, nullptr);
425+
} else {
426+
// This is malloc()-based, so we can acquire it into our own
427+
// ArrayBufferAllocator.
428+
CHECK_NOT_NULL(env->isolate_data()->node_allocator());
429+
env->isolate_data()->node_allocator()->RegisterPointer(data, length);
430+
}
431+
}
432+
450433
Local<ArrayBuffer> ab =
451434
ArrayBuffer::New(env->isolate(),
452435
data,
@@ -1053,15 +1036,13 @@ static void EncodeUtf8String(const FunctionCallbackInfo<Value>& args) {
10531036

10541037
Local<String> str = args[0].As<String>();
10551038
size_t length = str->Utf8Length(isolate);
1056-
char* data = node::UncheckedMalloc(length);
1039+
AllocatedBuffer buf = env->AllocateManaged(length);
10571040
str->WriteUtf8(isolate,
1058-
data,
1041+
buf.data(),
10591042
-1, // We are certain that `data` is sufficiently large
10601043
nullptr,
10611044
String::NO_NULL_TERMINATION | String::REPLACE_INVALID_UTF8);
1062-
auto array_buf = ArrayBuffer::New(
1063-
isolate, data, length, ArrayBufferCreationMode::kInternalized);
1064-
auto array = Uint8Array::New(array_buf, 0, length);
1045+
auto array = Uint8Array::New(buf.ToArrayBuffer(), 0, length);
10651046
args.GetReturnValue().Set(array);
10661047
}
10671048

@@ -1123,7 +1104,8 @@ void Initialize(Local<Object> target,
11231104

11241105
// It can be a nullptr when running inside an isolate where we
11251106
// do not own the ArrayBuffer allocator.
1126-
if (uint32_t* zero_fill_field = env->isolate_data()->zero_fill_field()) {
1107+
if (ArrayBufferAllocator* allocator = env->isolate_data()->node_allocator()) {
1108+
uint32_t* zero_fill_field = allocator->zero_fill_field();
11271109
Local<ArrayBuffer> array_buffer = ArrayBuffer::New(
11281110
env->isolate(), zero_fill_field, sizeof(*zero_fill_field));
11291111
CHECK(target

0 commit comments

Comments
 (0)