From 798dad24f408327625f47705c2bb00f9e71d08b4 Mon Sep 17 00:00:00 2001 From: Fedor Indutny Date: Thu, 24 Sep 2015 01:30:25 -0400 Subject: [PATCH] child_process: `null` channel handle on close `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 --- lib/internal/child_process.js | 1 + .../test-child-process-fork-regr-gh-2847.js | 40 +++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 test/parallel/test-child-process-fork-regr-gh-2847.js diff --git a/lib/internal/child_process.js b/lib/internal/child_process.js index d1596406cf9d53..8c1abc5f746fc8 100644 --- a/lib/internal/child_process.js +++ b/lib/internal/child_process.js @@ -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 index 00000000000000..07ef6415a3c3e1 --- /dev/null +++ b/test/parallel/test-child-process-fork-regr-gh-2847.js @@ -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(); +});