Skip to content

Commit 5902bc4

Browse files
indutnyisaacs
authored andcommitted
child_process: acknowledge sent handles
Fix race-condition when multiple handles are sent and SCM_RIGHTS messages are gets merged by OS by avoiding sending multiple handles at once! fix #4885
1 parent 4716dc6 commit 5902bc4

File tree

1 file changed

+29
-0
lines changed

1 file changed

+29
-0
lines changed

lib/child_process.js

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ var EventEmitter = require('events').EventEmitter;
2424
var net = require('net');
2525
var dgram = require('dgram');
2626
var Process = process.binding('process_wrap').Process;
27+
var assert = require('assert');
2728
var util = require('util');
2829
var constants; // if (!constants) constants = process.binding('constants');
2930

@@ -321,6 +322,7 @@ function handleMessage(target, message, handle) {
321322

322323
function setupChannel(target, channel) {
323324
target._channel = channel;
325+
target._handleQueue = null;
324326

325327
var decoder = new StringDecoder('utf8');
326328
var jsonBuffer = '';
@@ -358,8 +360,22 @@ function setupChannel(target, channel) {
358360

359361
// handlers will go through this
360362
target.on('internalMessage', function(message, handle) {
363+
// Once acknowledged - continue sending handles.
364+
if (message.cmd === 'NODE_HANDLE_ACK') {
365+
assert(Array.isArray(target._handleQueue));
366+
var queue = target._handleQueue;
367+
target._handleQueue = null;
368+
queue.forEach(function(args) {
369+
target.send(args.message, args.handle);
370+
});
371+
return;
372+
}
373+
361374
if (message.cmd !== 'NODE_HANDLE') return;
362375

376+
// Acknowledge handle receival.
377+
target.send({ cmd: 'NODE_HANDLE_ACK' });
378+
363379
var obj = handleConversion[message.type];
364380

365381
// Update simultaneous accepts on Windows
@@ -389,6 +405,7 @@ function setupChannel(target, channel) {
389405
// this message will be handled by an internalMessage event handler
390406
message = {
391407
cmd: 'NODE_HANDLE',
408+
type: null,
392409
msg: message
393410
};
394411

@@ -407,6 +424,12 @@ function setupChannel(target, channel) {
407424
throw new TypeError("This handle type can't be sent");
408425
}
409426

427+
// Queue-up message and handle if we haven't received ACK yet.
428+
if (this._handleQueue) {
429+
this._handleQueue.push({ message: message.msg, handle: handle });
430+
return;
431+
}
432+
410433
var obj = handleConversion[message.type];
411434

412435
// convert TCP object to native handle object
@@ -416,6 +439,10 @@ function setupChannel(target, channel) {
416439
if (obj.simultaneousAccepts) {
417440
net._setSimultaneousAccepts(handle);
418441
}
442+
} else if (this._handleQueue) {
443+
// Queue request anyway to avoid out-of-order messages.
444+
this._handleQueue.push({ message: message, handle: null });
445+
return;
419446
}
420447

421448
var string = JSON.stringify(message) + '\n';
@@ -426,6 +453,8 @@ function setupChannel(target, channel) {
426453
'write',
427454
'cannot write to IPC channel.');
428455
this.emit('error', er);
456+
} else if (handle && !this._handleQueue) {
457+
this._handleQueue = [];
429458
}
430459

431460
if (obj && obj.postSend) {

0 commit comments

Comments
 (0)