buffer: don't CHECK on zero-sized realloc
authorBen Noordhuis <info@bnoordhuis.nl>
Fri, 23 Oct 2015 17:10:49 +0000 (19:10 +0200)
committerJames M Snell <jasnell@gmail.com>
Thu, 29 Oct 2015 15:38:42 +0000 (08:38 -0700)
malloc(0) and realloc(ptr, 0) have implementation-defined behavior in
that the standard allows them to either return a unique pointer or a
nullptr for zero-sized allocation requests.  Normalize by always using
a nullptr.

Fixes: https://github.com/nodejs/node/issues/3496
PR-URL: https://github.com/nodejs/node/pull/3499
Reviewed-By: Sakthipriyan Vairamani <thechargingvolcano@gmail.com>
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
src/node_buffer.cc
test/parallel/test-buffer.js

index a472d0c..7d428b2 100644 (file)
@@ -211,18 +211,30 @@ MaybeLocal<Object> New(Isolate* isolate,
                        enum encoding enc) {
   EscapableHandleScope scope(isolate);
 
-  size_t length = StringBytes::Size(isolate, string, enc);
-  char* data = static_cast<char*>(malloc(length));
+  const size_t length = StringBytes::Size(isolate, string, enc);
+  size_t actual = 0;
+  char* data = nullptr;
+
+  // malloc(0) and realloc(ptr, 0) have implementation-defined behavior in
+  // that the standard allows them to either return a unique pointer or a
+  // nullptr for zero-sized allocation requests.  Normalize by always using
+  // a nullptr.
+  if (length > 0) {
+    data = static_cast<char*>(malloc(length));
 
-  if (data == nullptr)
-    return Local<Object>();
+    if (data == nullptr)
+      return Local<Object>();
 
-  size_t actual = StringBytes::Write(isolate, data, length, string, enc);
-  CHECK(actual <= length);
+    actual = StringBytes::Write(isolate, data, length, string, enc);
+    CHECK(actual <= length);
 
-  if (actual < length) {
-    data = static_cast<char*>(realloc(data, actual));
-    CHECK_NE(data, nullptr);
+    if (actual == 0) {
+      free(data);
+      data = nullptr;
+    } else if (actual < length) {
+      data = static_cast<char*>(realloc(data, actual));
+      CHECK_NE(data, nullptr);
+    }
   }
 
   Local<Object> buf;
index 1be4f3b..37c9e64 100644 (file)
@@ -550,6 +550,9 @@ for (var i = 0; i < segments.length; ++i) {
 }
 assert.equal(b.toString('binary', 0, pos), 'Madness?! This is node.js!');
 
+// Regression test for https://github.com/nodejs/node/issues/3496.
+assert.equal(Buffer('=bad'.repeat(1e4), 'base64').length, 0);
+
 // Creating buffers larger than pool size.
 var l = Buffer.poolSize + 5;
 var s = '';