Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings

Commit ba3f3e1

Browse filesBrowse files
thisalihassanaduh95
authored andcommitted
lib: reject SharedArrayBuffer in web APIs per spec
Signed-off-by: Ali Hassan <ali-hassan27@outlook.com> PR-URL: #62632 Refs: #59688 Reviewed-By: Filip Skokan <panva.ip@gmail.com> Reviewed-By: Antoine du Hamel <duhamelantoine1995@gmail.com>
1 parent 3490c1f commit ba3f3e1
Copy full SHA for ba3f3e1

4 files changed

+236-23Lines changed: 236 additions & 23 deletions

File tree

Expand file treeCollapse file tree
Open diff view settings
Filter options
Expand file treeCollapse file tree
Open diff view settings
Collapse file

‎lib/internal/crypto/webidl.js‎

Copy file name to clipboardExpand all lines: lib/internal/crypto/webidl.js
+3-23Lines changed: 3 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ const {
3131
} = primordials;
3232

3333
const {
34+
converters: sharedConverters,
3435
makeException,
3536
createEnumConverter,
3637
createSequenceConverter,
@@ -43,11 +44,10 @@ const {
4344
} = require('internal/util');
4445
const { CryptoKey } = require('internal/crypto/webcrypto');
4546
const {
46-
getDataViewOrTypedArrayBuffer,
4747
validateMaxBufferLength,
4848
kNamedCurveAliases,
4949
} = require('internal/crypto/util');
50-
const { isArrayBuffer, isSharedArrayBuffer } = require('internal/util/types');
50+
const { isSharedArrayBuffer } = require('internal/util/types');
5151

5252
// https://tc39.es/ecma262/#sec-tonumber
5353
function toNumber(value, opts = kEmptyObject) {
@@ -193,8 +193,6 @@ converters.object = (V, opts) => {
193193
return V;
194194
};
195195

196-
const isNonSharedArrayBuffer = isArrayBuffer;
197-
198196
/**
199197
* @param {string | object} V - The hash algorithm identifier (string or object).
200198
* @param {string} label - The dictionary name for the error message.
@@ -223,25 +221,7 @@ converters.Uint8Array = (V, opts = kEmptyObject) => {
223221
return V;
224222
};
225223

226-
converters.BufferSource = (V, opts = kEmptyObject) => {
227-
if (ArrayBufferIsView(V)) {
228-
if (isSharedArrayBuffer(getDataViewOrTypedArrayBuffer(V))) {
229-
throw makeException(
230-
'is a view on a SharedArrayBuffer, which is not allowed.',
231-
opts);
232-
}
233-
234-
return V;
235-
}
236-
237-
if (!isNonSharedArrayBuffer(V)) {
238-
throw makeException(
239-
'is not instance of ArrayBuffer, Buffer, TypedArray, or DataView.',
240-
opts);
241-
}
242-
243-
return V;
244-
};
224+
converters.BufferSource = sharedConverters.BufferSource;
245225

246226
converters['sequence<DOMString>'] = createSequenceConverter(
247227
converters.DOMString);
Collapse file

‎lib/internal/webidl.js‎

Copy file name to clipboardExpand all lines: lib/internal/webidl.js
+49Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
'use strict';
22

33
const {
4+
ArrayBufferIsView,
45
ArrayPrototypePush,
56
ArrayPrototypeToSorted,
7+
DataViewPrototypeGetBuffer,
68
MathAbs,
79
MathMax,
810
MathMin,
@@ -19,6 +21,7 @@ const {
1921
Symbol,
2022
SymbolIterator,
2123
TypeError,
24+
TypedArrayPrototypeGetBuffer,
2225
} = primordials;
2326

2427
const {
@@ -28,6 +31,11 @@ const {
2831
},
2932
} = require('internal/errors');
3033
const { kEmptyObject } = require('internal/util');
34+
const {
35+
isArrayBuffer,
36+
isDataView,
37+
isSharedArrayBuffer,
38+
} = require('internal/util/types');
3139

3240
const converters = { __proto__: null };
3341

@@ -382,6 +390,47 @@ function createInterfaceConverter(name, I) {
382390
};
383391
}
384392

393+
function getDataViewOrTypedArrayBuffer(V) {
394+
return isDataView(V) ?
395+
DataViewPrototypeGetBuffer(V) : TypedArrayPrototypeGetBuffer(V);
396+
}
397+
398+
// https://webidl.spec.whatwg.org/#ArrayBufferView
399+
converters.ArrayBufferView = (V, opts = kEmptyObject) => {
400+
if (!ArrayBufferIsView(V)) {
401+
throw makeException(
402+
'is not an ArrayBufferView.',
403+
opts);
404+
}
405+
if (isSharedArrayBuffer(getDataViewOrTypedArrayBuffer(V))) {
406+
throw makeException(
407+
'is a view on a SharedArrayBuffer, which is not allowed.',
408+
opts);
409+
}
410+
411+
return V;
412+
};
413+
414+
// https://webidl.spec.whatwg.org/#BufferSource
415+
converters.BufferSource = (V, opts = kEmptyObject) => {
416+
if (ArrayBufferIsView(V)) {
417+
if (isSharedArrayBuffer(getDataViewOrTypedArrayBuffer(V))) {
418+
throw makeException(
419+
'is a view on a SharedArrayBuffer, which is not allowed.',
420+
opts);
421+
}
422+
423+
return V;
424+
}
425+
426+
if (!isArrayBuffer(V)) {
427+
throw makeException(
428+
'is not instance of ArrayBuffer, Buffer, TypedArray, or DataView.',
429+
opts);
430+
}
431+
432+
return V;
433+
};
385434

386435
module.exports = {
387436
type,
Collapse file

‎lib/internal/webstreams/readablestream.js‎

Copy file name to clipboardExpand all lines: lib/internal/webstreams/readablestream.js
+19Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@ const {
4848
const {
4949
isArrayBufferView,
5050
isDataView,
51+
isSharedArrayBuffer,
5152
} = require('internal/util/types');
5253

5354
const {
@@ -988,6 +989,15 @@ class ReadableStreamBYOBReader {
988989

989990
const viewByteLength = ArrayBufferViewGetByteLength(view);
990991
const viewBuffer = ArrayBufferViewGetBuffer(view);
992+
993+
if (isSharedArrayBuffer(viewBuffer)) {
994+
throw new ERR_INVALID_ARG_VALUE(
995+
'view',
996+
view,
997+
'must not be backed by a SharedArrayBuffer',
998+
);
999+
}
1000+
9911001
const viewBufferByteLength = ArrayBufferPrototypeGetByteLength(viewBuffer);
9921002

9931003
if (viewByteLength === 0 || viewBufferByteLength === 0) {
@@ -1197,6 +1207,15 @@ class ReadableByteStreamController {
11971207
validateBuffer(chunk);
11981208
const chunkByteLength = ArrayBufferViewGetByteLength(chunk);
11991209
const chunkBuffer = ArrayBufferViewGetBuffer(chunk);
1210+
1211+
if (isSharedArrayBuffer(chunkBuffer)) {
1212+
throw new ERR_INVALID_ARG_VALUE(
1213+
'chunk',
1214+
chunk,
1215+
'must not be backed by a SharedArrayBuffer',
1216+
);
1217+
}
1218+
12001219
const chunkBufferByteLength = ArrayBufferPrototypeGetByteLength(chunkBuffer);
12011220
if (chunkByteLength === 0 || chunkBufferByteLength === 0) {
12021221
throw new ERR_INVALID_STATE.TypeError(
Collapse file
+165Lines changed: 165 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,165 @@
1+
'use strict';
2+
// Flags: --expose-internals
3+
const common = require('../common');
4+
const assert = require('assert');
5+
const test = require('node:test');
6+
const { ReadableStream } = require('stream/web');
7+
8+
const sab = new SharedArrayBuffer(8);
9+
const sabView = new Uint8Array(sab);
10+
const sabDataView = new DataView(sab);
11+
12+
// -- ReadableStreamBYOBReader.read() --
13+
14+
test('ReadableStreamBYOBReader.read() rejects SAB-backed Uint8Array', async () => {
15+
const rs = new ReadableStream({
16+
type: 'bytes',
17+
pull(controller) {
18+
controller.enqueue(new Uint8Array([1, 2, 3]));
19+
},
20+
});
21+
const reader = rs.getReader({ mode: 'byob' });
22+
await assert.rejects(
23+
reader.read(new Uint8Array(sab)),
24+
{ code: 'ERR_INVALID_ARG_VALUE' },
25+
);
26+
reader.releaseLock();
27+
});
28+
29+
test('ReadableStreamBYOBReader.read() rejects SAB-backed DataView', async () => {
30+
const rs = new ReadableStream({
31+
type: 'bytes',
32+
pull(controller) {
33+
controller.enqueue(new Uint8Array([1, 2, 3]));
34+
},
35+
});
36+
const reader = rs.getReader({ mode: 'byob' });
37+
await assert.rejects(
38+
reader.read(sabDataView),
39+
{ code: 'ERR_INVALID_ARG_VALUE' },
40+
);
41+
reader.releaseLock();
42+
});
43+
44+
test('ReadableStreamBYOBReader.read() accepts regular view', async () => {
45+
const rs = new ReadableStream({
46+
type: 'bytes',
47+
pull(controller) {
48+
controller.enqueue(new Uint8Array([1, 2, 3]));
49+
},
50+
});
51+
const reader = rs.getReader({ mode: 'byob' });
52+
const { value, done } = await reader.read(new Uint8Array(3));
53+
assert.strictEqual(done, false);
54+
assert.deepStrictEqual(value, new Uint8Array([1, 2, 3]));
55+
reader.releaseLock();
56+
});
57+
58+
// -- ReadableByteStreamController.enqueue() --
59+
60+
test('ReadableByteStreamController.enqueue() rejects SAB-backed Uint8Array', async () => {
61+
const sabForEnqueue = new SharedArrayBuffer(4);
62+
const sabViewForEnqueue = new Uint8Array(sabForEnqueue);
63+
sabViewForEnqueue[0] = 42;
64+
65+
const rs = new ReadableStream({
66+
type: 'bytes',
67+
pull: common.mustCall((controller) => {
68+
assert.throws(
69+
() => controller.enqueue(sabViewForEnqueue),
70+
{ code: 'ERR_INVALID_ARG_VALUE' },
71+
);
72+
controller.enqueue(new Uint8Array([1]));
73+
}),
74+
});
75+
const reader = rs.getReader();
76+
const { value } = await reader.read();
77+
assert.deepStrictEqual(value, new Uint8Array([1]));
78+
reader.releaseLock();
79+
});
80+
81+
test('ReadableByteStreamController.enqueue() rejects SAB-backed DataView', async () => {
82+
const sabForDv = new SharedArrayBuffer(4);
83+
const dvForEnqueue = new DataView(sabForDv);
84+
85+
const rs = new ReadableStream({
86+
type: 'bytes',
87+
pull: common.mustCall((controller) => {
88+
assert.throws(
89+
() => controller.enqueue(dvForEnqueue),
90+
{ code: 'ERR_INVALID_ARG_VALUE' },
91+
);
92+
controller.enqueue(new Uint8Array([2]));
93+
}),
94+
});
95+
const reader = rs.getReader();
96+
const { value } = await reader.read();
97+
assert.deepStrictEqual(value, new Uint8Array([2]));
98+
reader.releaseLock();
99+
});
100+
101+
// -- SharedWebIDL converters --
102+
103+
const { converters } = require('internal/webidl');
104+
105+
test('webidl converters.BufferSource rejects SharedArrayBuffer', () => {
106+
assert.throws(
107+
() => converters.BufferSource(sab),
108+
{ code: 'ERR_INVALID_ARG_TYPE' },
109+
);
110+
});
111+
112+
test('webidl converters.BufferSource rejects SAB-backed Uint8Array', () => {
113+
assert.throws(
114+
() => converters.BufferSource(sabView),
115+
{ code: 'ERR_INVALID_ARG_TYPE' },
116+
);
117+
});
118+
119+
test('webidl converters.BufferSource rejects SAB-backed DataView', () => {
120+
assert.throws(
121+
() => converters.BufferSource(sabDataView),
122+
{ code: 'ERR_INVALID_ARG_TYPE' },
123+
);
124+
});
125+
126+
test('webidl converters.BufferSource accepts ArrayBuffer', () => {
127+
const ab = new ArrayBuffer(4);
128+
assert.strictEqual(converters.BufferSource(ab), ab);
129+
});
130+
131+
test('webidl converters.BufferSource accepts regular TypedArray', () => {
132+
const ta = new Uint8Array(4);
133+
assert.strictEqual(converters.BufferSource(ta), ta);
134+
});
135+
136+
test('webidl converters.ArrayBufferView rejects SAB-backed Uint8Array', () => {
137+
assert.throws(
138+
() => converters.ArrayBufferView(sabView),
139+
{ code: 'ERR_INVALID_ARG_TYPE' },
140+
);
141+
});
142+
143+
test('webidl converters.ArrayBufferView rejects SAB-backed DataView', () => {
144+
assert.throws(
145+
() => converters.ArrayBufferView(sabDataView),
146+
{ code: 'ERR_INVALID_ARG_TYPE' },
147+
);
148+
});
149+
150+
test('webidl converters.ArrayBufferView rejects non-view', () => {
151+
assert.throws(
152+
() => converters.ArrayBufferView('not a view'),
153+
{ code: 'ERR_INVALID_ARG_TYPE' },
154+
);
155+
});
156+
157+
test('webidl converters.ArrayBufferView accepts regular Uint8Array', () => {
158+
const ta = new Uint8Array(4);
159+
assert.strictEqual(converters.ArrayBufferView(ta), ta);
160+
});
161+
162+
test('webidl converters.ArrayBufferView accepts regular DataView', () => {
163+
const dv = new DataView(new ArrayBuffer(4));
164+
assert.strictEqual(converters.ArrayBufferView(dv), dv);
165+
});

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.