diff --git a/lib/internal/child_process/serialization.js b/lib/internal/child_process/serialization.js index f61a6b6f2552d0..ec858f401bea9e 100644 --- a/lib/internal/child_process/serialization.js +++ b/lib/internal/child_process/serialization.js @@ -12,6 +12,7 @@ const { StringDecoder } = require('string_decoder'); const v8 = require('v8'); const { isArrayBufferView } = require('internal/util/types'); const assert = require('internal/assert'); +const { streamBaseState, kLastWriteWasAsync } = internalBinding('stream_wrap'); const kMessageBuffer = Symbol('kMessageBuffer'); const kJSONBuffer = Symbol('kJSONBuffer'); @@ -82,10 +83,16 @@ const advanced = { const serializedMessage = ser.releaseBuffer(); const sizeBuffer = Buffer.allocUnsafe(4); sizeBuffer.writeUInt32BE(serializedMessage.length); - return channel.writeBuffer(req, Buffer.concat([ + + const buffer = Buffer.concat([ sizeBuffer, serializedMessage, - ]), handle); + ]); + const result = channel.writeBuffer(req, buffer, handle); + // Mirror what stream_base_commons.js does for Buffer retention. + if (streamBaseState[kLastWriteWasAsync]) + req.buffer = buffer; + return result; }, }; diff --git a/test/parallel/test-child-process-advanced-serialization-largebuffer.js b/test/parallel/test-child-process-advanced-serialization-largebuffer.js new file mode 100644 index 00000000000000..4e80bce40570f9 --- /dev/null +++ b/test/parallel/test-child-process-advanced-serialization-largebuffer.js @@ -0,0 +1,27 @@ +'use strict'; +const common = require('../common'); +const assert = require('assert'); +const child_process = require('child_process'); + +// Regression test for https://github.com/nodejs/node/issues/34797 +const eightMB = 8 * 1024 * 1024; + +if (process.argv[2] === 'child') { + for (let i = 0; i < 4; i++) { + process.send(new Uint8Array(eightMB).fill(i)); + } +} else { + const child = child_process.spawn(process.execPath, [__filename, 'child'], { + stdio: ['inherit', 'inherit', 'inherit', 'ipc'], + serialization: 'advanced' + }); + const received = []; + child.on('message', common.mustCall((chunk) => { + assert.deepStrictEqual(chunk, new Uint8Array(eightMB).fill(chunk[0])); + + received.push(chunk[0]); + if (received.length === 4) { + assert.deepStrictEqual(received, [0, 1, 2, 3]); + } + }, 4)); +}