child_process: guard against race condition
authorRich Trott <rtrott@gmail.com>
Thu, 24 Dec 2015 21:00:29 +0000 (13:00 -0800)
committerMyles Borins <mborins@us.ibm.com>
Tue, 19 Jan 2016 19:52:33 +0000 (11:52 -0800)
It is possible that the internal hnadleMessage() might try to send to
a channel that has been closed. The result can be an AssertionError.
Guard against this.

Fixes: https://github.com/nodejs/node/issues/4205
PR-URL: https://github.com/nodejs/node/pull/4418
Reviewed-By: Brian White <mscdex@mscdex.net>
Reviewed-By: Johan Bergström <bugs@bergstroem.nu>
lib/internal/child_process.js
test/parallel/test-cluster-disconnect-race.js [new file with mode: 0644]

index 8b2e57e..b4365fb 100644 (file)
@@ -675,6 +675,9 @@ function setupChannel(target, channel) {
 
 const INTERNAL_PREFIX = 'NODE_';
 function handleMessage(target, message, handle) {
+  if (!target._channel)
+    return;
+
   var eventName = 'message';
   if (message !== null &&
       typeof message === 'object' &&
diff --git a/test/parallel/test-cluster-disconnect-race.js b/test/parallel/test-cluster-disconnect-race.js
new file mode 100644 (file)
index 0000000..40cfd91
--- /dev/null
@@ -0,0 +1,33 @@
+'use strict';
+
+// This code triggers an AssertionError on Linux in Node.js 5.3.0 and earlier.
+// Ref: https://github.com/nodejs/node/issues/4205
+
+const common = require('../common');
+const assert = require('assert');
+const net = require('net');
+const cluster = require('cluster');
+cluster.schedulingPolicy = cluster.SCHED_NONE;
+
+if (cluster.isMaster) {
+  var worker1, worker2;
+
+  worker1 = cluster.fork();
+  worker1.on('message', common.mustCall(function() {
+    worker2 = cluster.fork();
+    worker1.disconnect();
+    worker2.on('online', common.mustCall(worker2.disconnect));
+  }));
+
+  cluster.on('exit', function(worker, code) {
+    assert.strictEqual(code, 0, 'worker exited with error');
+  });
+
+  return;
+}
+
+var server = net.createServer();
+
+server.listen(common.PORT, function() {
+  process.send('listening');
+});