Skip to content

Commit

Permalink
child_process: fix handle passing w large payloads
Browse files Browse the repository at this point in the history
Fix situations in which the handle passed along with a message
that has a large payload and can’t be read entirely by a single
`recvmsg()` call isn’t associated with the message to which it
belongs.

Fixes: #13778
  • Loading branch information
addaleax committed Aug 7, 2017
1 parent 41a0dfc commit be0fed0
Show file tree
Hide file tree
Showing 2 changed files with 46 additions and 3 deletions.
12 changes: 9 additions & 3 deletions lib/internal/child_process.js
Original file line number Diff line number Diff line change
Expand Up @@ -455,10 +455,14 @@ function setupChannel(target, channel) {

var decoder = new StringDecoder('utf8');
var jsonBuffer = '';
var pendingHandle = null;
channel.buffering = false;
channel.onread = function(nread, pool, recvHandle) {
// TODO(bnoordhuis) Check that nread > 0.
if (pool) {
if (recvHandle)
pendingHandle = recvHandle;

// Linebreak is used as a message end sign
var chunks = decoder.write(pool).split('\n');
var numCompleteChunks = chunks.length - 1;
Expand All @@ -478,10 +482,12 @@ function setupChannel(target, channel) {
// read because SCM_RIGHTS messages don't get coalesced. Make sure
// that we deliver the handle with the right message however.
if (isInternal(message)) {
if (message.cmd === 'NODE_HANDLE')
handleMessage(message, recvHandle, true);
else
if (message.cmd === 'NODE_HANDLE') {
handleMessage(message, pendingHandle, true);
pendingHandle = null;
} else {
handleMessage(message, undefined, true);
}
} else {
handleMessage(message, undefined, false);
}
Expand Down
37 changes: 37 additions & 0 deletions test/parallel/test-cluster-send-handle-large-payload.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
'use strict';
const common = require('../common');
const assert = require('assert');
const cluster = require('cluster');
const net = require('net');

const payload = 'a'.repeat(800004);

if (cluster.isMaster) {
const server = net.createServer();

server.on('connection', common.mustCall((socket) => socket.unref()));

const worker = cluster.fork();
worker.on('message', common.mustCall(({ payload: received }, handle) => {
assert.strictEqual(payload, received);
assert(handle instanceof net.Socket);
server.close();
worker.kill();
handle.destroy();
}));

server.listen(0, common.mustCall(() => {
const port = server.address().port;
const socket = new net.Socket();
socket.connect(port, (err) => {
assert.ifError(err);
worker.send({ payload }, socket);
});
}));
} else {
process.on('message', common.mustCall(({ payload: received }, handle) => {
assert.strictEqual(payload, received);
assert(handle instanceof net.Socket);
process.send({ payload }, handle);
}));
}

0 comments on commit be0fed0

Please sign in to comment.