Skip to content

Commit 611851d

Browse files
addaleaxjasnell
authored andcommitted
child_process: fix handle passing w large payloads
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. PR-URL: #14588 Fixes: #13778 Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Santiago Gimeno <santiago.gimeno@gmail.com>
1 parent 9564c20 commit 611851d

2 files changed

Lines changed: 49 additions & 3 deletions

File tree

lib/internal/child_process.js

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -455,10 +455,14 @@ function setupChannel(target, channel) {
455455

456456
var decoder = new StringDecoder('utf8');
457457
var jsonBuffer = '';
458+
var pendingHandle = null;
458459
channel.buffering = false;
459460
channel.onread = function(nread, pool, recvHandle) {
460461
// TODO(bnoordhuis) Check that nread > 0.
461462
if (pool) {
463+
if (recvHandle)
464+
pendingHandle = recvHandle;
465+
462466
// Linebreak is used as a message end sign
463467
var chunks = decoder.write(pool).split('\n');
464468
var numCompleteChunks = chunks.length - 1;
@@ -478,10 +482,12 @@ function setupChannel(target, channel) {
478482
// read because SCM_RIGHTS messages don't get coalesced. Make sure
479483
// that we deliver the handle with the right message however.
480484
if (isInternal(message)) {
481-
if (message.cmd === 'NODE_HANDLE')
482-
handleMessage(message, recvHandle, true);
483-
else
485+
if (message.cmd === 'NODE_HANDLE') {
486+
handleMessage(message, pendingHandle, true);
487+
pendingHandle = null;
488+
} else {
484489
handleMessage(message, undefined, true);
490+
}
485491
} else {
486492
handleMessage(message, undefined, false);
487493
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
'use strict';
2+
const common = require('../common');
3+
const assert = require('assert');
4+
const cluster = require('cluster');
5+
const net = require('net');
6+
7+
const payload = 'a'.repeat(800004);
8+
9+
if (cluster.isMaster) {
10+
const server = net.createServer();
11+
12+
server.on('connection', common.mustCall((socket) => socket.unref()));
13+
14+
const worker = cluster.fork();
15+
worker.on('message', common.mustCall(({ payload: received }, handle) => {
16+
assert.strictEqual(payload, received);
17+
assert(handle instanceof net.Socket);
18+
server.close();
19+
handle.destroy();
20+
}));
21+
22+
server.listen(0, common.mustCall(() => {
23+
const port = server.address().port;
24+
const socket = new net.Socket();
25+
socket.connect(port, (err) => {
26+
assert.ifError(err);
27+
worker.send({ payload }, socket);
28+
});
29+
}));
30+
} else {
31+
process.on('message', common.mustCall(({ payload: received }, handle) => {
32+
assert.strictEqual(payload, received);
33+
assert(handle instanceof net.Socket);
34+
process.send({ payload }, handle);
35+
36+
// Prepare for a clean exit.
37+
process.channel.unref();
38+
handle.unref();
39+
}));
40+
}

0 commit comments

Comments
 (0)