buffer: FreeCallback should be tied to ArrayBuffer
authorFedor Indutny <fedor@indutny.com>
Tue, 6 Oct 2015 03:26:13 +0000 (23:26 -0400)
committerJames M Snell <jasnell@gmail.com>
Thu, 8 Oct 2015 03:39:17 +0000 (20:39 -0700)
FreeCallback should be invoked on the storage disposal (`ArrayBuffer`),
not when the view (`Uint8Array` or `Buffer`) is disposed. This causes
bug and crashes in addons which create buffers and store only slices of
them.

PR-URL: https://github.com/nodejs/node/pull/3198
Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
src/node_buffer.cc
test/addons/buffer-free-callback/binding.cc [new file with mode: 0644]
test/addons/buffer-free-callback/binding.gyp [new file with mode: 0644]
test/addons/buffer-free-callback/test.js [new file with mode: 0644]

index 9dbf3f0f6eab7b2d56acbdd2339479f8c9bce82b..eb727cf9c828d6abdb93ede7817f331e433d3e2d 100644 (file)
@@ -353,7 +353,7 @@ MaybeLocal<Object> New(Environment* env,
   if (!mb.FromMaybe(false))
     return Local<Object>();
 
-  CallbackInfo::New(env->isolate(), ui, callback, hint);
+  CallbackInfo::New(env->isolate(), ab, callback, hint);
   return scope.Escape(ui);
 }
 
diff --git a/test/addons/buffer-free-callback/binding.cc b/test/addons/buffer-free-callback/binding.cc
new file mode 100644 (file)
index 0000000..a1e7773
--- /dev/null
@@ -0,0 +1,36 @@
+#include <node.h>
+#include <node_buffer.h>
+#include <util.h>
+#include <v8.h>
+
+static int alive;
+static char buf[1024];
+
+static void FreeCallback(char* data, void* hint) {
+  alive--;
+}
+
+void Alloc(const v8::FunctionCallbackInfo<v8::Value>& args) {
+  v8::Isolate* isolate = args.GetIsolate();
+  alive++;
+  args.GetReturnValue().Set(node::Buffer::New(
+        isolate,
+        buf,
+        sizeof(buf),
+        FreeCallback,
+        nullptr).ToLocalChecked());
+}
+
+void Check(const v8::FunctionCallbackInfo<v8::Value>& args) {
+  v8::Isolate* isolate = args.GetIsolate();
+  isolate->RequestGarbageCollectionForTesting(
+      v8::Isolate::kFullGarbageCollection);
+  CHECK_GT(alive, 0);
+}
+
+void init(v8::Local<v8::Object> target) {
+  NODE_SET_METHOD(target, "alloc", Alloc);
+  NODE_SET_METHOD(target, "check", Check);
+}
+
+NODE_MODULE(binding, init);
diff --git a/test/addons/buffer-free-callback/binding.gyp b/test/addons/buffer-free-callback/binding.gyp
new file mode 100644 (file)
index 0000000..3bfb844
--- /dev/null
@@ -0,0 +1,8 @@
+{
+  'targets': [
+    {
+      'target_name': 'binding',
+      'sources': [ 'binding.cc' ]
+    }
+  ]
+}
diff --git a/test/addons/buffer-free-callback/test.js b/test/addons/buffer-free-callback/test.js
new file mode 100644 (file)
index 0000000..14bc350
--- /dev/null
@@ -0,0 +1,9 @@
+'use strict';
+// Flags: --expose-gc
+
+var assert = require('assert');
+var binding = require('./build/Release/binding');
+var buf = binding.alloc();
+var slice = buf.slice(32);
+buf = null;
+binding.check(slice);