Skip to content

Commit 4cfd7ee

Browse files
Error stream if CopyDataBlockBytes assertions do not hold
1 parent 1f1a16a commit 4cfd7ee

File tree

3 files changed

+55
-7
lines changed

3 files changed

+55
-7
lines changed

index.bs

+24-4
Original file line numberDiff line numberDiff line change
@@ -3441,10 +3441,12 @@ The following abstract operations support the implementation of the
34413441
queue entry/byte length=]).
34423442
1. Let |destStart| be |pullIntoDescriptor|'s [=pull-into descriptor/byte offset=] +
34433443
|pullIntoDescriptor|'s [=pull-into descriptor/bytes filled=].
3444-
1. Perform ! [$CopyDataBlockBytes$](|pullIntoDescriptor|'s [=pull-into
3445-
descriptor/buffer=].\[[ArrayBufferData]], |destStart|,
3446-
|headOfQueue|'s [=readable byte stream queue entry/buffer=].\[[ArrayBufferData]],
3447-
|headOfQueue|'s [=readable byte stream queue entry/byte offset=], |bytesToCopy|).
3444+
1. If ! [$SafeCopyDataBlockBytes$](|pullIntoDescriptor|'s [=pull-into descriptor/buffer=],
3445+
|destStart|, |headOfQueue|'s [=readable byte stream queue entry/buffer=],
3446+
|headOfQueue|'s [=readable byte stream queue entry/byte offset=], |bytesToCopy|) is false,
3447+
1. Let |e| be a {{TypeError}} exception.
3448+
1. Perform ! [$ReadableByteStreamControllerError$](|controller|, |e|).
3449+
1. Return false.
34483450
1. If |headOfQueue|'s [=readable byte stream queue entry/byte length=] is |bytesToCopy|,
34493451
1. [=list/Remove=] |queue|[0].
34503452
1. Otherwise,
@@ -6848,6 +6850,24 @@ The following abstract operations are a grab-bag of utilities.
68486850
1. Return ? [$StructuredDeserialize$](|serialized|, [=the current Realm=]).
68496851
</div>
68506852

6853+
<div algorithm>
6854+
<dfn abstract-op lt="SafeCopyDataBlockBytes">SafeCopyDataBlockBytes(|toBuffer|, |toIndex|,
6855+
|fromBuffer|, |fromIndex|, |count|)</dfn> performs the following steps:
6856+
6857+
1. Assert: [$Type$](|toBuffer|) is Object.
6858+
1. Assert: |toBuffer| has an \[[ArrayBufferData]] internal slot.
6859+
1. Assert: [$Type$](|fromBuffer|) is Object.
6860+
1. Assert: |fromBuffer| has an \[[ArrayBufferData]] internal slot.
6861+
1. If |toBuffer| is |fromBuffer|, return false.
6862+
1. If ! [$IsDetachedBuffer$](|toBuffer|) is true, return false.
6863+
1. If ! [$IsDetachedBuffer$](|fromBuffer|) is true, return false.
6864+
1. If |toIndex| + |count| > |toBuffer|.\[[ArrayBufferByteLength]], return false.
6865+
1. If |fromIndex| + |count| > |fromBuffer|.\[[ArrayBufferByteLength]], return false.
6866+
1. Perform ! [$CopyDataBlockBytes$](|toBuffer|.\[[ArrayBufferData]], |toIndex|,
6867+
|fromBuffer|.\[[ArrayBufferData]], |fromIndex|, |count|).
6868+
1. Return true.
6869+
</div>
6870+
68516871
<h2 id="other-specs">Using streams in other specifications</h2>
68526872

68536873
Much of this standard concerns itself with the internal machinery of streams. Other specifications

reference-implementation/lib/abstract-ops/miscellaneous.js

+21
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
'use strict';
2+
const { CopyDataBlockBytes, IsDetachedBuffer } = require('./ecmascript');
23

34
exports.IsNonNegativeNumber = v => {
45
if (typeof v !== 'number') {
@@ -20,3 +21,23 @@ exports.CloneAsUint8Array = O => {
2021
const buffer = O.buffer.slice(O.byteOffset, O.byteOffset + O.byteLength);
2122
return new Uint8Array(buffer);
2223
};
24+
25+
exports.SafeCopyDataBlockBytes = (toBuffer, toIndex, fromBuffer, fromIndex, count) => {
26+
if (toBuffer === fromBuffer) {
27+
return false;
28+
}
29+
if (IsDetachedBuffer(toBuffer) === true) {
30+
return false;
31+
}
32+
if (IsDetachedBuffer(fromBuffer) === true) {
33+
return false;
34+
}
35+
if (toIndex + count > toBuffer.byteLength) {
36+
return false;
37+
}
38+
if (fromIndex + count > fromBuffer.byteLength) {
39+
return false;
40+
}
41+
CopyDataBlockBytes(toBuffer, toIndex, fromBuffer, fromIndex, count);
42+
return true;
43+
};

reference-implementation/lib/abstract-ops/readable-streams.js

+10-3
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ const assert = require('assert');
44
const { promiseResolvedWith, promiseRejectedWith, newPromise, resolvePromise, rejectPromise, uponPromise,
55
setPromiseIsHandledToTrue, waitForAllPromise, transformPromiseWith, uponFulfillment, uponRejection } =
66
require('../helpers/webidl.js');
7-
const { CanTransferArrayBuffer, Call, CopyDataBlockBytes, CreateArrayFromList, GetIterator, GetMethod, IsDetachedBuffer,
7+
const { CanTransferArrayBuffer, Call, CreateArrayFromList, GetIterator, GetMethod, IsDetachedBuffer,
88
IteratorComplete, IteratorNext, IteratorValue, TransferArrayBuffer, typeIsObject } = require('./ecmascript.js');
9-
const { CloneAsUint8Array, IsNonNegativeNumber } = require('./miscellaneous.js');
9+
const { CloneAsUint8Array, IsNonNegativeNumber, SafeCopyDataBlockBytes } = require('./miscellaneous.js');
1010
const { EnqueueValueWithSize, ResetQueue } = require('./queue-with-sizes.js');
1111
const { AcquireWritableStreamDefaultWriter, IsWritableStreamLocked, WritableStreamAbort,
1212
WritableStreamDefaultWriterCloseWithErrorPropagation, WritableStreamDefaultWriterRelease,
@@ -1447,7 +1447,14 @@ function ReadableByteStreamControllerFillPullIntoDescriptorFromQueue(controller,
14471447
const bytesToCopy = Math.min(totalBytesToCopyRemaining, headOfQueue.byteLength);
14481448

14491449
const destStart = pullIntoDescriptor.byteOffset + pullIntoDescriptor.bytesFilled;
1450-
CopyDataBlockBytes(pullIntoDescriptor.buffer, destStart, headOfQueue.buffer, headOfQueue.byteOffset, bytesToCopy);
1450+
1451+
if (SafeCopyDataBlockBytes(pullIntoDescriptor.buffer, destStart, headOfQueue.buffer, headOfQueue.byteOffset,
1452+
bytesToCopy) === false) {
1453+
// This should never happen. Please report an issue if it does! https://github.com/whatwg/streams/issues
1454+
const e = new TypeError('Invalid buffer');
1455+
ReadableByteStreamControllerError(controller, e);
1456+
return false;
1457+
}
14511458

14521459
if (headOfQueue.byteLength === bytesToCopy) {
14531460
queue.shift();

0 commit comments

Comments
 (0)