Skip to content

Commit 253f5f4

Browse files
trivikraduh95
authored andcommitted
stream: uncork fromWritable writev on chunk error
Ensure fromWritable().writev() uncorks the wrapped Writable when converting a later chunk throws. This prevents an internal cork from leaking after ERR_INVALID_ARG_TYPE. Fixes: #63294 Signed-off-by: Kamat, Trivikram <16024985+trivikr@users.noreply.github.com> Assisted-by: openai:gpt-5.5 PR-URL: #63295 Fixes: #63294 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Ethan Arrowood <ethan@arrowood.dev>
1 parent 5828fad commit 253f5f4

2 files changed

Lines changed: 36 additions & 6 deletions

File tree

lib/internal/streams/iter/classic.js

Lines changed: 20 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -535,6 +535,16 @@ function fromWritable(writable, options = kNullPrototype) {
535535
return (writable.writableLength ?? 0) >= hwm;
536536
}
537537

538+
function writeChunks(chunks) {
539+
let ok = true;
540+
for (let i = 0; i < chunks.length; i++) {
541+
const bytes = toUint8Array(chunks[i]);
542+
totalBytes += TypedArrayPrototypeGetByteLength(bytes);
543+
ok = writable.write(bytes);
544+
}
545+
return ok;
546+
}
547+
538548
const writer = {
539549
__proto__: null,
540550

@@ -630,14 +640,18 @@ function fromWritable(writable, options = kNullPrototype) {
630640
return PromiseResolve();
631641
}
632642

633-
if (typeof writable.cork === 'function') writable.cork();
634643
let ok = true;
635-
for (let i = 0; i < chunks.length; i++) {
636-
const bytes = toUint8Array(chunks[i]);
637-
totalBytes += TypedArrayPrototypeGetByteLength(bytes);
638-
ok = writable.write(bytes);
644+
if (typeof writable.cork === 'function' &&
645+
typeof writable.uncork === 'function') {
646+
writable.cork();
647+
try {
648+
ok = writeChunks(chunks);
649+
} finally {
650+
writable.uncork();
651+
}
652+
} else {
653+
ok = writeChunks(chunks);
639654
}
640-
if (typeof writable.uncork === 'function') writable.uncork();
641655

642656
if (ok) return PromiseResolve();
643657

test/parallel/test-stream-iter-writable-interop.js

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -550,6 +550,21 @@ function testWritevInvalidChunksType() {
550550
);
551551
}
552552

553+
// =============================================================================
554+
// writev() uncorks when chunk validation throws
555+
// =============================================================================
556+
557+
function testWritevInvalidChunkUncorks() {
558+
const writable = new Writable({ write(chunk, enc, cb) { cb(); } });
559+
const writer = fromWritable(writable);
560+
561+
assert.throws(
562+
() => writer.writev([new Uint8Array([1]), 42]),
563+
{ code: 'ERR_INVALID_ARG_TYPE' },
564+
);
565+
assert.strictEqual(writable.writableCorked, 0);
566+
}
567+
553568
// =============================================================================
554569
// Cached writer: second call returns same instance
555570
// =============================================================================
@@ -638,6 +653,7 @@ testDrainableNull();
638653
testDropOldestThrows();
639654
testInvalidBackpressureThrows();
640655
testWritevInvalidChunksType();
656+
testWritevInvalidChunkUncorks();
641657
testCachedWriter();
642658
testObjectModeThrows();
643659

0 commit comments

Comments
 (0)