Skip to content
This repository was archived by the owner on Mar 4, 2020. It is now read-only.

Commit f61bae3

Browse files
zcbenzalexeykuzmin
authored andcommittedMay 29, 2018
Allocate memory of Buffer with V8's allocator
(cherry picked from commit 813a45f) (cherry picked from commit cbbe8e8)
1 parent 201f3b6 commit f61bae3

File tree

6 files changed

+101
-52
lines changed

6 files changed

+101
-52
lines changed
 

‎src/node_buffer.cc

+14-11
Original file line numberDiff line numberDiff line change
@@ -61,9 +61,10 @@ bool zero_fill_all_buffers = false;
6161

6262
namespace {
6363

64-
inline void* BufferMalloc(size_t length) {
65-
return zero_fill_all_buffers ? node::UncheckedCalloc(length) :
66-
node::UncheckedMalloc(length);
64+
inline void* BufferMalloc(v8::Isolate* isolate, size_t length) {
65+
auto* allocator = isolate->GetArrayBufferAllocator();
66+
return zero_fill_all_buffers ? allocator->Allocate(length) :
67+
allocator->AllocateUninitialized(length);
6768
}
6869

6970
} // namespace
@@ -241,7 +242,7 @@ MaybeLocal<Object> New(Isolate* isolate,
241242
char* data = nullptr;
242243

243244
if (length > 0) {
244-
data = static_cast<char*>(BufferMalloc(length));
245+
data = static_cast<char*>(BufferMalloc(isolate, length));
245246

246247
if (data == nullptr)
247248
return Local<Object>();
@@ -250,10 +251,11 @@ MaybeLocal<Object> New(Isolate* isolate,
250251
CHECK(actual <= length);
251252

252253
if (actual == 0) {
253-
free(data);
254+
isolate->GetArrayBufferAllocator()->Free(data, length);
254255
data = nullptr;
255256
} else if (actual < length) {
256-
data = node::Realloc(data, actual);
257+
// We should call realloc here, but v8::ArrayBufferAllocator does not
258+
// provide such ability.
257259
}
258260
}
259261

@@ -262,7 +264,7 @@ MaybeLocal<Object> New(Isolate* isolate,
262264
return scope.Escape(buf);
263265

264266
// Object failed to be created. Clean up resources.
265-
free(data);
267+
isolate->GetArrayBufferAllocator()->Free(data, length);
266268
return Local<Object>();
267269
}
268270

@@ -286,7 +288,7 @@ MaybeLocal<Object> New(Environment* env, size_t length) {
286288

287289
void* data;
288290
if (length > 0) {
289-
data = BufferMalloc(length);
291+
data = BufferMalloc(env->isolate(), length);
290292
if (data == nullptr)
291293
return Local<Object>();
292294
} else {
@@ -302,7 +304,7 @@ MaybeLocal<Object> New(Environment* env, size_t length) {
302304

303305
if (ui.IsEmpty()) {
304306
// Object failed to be created. Clean up resources.
305-
free(data);
307+
env->isolate()->GetArrayBufferAllocator()->Free(data, length);
306308
}
307309

308310
return scope.Escape(ui.FromMaybe(Local<Uint8Array>()));
@@ -327,10 +329,11 @@ MaybeLocal<Object> Copy(Environment* env, const char* data, size_t length) {
327329
return Local<Object>();
328330
}
329331

332+
auto* allocator = env->isolate()->GetArrayBufferAllocator();
330333
void* new_data;
331334
if (length > 0) {
332335
CHECK_NE(data, nullptr);
333-
new_data = node::UncheckedMalloc(length);
336+
new_data = allocator->AllocateUninitialized(length);
334337
if (new_data == nullptr)
335338
return Local<Object>();
336339
memcpy(new_data, data, length);
@@ -347,7 +350,7 @@ MaybeLocal<Object> Copy(Environment* env, const char* data, size_t length) {
347350

348351
if (ui.IsEmpty()) {
349352
// Object failed to be created. Clean up resources.
350-
free(new_data);
353+
allocator->Free(new_data, length);
351354
}
352355

353356
return scope.Escape(ui.FromMaybe(Local<Uint8Array>()));

‎src/node_crypto.cc

+47-26
Original file line numberDiff line numberDiff line change
@@ -1890,7 +1890,8 @@ void SSLWrap<Base>::GetSession(const FunctionCallbackInfo<Value>& args) {
18901890
int slen = i2d_SSL_SESSION(sess, nullptr);
18911891
CHECK_GT(slen, 0);
18921892

1893-
char* sbuf = Malloc(slen);
1893+
auto* allocator = env->isolate()->GetArrayBufferAllocator();
1894+
char* sbuf = static_cast<char*>(allocator->AllocateUninitialized(slen));
18941895
unsigned char* p = reinterpret_cast<unsigned char*>(sbuf);
18951896
i2d_SSL_SESSION(sess, &p);
18961897
args.GetReturnValue().Set(Buffer::New(env, sbuf, slen).ToLocalChecked());
@@ -3011,7 +3012,8 @@ CipherBase::UpdateResult CipherBase::Update(const char* data,
30113012
return kErrorState;
30123013
}
30133014

3014-
*out = Malloc<unsigned char>(buff_len);
3015+
auto* allocator = env()->isolate()->GetArrayBufferAllocator();
3016+
*out = static_cast<unsigned char*>(allocator->AllocateUninitialized(buff_len));
30153017
int r = EVP_CipherUpdate(ctx_.get(),
30163018
*out,
30173019
out_len,
@@ -3053,7 +3055,8 @@ void CipherBase::Update(const FunctionCallbackInfo<Value>& args) {
30533055
}
30543056

30553057
if (r != kSuccess) {
3056-
free(out);
3058+
auto* allocator = env->isolate()->GetArrayBufferAllocator();
3059+
allocator->Free(out, out_len);
30573060
if (r == kErrorState) {
30583061
ThrowCryptoError(env, ERR_get_error(),
30593062
"Trying to add data in unsupported state");
@@ -3091,8 +3094,9 @@ bool CipherBase::Final(unsigned char** out, int* out_len) {
30913094

30923095
const int mode = EVP_CIPHER_CTX_mode(ctx_.get());
30933096

3094-
*out = Malloc<unsigned char>(
3095-
static_cast<size_t>(EVP_CIPHER_CTX_block_size(ctx_.get())));
3097+
auto* allocator = env()->isolate()->GetArrayBufferAllocator();
3098+
*out = static_cast<unsigned char*>(allocator->AllocateUninitialized(
3099+
EVP_CIPHER_CTX_block_size(ctx_.get())));
30963100

30973101
// In CCM mode, final() only checks whether authentication failed in update().
30983102
// EVP_CipherFinal_ex must not be called and will fail.
@@ -3135,7 +3139,8 @@ void CipherBase::Final(const FunctionCallbackInfo<Value>& args) {
31353139
bool r = cipher->Final(&out_value, &out_len);
31363140

31373141
if (out_len <= 0 || !r) {
3138-
free(out_value);
3142+
auto* allocator = env->isolate()->GetArrayBufferAllocator();
3143+
allocator->Free(out_value, out_len);
31393144
out_value = nullptr;
31403145
out_len = 0;
31413146
if (!r) {
@@ -3781,7 +3786,8 @@ void Verify::VerifyFinal(const FunctionCallbackInfo<Value>& args) {
37813786
template <PublicKeyCipher::Operation operation,
37823787
PublicKeyCipher::EVP_PKEY_cipher_init_t EVP_PKEY_cipher_init,
37833788
PublicKeyCipher::EVP_PKEY_cipher_t EVP_PKEY_cipher>
3784-
bool PublicKeyCipher::Cipher(const char* key_pem,
3789+
bool PublicKeyCipher::Cipher(Environment* env,
3790+
const char* key_pem,
37853791
int key_pem_len,
37863792
const char* passphrase,
37873793
int padding,
@@ -3790,6 +3796,7 @@ bool PublicKeyCipher::Cipher(const char* key_pem,
37903796
unsigned char** out,
37913797
size_t* out_len) {
37923798
EVPKeyPointer pkey;
3799+
auto* allocator = env->isolate()->GetArrayBufferAllocator();
37933800

37943801
BIOPointer bp(BIO_new_mem_buf(const_cast<char*>(key_pem), key_pem_len));
37953802
if (!bp)
@@ -3837,7 +3844,7 @@ bool PublicKeyCipher::Cipher(const char* key_pem,
38373844
if (EVP_PKEY_cipher(ctx.get(), nullptr, out_len, data, len) <= 0)
38383845
return false;
38393846

3840-
*out = Malloc<unsigned char>(*out_len);
3847+
*out = static_cast<unsigned char*>(allocator->AllocateUninitialized(*out_len));
38413848

38423849
if (EVP_PKEY_cipher(ctx.get(), *out, out_len, data, len) <= 0)
38433850
return false;
@@ -3870,6 +3877,7 @@ void PublicKeyCipher::Cipher(const FunctionCallbackInfo<Value>& args) {
38703877
ClearErrorOnReturn clear_error_on_return;
38713878

38723879
bool r = Cipher<operation, EVP_PKEY_cipher_init, EVP_PKEY_cipher>(
3880+
env,
38733881
kbuf,
38743882
klen,
38753883
args.Length() >= 3 && !args[2]->IsNull() ? *passphrase : nullptr,
@@ -3880,7 +3888,8 @@ void PublicKeyCipher::Cipher(const FunctionCallbackInfo<Value>& args) {
38803888
&out_len);
38813889

38823890
if (out_len == 0 || !r) {
3883-
free(out_value);
3891+
auto* allocator = env->isolate()->GetArrayBufferAllocator();
3892+
allocator->Free(out_value, out_len);
38843893
out_value = nullptr;
38853894
out_len = 0;
38863895
if (!r) {
@@ -4085,7 +4094,8 @@ void DiffieHellman::GenerateKeys(const FunctionCallbackInfo<Value>& args) {
40854094
const BIGNUM* pub_key;
40864095
DH_get0_key(diffieHellman->dh_.get(), &pub_key, nullptr);
40874096
size_t size = BN_num_bytes(pub_key);
4088-
char* data = Malloc(size);
4097+
auto* allocator = env->isolate()->GetArrayBufferAllocator();
4098+
char* data = static_cast<char*>(allocator->AllocateUninitialized(size));
40894099
BN_bn2bin(pub_key, reinterpret_cast<unsigned char*>(data));
40904100
args.GetReturnValue().Set(Buffer::New(env, data, size).ToLocalChecked());
40914101
}
@@ -4104,7 +4114,8 @@ void DiffieHellman::GetField(const FunctionCallbackInfo<Value>& args,
41044114
if (num == nullptr) return env->ThrowError(err_if_null);
41054115

41064116
size_t size = BN_num_bytes(num);
4107-
char* data = Malloc(size);
4117+
auto* allocator = env->isolate()->GetArrayBufferAllocator();
4118+
char* data = static_cast<char*>(allocator->AllocateUninitialized(size));
41084119
BN_bn2bin(num, reinterpret_cast<unsigned char*>(data));
41094120
args.GetReturnValue().Set(Buffer::New(env, data, size).ToLocalChecked());
41104121
}
@@ -4168,7 +4179,8 @@ void DiffieHellman::ComputeSecret(const FunctionCallbackInfo<Value>& args) {
41684179
Buffer::Length(args[0]),
41694180
0));
41704181

4171-
MallocedBuffer<char> data(DH_size(diffieHellman->dh_.get()));
4182+
auto* allocator = env->isolate()->GetArrayBufferAllocator();
4183+
MallocedBuffer<char> data(DH_size(diffieHellman->dh_.get()), allocator);
41724184

41734185
int size = DH_compute_key(reinterpret_cast<unsigned char*>(data.data),
41744186
key.get(),
@@ -4388,13 +4400,14 @@ void ECDH::ComputeSecret(const FunctionCallbackInfo<Value>& args) {
43884400
}
43894401

43904402
// NOTE: field_size is in bits
4403+
auto* allocator = env->isolate()->GetArrayBufferAllocator();
43914404
int field_size = EC_GROUP_get_degree(ecdh->group_);
43924405
size_t out_len = (field_size + 7) / 8;
4393-
char* out = node::Malloc(out_len);
4406+
char* out = static_cast<char*>(allocator->AllocateUninitialized(out_len));
43944407

43954408
int r = ECDH_compute_key(out, out_len, pub.get(), ecdh->key_.get(), nullptr);
43964409
if (!r) {
4397-
free(out);
4410+
allocator->Free(out, out_len);
43984411
return env->ThrowError("Failed to compute ECDH key");
43994412
}
44004413

@@ -4424,11 +4437,13 @@ void ECDH::GetPublicKey(const FunctionCallbackInfo<Value>& args) {
44244437
if (size == 0)
44254438
return env->ThrowError("Failed to get public key length");
44264439

4427-
unsigned char* out = node::Malloc<unsigned char>(size);
4440+
auto* allocator = env->isolate()->GetArrayBufferAllocator();
4441+
unsigned char* out =
4442+
static_cast<unsigned char*>(allocator->AllocateUninitialized(size));
44284443

44294444
int r = EC_POINT_point2oct(ecdh->group_, pub, form, out, size, nullptr);
44304445
if (r != size) {
4431-
free(out);
4446+
allocator->Free(out, size);
44324447
return env->ThrowError("Failed to get public key");
44334448
}
44344449

@@ -4448,11 +4463,13 @@ void ECDH::GetPrivateKey(const FunctionCallbackInfo<Value>& args) {
44484463
if (b == nullptr)
44494464
return env->ThrowError("Failed to get ECDH private key");
44504465

4466+
auto* allocator = env->isolate()->GetArrayBufferAllocator();
44514467
int size = BN_num_bytes(b);
4452-
unsigned char* out = node::Malloc<unsigned char>(size);
4468+
unsigned char* out =
4469+
static_cast<unsigned char*>(allocator->AllocateUninitialized(size));
44534470

44544471
if (size != BN_bn2bin(b, out)) {
4455-
free(out);
4472+
allocator->Free(out, size);
44564473
return env->ThrowError("Failed to convert ECDH private key to Buffer");
44574474
}
44584475

@@ -4572,7 +4589,7 @@ class PBKDF2Request : public AsyncWrap, public ThreadPoolWork {
45724589
success_(false),
45734590
pass_(std::move(pass)),
45744591
salt_(std::move(salt)),
4575-
key_(keylen),
4592+
key_(keylen, env->isolate()->GetArrayBufferAllocator()),
45764593
iteration_count_(iteration_count) {
45774594
}
45784595

@@ -4634,6 +4651,7 @@ void PBKDF2Request::AfterThreadPoolWork(int status) {
46344651

46354652
void PBKDF2(const FunctionCallbackInfo<Value>& args) {
46364653
Environment* env = Environment::GetCurrent(args);
4654+
auto* allocator = env->isolate()->GetArrayBufferAllocator();
46374655

46384656
const EVP_MD* digest = nullptr;
46394657
int keylen = -1;
@@ -4642,12 +4660,12 @@ void PBKDF2(const FunctionCallbackInfo<Value>& args) {
46424660

46434661
int passlen = Buffer::Length(args[0]);
46444662

4645-
MallocedBuffer<char> pass(passlen);
4663+
MallocedBuffer<char> pass(passlen, allocator);
46464664
memcpy(pass.data, Buffer::Data(args[0]), passlen);
46474665

46484666
int saltlen = Buffer::Length(args[1]);
46494667

4650-
MallocedBuffer<char> salt(saltlen);
4668+
MallocedBuffer<char> salt(saltlen, allocator);
46514669
memcpy(salt.data, Buffer::Data(args[1]), saltlen);
46524670

46534671
iteration_count = args[2]->Int32Value(env->context()).FromJust();
@@ -4724,9 +4742,10 @@ class RandomBytesRequest : public AsyncWrap, public ThreadPoolWork {
47244742
}
47254743

47264744
inline void release() {
4745+
size_t free_size = size_;
47274746
size_ = 0;
47284747
if (free_mode_ == FREE_DATA) {
4729-
free(data_);
4748+
env()->isolate()->GetArrayBufferAllocator()->Free(data_, free_size);
47304749
data_ = nullptr;
47314750
}
47324751
}
@@ -4840,7 +4859,8 @@ void RandomBytes(const FunctionCallbackInfo<Value>& args) {
48404859

48414860
Local<Object> obj = env->randombytes_constructor_template()->
48424861
NewInstance(env->context()).ToLocalChecked();
4843-
char* data = node::Malloc(size);
4862+
char* data = static_cast<char*>(
4863+
env->isolate()->GetArrayBufferAllocator()->AllocateUninitialized(size));
48444864
std::unique_ptr<RandomBytesRequest> req(
48454865
new RandomBytesRequest(env,
48464866
obj,
@@ -5015,8 +5035,9 @@ void VerifySpkac(const FunctionCallbackInfo<Value>& args) {
50155035
}
50165036

50175037

5018-
char* ExportPublicKey(const char* data, int len, size_t* size) {
5038+
char* ExportPublicKey(Environment* env, const char* data, int len, size_t* size) {
50195039
char* buf = nullptr;
5040+
auto* allocator = env->isolate()->GetArrayBufferAllocator();
50205041

50215042
BIOPointer bio(BIO_new(BIO_s_mem()));
50225043
if (!bio)
@@ -5037,7 +5058,7 @@ char* ExportPublicKey(const char* data, int len, size_t* size) {
50375058
BIO_get_mem_ptr(bio.get(), &ptr);
50385059

50395060
*size = ptr->length;
5040-
buf = Malloc(*size);
5061+
buf = static_cast<char*>(allocator->AllocateUninitialized(*size));
50415062
memcpy(buf, ptr->data, *size);
50425063

50435064
return buf;
@@ -5055,7 +5076,7 @@ void ExportPublicKey(const FunctionCallbackInfo<Value>& args) {
50555076
CHECK_NE(data, nullptr);
50565077

50575078
size_t pkey_size;
5058-
char* pkey = ExportPublicKey(data, length, &pkey_size);
5079+
char* pkey = ExportPublicKey(env, data, length, &pkey_size);
50595080
if (pkey == nullptr)
50605081
return args.GetReturnValue().SetEmptyString();
50615082

‎src/node_crypto.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -554,7 +554,8 @@ class PublicKeyCipher {
554554
template <Operation operation,
555555
EVP_PKEY_cipher_init_t EVP_PKEY_cipher_init,
556556
EVP_PKEY_cipher_t EVP_PKEY_cipher>
557-
static bool Cipher(const char* key_pem,
557+
static bool Cipher(Environment* env,
558+
const char* key_pem,
558559
int key_pem_len,
559560
const char* passphrase,
560561
int padding,

‎src/stream_base.cc

+9-2
Original file line numberDiff line numberDiff line change
@@ -355,19 +355,26 @@ void StreamResource::ClearError() {
355355

356356

357357
uv_buf_t StreamListener::OnStreamAlloc(size_t suggested_size) {
358-
return uv_buf_init(Malloc(suggested_size), suggested_size);
358+
CHECK_NE(stream_, nullptr);
359+
StreamBase* stream = static_cast<StreamBase*>(stream_);
360+
Environment* env = stream->stream_env();
361+
auto* allocator = env->isolate()->GetArrayBufferAllocator();
362+
return uv_buf_init(
363+
static_cast<char*>(allocator->AllocateUninitialized(suggested_size)),
364+
suggested_size);
359365
}
360366

361367

362368
void EmitToJSStreamListener::OnStreamRead(ssize_t nread, const uv_buf_t& buf) {
363369
CHECK_NE(stream_, nullptr);
364370
StreamBase* stream = static_cast<StreamBase*>(stream_);
365371
Environment* env = stream->stream_env();
372+
auto* allocator = env->isolate()->GetArrayBufferAllocator();
366373
HandleScope handle_scope(env->isolate());
367374
Context::Scope context_scope(env->context());
368375

369376
if (nread <= 0) {
370-
free(buf.base);
377+
allocator->Free(buf.base, buf.len);
371378
if (nread < 0)
372379
stream->CallJSOnreadMethod(nread, Local<Object>());
373380
return;

‎src/udp_wrap.cc

+14-8
Original file line numberDiff line numberDiff line change
@@ -447,7 +447,10 @@ void UDPWrap::OnSend(uv_udp_send_t* req, int status) {
447447
void UDPWrap::OnAlloc(uv_handle_t* handle,
448448
size_t suggested_size,
449449
uv_buf_t* buf) {
450-
buf->base = node::Malloc(suggested_size);
450+
auto* wrap = static_cast<UDPWrap*>(handle->data);
451+
auto* allocator = wrap->env()->isolate()->GetArrayBufferAllocator();
452+
buf->base =
453+
static_cast<char*>(allocator->AllocateUninitialized(suggested_size));
451454
buf->len = suggested_size;
452455
}
453456

@@ -457,15 +460,16 @@ void UDPWrap::OnRecv(uv_udp_t* handle,
457460
const uv_buf_t* buf,
458461
const struct sockaddr* addr,
459462
unsigned int flags) {
463+
UDPWrap* wrap = static_cast<UDPWrap*>(handle->data);
464+
Environment* env = wrap->env();
465+
auto* allocator = env->isolate()->GetArrayBufferAllocator();
466+
460467
if (nread == 0 && addr == nullptr) {
461468
if (buf->base != nullptr)
462-
free(buf->base);
469+
allocator->Free(buf->base, buf->len);
463470
return;
464471
}
465472

466-
UDPWrap* wrap = static_cast<UDPWrap*>(handle->data);
467-
Environment* env = wrap->env();
468-
469473
HandleScope handle_scope(env->isolate());
470474
Context::Scope context_scope(env->context());
471475

@@ -479,13 +483,15 @@ void UDPWrap::OnRecv(uv_udp_t* handle,
479483

480484
if (nread < 0) {
481485
if (buf->base != nullptr)
482-
free(buf->base);
486+
allocator->Free(buf->base, buf->len);
483487
wrap->MakeCallback(env->onmessage_string(), arraysize(argv), argv);
484488
return;
485489
}
486490

487-
char* base = node::UncheckedRealloc(buf->base, nread);
488-
argv[2] = Buffer::New(env, base, nread).ToLocalChecked();
491+
// Note that nread may be smaller thant buf->len, in that case the length
492+
// passed to ArrayBufferAllocator::Free would not be the correct one, but
493+
// it should be fine unless embedder is using some unusual memory allocator.
494+
argv[2] = Buffer::New(env, buf->base, nread).ToLocalChecked();
489495
argv[3] = AddressToJS(env, addr);
490496
wrap->MakeCallback(env->onmessage_string(), arraysize(argv), argv);
491497
}

‎src/util.h

+15-4
Original file line numberDiff line numberDiff line change
@@ -424,24 +424,35 @@ template <typename T>
424424
struct MallocedBuffer {
425425
T* data;
426426
size_t size;
427+
v8::ArrayBuffer::Allocator* allocator;
427428

428429
T* release() {
430+
allocator = nullptr;
429431
T* ret = data;
430432
data = nullptr;
431433
return ret;
432434
}
433435

434-
MallocedBuffer() : data(nullptr) {}
435-
explicit MallocedBuffer(size_t size) : data(Malloc<T>(size)), size(size) {}
436-
MallocedBuffer(MallocedBuffer&& other) : data(other.data), size(other.size) {
436+
MallocedBuffer() : data(nullptr), allocator(nullptr) {}
437+
MallocedBuffer(size_t size, v8::ArrayBuffer::Allocator* allocator)
438+
: size(size), allocator(allocator) {
439+
data = static_cast<T*>(allocator->AllocateUninitialized(size));
440+
}
441+
MallocedBuffer(MallocedBuffer&& other)
442+
: data(other.data), size(other.size), allocator(other.allocator) {
437443
other.data = nullptr;
444+
other.allocator = nullptr;
438445
}
439446
MallocedBuffer& operator=(MallocedBuffer&& other) {
440447
this->~MallocedBuffer();
441448
return *new(this) MallocedBuffer(other);
442449
}
443450
~MallocedBuffer() {
444-
free(data);
451+
if (allocator) {
452+
allocator->Free(data, size);
453+
} else {
454+
free(data);
455+
}
445456
}
446457
MallocedBuffer(const MallocedBuffer&) = delete;
447458
MallocedBuffer& operator=(const MallocedBuffer&) = delete;

0 commit comments

Comments
 (0)
This repository has been archived.