Skip to content

Commit a3ac445

Browse files
daeyeonruyadorno
authored andcommitted
stream: fix isDetachedBuffer validations
Signed-off-by: Daeyeon Jeong daeyeon.dev@gmail.com PR-URL: #44114 Refs: #43866 Reviewed-By: LiviaMedeiros <livia@cirno.name> Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
1 parent bce8041 commit a3ac445

File tree

3 files changed

+57
-21
lines changed

3 files changed

+57
-21
lines changed

lib/internal/webstreams/readablestream.js

+17-18
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ const {
5959
} = require('v8');
6060

6161
const {
62+
validateBuffer,
6263
validateObject,
6364
} = require('internal/validators');
6465

@@ -101,6 +102,7 @@ const {
101102
extractHighWaterMark,
102103
extractSizeAlgorithm,
103104
lazyTransfer,
105+
isDetachedBuffer,
104106
isViewedArrayBufferDetached,
105107
isBrandCheck,
106108
resetQueue,
@@ -658,11 +660,13 @@ class ReadableStreamBYOBRequest {
658660
const viewBuffer = ArrayBufferViewGetBuffer(view);
659661
const viewBufferByteLength = ArrayBufferGetByteLength(viewBuffer);
660662

661-
if (viewByteLength === 0 || viewBufferByteLength === 0) {
662-
throw new ERR_INVALID_STATE.TypeError(
663-
'View ArrayBuffer is zero-length or detached');
663+
if (isDetachedBuffer(viewBuffer)) {
664+
throw new ERR_INVALID_STATE.TypeError('Viewed ArrayBuffer is detached');
664665
}
665666

667+
assert(viewByteLength > 0);
668+
assert(viewBufferByteLength > 0);
669+
666670
readableByteStreamControllerRespond(controller, bytesWritten);
667671
}
668672

@@ -681,6 +685,8 @@ class ReadableStreamBYOBRequest {
681685
'This BYOB request has been invalidated');
682686
}
683687

688+
validateBuffer(view, 'view');
689+
684690
if (isViewedArrayBufferDetached(view)) {
685691
throw new ERR_INVALID_STATE.TypeError('Viewed ArrayBuffer is detached');
686692
}
@@ -894,15 +900,19 @@ class ReadableStreamBYOBReader {
894900
],
895901
view));
896902
}
903+
897904
const viewByteLength = ArrayBufferViewGetByteLength(view);
898905
const viewBuffer = ArrayBufferViewGetBuffer(view);
899906
const viewBufferByteLength = ArrayBufferGetByteLength(viewBuffer);
900907

901908
if (viewByteLength === 0 || viewBufferByteLength === 0) {
902909
return PromiseReject(
903910
new ERR_INVALID_STATE.TypeError(
904-
'View ArrayBuffer is zero-length or detached'));
911+
'View or Viewed ArrayBuffer is zero-length or detached',
912+
),
913+
);
905914
}
915+
906916
// Supposed to assert here that the view's buffer is not
907917
// detached, but there's no API available to use to check that.
908918
if (this[kState].stream === undefined) {
@@ -2298,11 +2308,10 @@ function readableByteStreamControllerEnqueue(
22982308
if (pendingPullIntos.length) {
22992309
const firstPendingPullInto = pendingPullIntos[0];
23002310

2301-
const pendingBufferByteLength =
2302-
ArrayBufferGetByteLength(firstPendingPullInto.buffer);
2303-
if (pendingBufferByteLength === 0) {
2311+
if (isDetachedBuffer(firstPendingPullInto.buffer)) {
23042312
throw new ERR_INVALID_STATE.TypeError(
2305-
'Destination ArrayBuffer is zero-length or detached');
2313+
'Destination ArrayBuffer is detached',
2314+
);
23062315
}
23072316

23082317
firstPendingPullInto.buffer =
@@ -2501,16 +2510,6 @@ function readableByteStreamControllerRespondWithNewView(controller, view) {
25012510
const desc = pendingPullIntos[0];
25022511
assert(stream[kState].state !== 'errored');
25032512

2504-
if (!isArrayBufferView(view)) {
2505-
throw new ERR_INVALID_ARG_TYPE(
2506-
'view',
2507-
[
2508-
'Buffer',
2509-
'TypedArray',
2510-
'DataView',
2511-
],
2512-
view);
2513-
}
25142513
const viewByteLength = ArrayBufferViewGetByteLength(view);
25152514
const viewByteOffset = ArrayBufferViewGetByteOffset(view);
25162515
const viewBuffer = ArrayBufferViewGetBuffer(view);

lib/internal/webstreams/util.js

+6-3
Original file line numberDiff line numberDiff line change
@@ -129,11 +129,13 @@ function transferArrayBuffer(buffer) {
129129
return res;
130130
}
131131

132-
function isArrayBufferDetached(buffer) {
132+
function isDetachedBuffer(buffer) {
133133
if (ArrayBufferGetByteLength(buffer) === 0) {
134+
// TODO(daeyeon): Consider using C++ builtin to improve performance.
134135
try {
135136
new Uint8Array(buffer);
136-
} catch {
137+
} catch (error) {
138+
assert(error.name === 'TypeError');
137139
return true;
138140
}
139141
}
@@ -143,7 +145,7 @@ function isArrayBufferDetached(buffer) {
143145
function isViewedArrayBufferDetached(view) {
144146
return (
145147
ArrayBufferViewGetByteLength(view) === 0 &&
146-
isArrayBufferDetached(ArrayBufferViewGetBuffer(view))
148+
isDetachedBuffer(ArrayBufferViewGetBuffer(view))
147149
);
148150
}
149151

@@ -243,6 +245,7 @@ module.exports = {
243245
extractSizeAlgorithm,
244246
lazyTransfer,
245247
isBrandCheck,
248+
isDetachedBuffer,
246249
isPromisePending,
247250
isViewedArrayBufferDetached,
248251
peekQueueValue,

test/parallel/test-whatwg-readablebytestream-bad-buffers-and-views.js

+34
Original file line numberDiff line numberDiff line change
@@ -51,4 +51,38 @@ let pass = 0;
5151
reader.read(new Uint8Array([4, 5, 6]));
5252
}
5353

54+
{
55+
const stream = new ReadableStream({
56+
start(c) {
57+
c.enqueue(new Uint8Array([1, 2, 3]));
58+
},
59+
type: 'bytes',
60+
});
61+
const reader = stream.getReader({ mode: 'byob' });
62+
const view = new Uint8Array();
63+
assert
64+
.rejects(reader.read(view), {
65+
code: 'ERR_INVALID_STATE',
66+
name: 'TypeError',
67+
})
68+
.then(common.mustCall());
69+
}
70+
71+
{
72+
const stream = new ReadableStream({
73+
start(c) {
74+
c.enqueue(new Uint8Array([1, 2, 3]));
75+
},
76+
type: 'bytes',
77+
});
78+
const reader = stream.getReader({ mode: 'byob' });
79+
const view = new Uint8Array(new ArrayBuffer(10), 0, 0);
80+
assert
81+
.rejects(reader.read(view), {
82+
code: 'ERR_INVALID_STATE',
83+
name: 'TypeError',
84+
})
85+
.then(common.mustCall());
86+
}
87+
5488
process.on('exit', () => assert.strictEqual(pass, 2));

0 commit comments

Comments
 (0)