Skip to content

Commit ae6580b

Browse files
authored
fix: clean up memory leaks related to mongocrypt_binary_t (#166)
* refactor: inline all persistent ctor references * fix: wrap all mongocrypt_binary_t in smart pointers This fixes two places where we weren't cleaning up memory after creating binary instances * fix: mongocrypt_binary_t is non-owning, don't copy buffer contents BufferToBinary was needlessly making a copy of the data for the passed buffer when creating a new `mongocrypt_binary_t`. Since that type is a non-owning view, we should directly pass the contents of the buffer. NODE-2985
1 parent ed4a7da commit ae6580b

File tree

2 files changed

+25
-19
lines changed

2 files changed

+25
-19
lines changed

bindings/node/src/mongocrypt.cc

Lines changed: 13 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,7 @@ std::string StringFromBinary(mongocrypt_binary_t* binary) {
3737
mongocrypt_binary_t* BufferToBinary(v8::Local<v8::Object> node_buffer) {
3838
uint8_t* buffer = (uint8_t*)node::Buffer::Data(node_buffer);
3939
size_t buffer_len = node::Buffer::Length(node_buffer);
40-
41-
uint8_t* buffer_copy = new uint8_t[buffer_len];
42-
memcpy(buffer_copy, buffer, buffer_len);
43-
44-
return mongocrypt_binary_new_from_data(buffer_copy, buffer_len);
40+
return mongocrypt_binary_new_from_data(buffer, buffer_len);
4541
}
4642

4743
v8::Local<v8::Object> BufferFromBinary(mongocrypt_binary_t* binary) {
@@ -121,7 +117,6 @@ std::string errorStringFromStatus(mongocrypt_ctx_t* context) {
121117
return errorMessage;
122118
}
123119

124-
Nan::Persistent<v8::Function> MongoCrypt::constructor;
125120
NAN_MODULE_INIT(MongoCrypt::Init) {
126121
v8::Local<v8::FunctionTemplate> tpl = Nan::New<v8::FunctionTemplate>(New);
127122
tpl->SetClassName(Nan::New("MongoCrypt").ToLocalChecked());
@@ -138,7 +133,7 @@ NAN_MODULE_INIT(MongoCrypt::Init) {
138133

139134
Nan::SetAccessor(itpl, Nan::New("status").ToLocalChecked(), Status);
140135

141-
constructor.Reset(Nan::GetFunction(tpl).ToLocalChecked());
136+
constructor().Reset(Nan::GetFunction(tpl).ToLocalChecked());
142137
Nan::Set(
143138
target, Nan::New("MongoCrypt").ToLocalChecked(), Nan::GetFunction(tpl).ToLocalChecked());
144139
}
@@ -400,7 +395,9 @@ NAN_METHOD(MongoCrypt::New) {
400395
return;
401396
}
402397

403-
if (!mongocrypt_setopt_kms_providers(crypt.get(), BufferToBinary(kmsProvidersOptions))) {
398+
std::unique_ptr<mongocrypt_binary_t, MongoCryptBinaryDeleter> kmsProvidersBinary(
399+
BufferToBinary(kmsProvidersOptions));
400+
if (!mongocrypt_setopt_kms_providers(crypt.get(), kmsProvidersBinary.get())) {
404401
Nan::ThrowTypeError(errorStringFromStatus(crypt.get()));
405402
return;
406403
}
@@ -416,7 +413,9 @@ NAN_METHOD(MongoCrypt::New) {
416413
return;
417414
}
418415

419-
if (!mongocrypt_setopt_schema_map(crypt.get(), BufferToBinary(schemaMapBuffer))) {
416+
std::unique_ptr<mongocrypt_binary_t, MongoCryptBinaryDeleter> schemaMapBinary(
417+
BufferToBinary(schemaMapBuffer));
418+
if (!mongocrypt_setopt_schema_map(crypt.get(), schemaMapBinary.get())) {
420419
Nan::ThrowTypeError(errorStringFromStatus(crypt.get()));
421420
return;
422421
}
@@ -493,7 +492,7 @@ NAN_METHOD(MongoCrypt::New) {
493492

494493
const int argc = 1;
495494
v8::Local<v8::Value> argv[argc] = {info[0]};
496-
v8::Local<v8::Function> ctor = Nan::New<v8::Function>(MongoCrypt::constructor);
495+
v8::Local<v8::Function> ctor = Nan::New<v8::Function>(constructor());
497496
info.GetReturnValue().Set(Nan::NewInstance(ctor, argc, argv).ToLocalChecked());
498497
}
499498

@@ -680,7 +679,6 @@ NAN_METHOD(MongoCrypt::MakeDataKeyContext) {
680679
info.GetReturnValue().Set(result);
681680
}
682681

683-
Nan::Persistent<v8::Function> MongoCryptContext::constructor;
684682
NAN_MODULE_INIT(MongoCryptContext::Init) {
685683
v8::Local<v8::FunctionTemplate> tpl = Nan::New<v8::FunctionTemplate>();
686684
tpl->SetClassName(Nan::New("MongoCryptContext").ToLocalChecked());
@@ -697,15 +695,15 @@ NAN_MODULE_INIT(MongoCryptContext::Init) {
697695
Nan::SetAccessor(itpl, Nan::New("status").ToLocalChecked(), Status);
698696
Nan::SetAccessor(itpl, Nan::New("state").ToLocalChecked(), State);
699697

700-
constructor.Reset(Nan::GetFunction(tpl).ToLocalChecked());
698+
constructor().Reset(Nan::GetFunction(tpl).ToLocalChecked());
701699
Nan::Set(target,
702700
Nan::New("MongoCryptContext").ToLocalChecked(),
703701
Nan::GetFunction(tpl).ToLocalChecked());
704702
}
705703

706704
v8::Local<v8::Object> MongoCryptContext::NewInstance(mongocrypt_ctx_t* context) {
707705
Nan::EscapableHandleScope scope;
708-
v8::Local<v8::Function> ctor = Nan::New<v8::Function>(MongoCryptContext::constructor);
706+
v8::Local<v8::Function> ctor = Nan::New<v8::Function>(constructor());
709707
v8::Local<v8::Object> object = Nan::NewInstance(ctor).ToLocalChecked();
710708
MongoCryptContext* class_instance = new MongoCryptContext(context);
711709
class_instance->Wrap(object);
@@ -794,7 +792,6 @@ NAN_METHOD(MongoCryptContext::Finalize) {
794792
info.GetReturnValue().Set(buffer);
795793
}
796794

797-
Nan::Persistent<v8::Function> MongoCryptKMSRequest::constructor;
798795
NAN_MODULE_INIT(MongoCryptKMSRequest::Init) {
799796
v8::Local<v8::FunctionTemplate> tpl = Nan::New<v8::FunctionTemplate>();
800797
tpl->SetClassName(Nan::New("MongoCryptKMSRequest").ToLocalChecked());
@@ -808,15 +805,15 @@ NAN_MODULE_INIT(MongoCryptKMSRequest::Init) {
808805
Nan::SetAccessor(itpl, Nan::New("endpoint").ToLocalChecked(), Endpoint);
809806
Nan::SetAccessor(itpl, Nan::New("message").ToLocalChecked(), Message);
810807

811-
constructor.Reset(Nan::GetFunction(tpl).ToLocalChecked());
808+
constructor().Reset(Nan::GetFunction(tpl).ToLocalChecked());
812809
Nan::Set(target,
813810
Nan::New("MongoCryptKMSRequest").ToLocalChecked(),
814811
Nan::GetFunction(tpl).ToLocalChecked());
815812
}
816813

817814
v8::Local<v8::Object> MongoCryptKMSRequest::NewInstance(mongocrypt_kms_ctx_t* kms_context) {
818815
Nan::EscapableHandleScope scope;
819-
v8::Local<v8::Function> ctor = Nan::New<v8::Function>(MongoCryptKMSRequest::constructor);
816+
v8::Local<v8::Function> ctor = Nan::New<v8::Function>(constructor());
820817
v8::Local<v8::Object> object = Nan::NewInstance(ctor).ToLocalChecked();
821818
MongoCryptKMSRequest* class_instance = new MongoCryptKMSRequest(kms_context);
822819
class_instance->Wrap(object);

bindings/node/src/mongocrypt.h

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,10 @@ class MongoCrypt : public Nan::ObjectWrap {
3131
static NAN_MODULE_INIT(Init);
3232

3333
private:
34-
static Nan::Persistent<v8::Function> constructor;
34+
static inline Nan::Persistent<v8::Function> & constructor() {
35+
static Nan::Persistent<v8::Function> ctor;
36+
return ctor;
37+
}
3538

3639
static NAN_METHOD(New);
3740
static NAN_METHOD(MakeEncryptionContext);
@@ -73,7 +76,10 @@ class MongoCryptContext : public Nan::ObjectWrap {
7376
static v8::Local<v8::Object> NewInstance(mongocrypt_ctx_t* context);
7477

7578
private:
76-
static Nan::Persistent<v8::Function> constructor;
79+
static inline Nan::Persistent<v8::Function> & constructor() {
80+
static Nan::Persistent<v8::Function> ctor;
81+
return ctor;
82+
}
7783

7884
static NAN_METHOD(NextMongoOperation);
7985
static NAN_METHOD(AddMongoOperationResponse);
@@ -96,7 +102,10 @@ class MongoCryptKMSRequest : public Nan::ObjectWrap {
96102
static v8::Local<v8::Object> NewInstance(mongocrypt_kms_ctx_t* kms_context);
97103

98104
private:
99-
static Nan::Persistent<v8::Function> constructor;
105+
static inline Nan::Persistent<v8::Function> & constructor() {
106+
static Nan::Persistent<v8::Function> ctor;
107+
return ctor;
108+
}
100109

101110
static NAN_METHOD(AddResponse);
102111

0 commit comments

Comments
 (0)