src: plug memory leaks
authorBen Noordhuis <info@bnoordhuis.nl>
Fri, 7 Aug 2015 21:03:00 +0000 (23:03 +0200)
committerBen Noordhuis <info@bnoordhuis.nl>
Thu, 13 Aug 2015 18:03:41 +0000 (20:03 +0200)
In a few places dynamic memory was passed to the Buffer::New() overload
that makes a copy of the input, not the one that takes ownership.

This commit is a band-aid to fix the memory leaks.  Longer term, we
should look into using C++11 move semantics more effectively.

Fixes: https://github.com/nodejs/node/issues/2308
PR-URL: https://github.com/nodejs/node/pull/2352
Reviewed-By: Fedor Indutny <fedor@indutny.com>
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
src/node_buffer.h
src/node_crypto.cc
src/stream_wrap.cc
src/udp_wrap.cc

index 5b935b8..f7c88f6 100644 (file)
@@ -67,12 +67,17 @@ static inline bool IsWithinBounds(size_t off, size_t len, size_t max) {
 // in src/node_internals.h because of a circular dependency.
 #if defined(NODE_WANT_INTERNALS)
 v8::MaybeLocal<v8::Object> New(Environment* env, size_t size);
+// Makes a copy of |data|.
 v8::MaybeLocal<v8::Object> New(Environment* env, const char* data, size_t len);
+// Takes ownership of |data|.
 v8::MaybeLocal<v8::Object> New(Environment* env,
                                char* data,
                                size_t length,
                                FreeCallback callback,
                                void* hint);
+// Takes ownership of |data|.  Must allocate |data| with malloc() or realloc()
+// because ArrayBufferAllocator::Free() deallocates it again with free().
+// Mixing operator new and free() is undefined behavior so don't do that.
 v8::MaybeLocal<v8::Object> Use(Environment* env, char* data, size_t length);
 #endif  // defined(NODE_WANT_INTERNALS)
 
index b5e83f9..d1bb677 100644 (file)
@@ -4479,7 +4479,7 @@ void ECDH::ComputeSecret(const FunctionCallbackInfo<Value>& args) {
     return env->ThrowError("Failed to compute ECDH key");
   }
 
-  Local<Object> buf = Buffer::New(env, out, out_len).ToLocalChecked();
+  Local<Object> buf = Buffer::Use(env, out, out_len).ToLocalChecked();
   args.GetReturnValue().Set(buf);
 }
 
@@ -4544,7 +4544,7 @@ void ECDH::GetPrivateKey(const FunctionCallbackInfo<Value>& args) {
   }
 
   Local<Object> buf =
-      Buffer::New(env, reinterpret_cast<char*>(out), size).ToLocalChecked();
+      Buffer::Use(env, reinterpret_cast<char*>(out), size).ToLocalChecked();
   args.GetReturnValue().Set(buf);
 }
 
@@ -4947,7 +4947,7 @@ void RandomBytesCheck(RandomBytesRequest* req, Local<Value> argv[2]) {
     size_t size;
     req->return_memory(&data, &size);
     argv[0] = Null(req->env()->isolate());
-    argv[1] = Buffer::New(req->env(), data, size).ToLocalChecked();
+    argv[1] = Buffer::Use(req->env(), data, size).ToLocalChecked();
   }
 }
 
index ae941f5..3097eac 100644 (file)
@@ -223,7 +223,7 @@ void StreamWrap::OnReadImpl(ssize_t nread,
     CHECK_EQ(pending, UV_UNKNOWN_HANDLE);
   }
 
-  Local<Object> obj = Buffer::New(env, base, nread).ToLocalChecked();
+  Local<Object> obj = Buffer::Use(env, base, nread).ToLocalChecked();
   wrap->EmitData(nread, obj, pending_obj);
 }
 
index dd3958e..791ef76 100644 (file)
@@ -408,7 +408,7 @@ void UDPWrap::OnRecv(uv_udp_t* handle,
   }
 
   char* base = static_cast<char*>(realloc(buf->base, nread));
-  argv[2] = Buffer::New(env, base, nread).ToLocalChecked();
+  argv[2] = Buffer::Use(env, base, nread).ToLocalChecked();
   argv[3] = AddressToJS(env, addr);
   wrap->MakeCallback(env->onmessage_string(), ARRAY_SIZE(argv), argv);
 }