child_process: `null` channel handle on close
authorFedor Indutny <fedor@indutny.com>
Thu, 24 Sep 2015 05:30:25 +0000 (01:30 -0400)
committerJeremiah Senkpiel <fishrock123@rocketmail.com>
Fri, 25 Sep 2015 05:09:46 +0000 (22:09 -0700)
`HandleWrap::OnClose` destroys the underlying C++ object and null's the
internal field pointer to it. Therefore there should be no references to
the wrapping JavaScript object.

`null` the process' `_channel` field right after closing it, to ensure
no crashes will happen.

Fix: https://github.com/nodejs/node/issues/2847
PR-URL: https://github.com/nodejs/node/pull/3041
Reviewed-By: Trevor Norris <trev.norris@gmail.com>
lib/internal/child_process.js
test/parallel/test-child-process-fork-regr-gh-2847.js [new file with mode: 0644]

index d159640..8c1abc5 100644 (file)
@@ -449,6 +449,7 @@ function setupChannel(target, channel) {
       target.disconnect();
       channel.onread = nop;
       channel.close();
+      target._channel = null;
       maybeClose(target);
     }
   };
diff --git a/test/parallel/test-child-process-fork-regr-gh-2847.js b/test/parallel/test-child-process-fork-regr-gh-2847.js
new file mode 100644 (file)
index 0000000..07ef641
--- /dev/null
@@ -0,0 +1,40 @@
+'use strict';
+
+const common = require('../common');
+const assert = require('assert');
+
+const cluster = require('cluster');
+const net = require('net');
+const util = require('util');
+
+if (!cluster.isMaster) {
+  // Exit on first received handle to leave the queue non-empty in master
+  process.on('message', function() {
+    process.exit(1);
+  });
+  return;
+}
+
+var server = net.createServer(function(s) {
+  setTimeout(function() {
+    s.destroy();
+  }, 100);
+}).listen(common.PORT, function() {
+  var worker = cluster.fork();
+
+  function send(callback) {
+    var s = net.connect(common.PORT, function() {
+      worker.send({}, s, callback);
+    });
+  }
+
+  worker.process.once('close', common.mustCall(function() {
+    // Otherwise the crash on `_channel.fd` access may happen
+    assert(worker.process._channel === null);
+    server.close();
+  }));
+
+  // Queue up several handles, to make `process.disconnect()` wait
+  for (var i = 0; i < 100; i++)
+    send();
+});