Skip to content

Commit 12f1331

Browse files
committed
[Fix] ES2024+: ArrayBufferCopyAndDetach: properly handle resizable ArrayBuffers; add tests
1 parent 2475778 commit 12f1331

File tree

2 files changed

+101
-2
lines changed

2 files changed

+101
-2
lines changed

2024/ArrayBufferCopyAndDetach.js

+4-2
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,15 @@ var ToIndex = require('./ToIndex');
3636
var isArrayBuffer = require('is-array-buffer');
3737
var isSharedArrayBuffer = require('is-shared-array-buffer');
3838

39+
// https://262.ecma-international.org/15.0/#sec-arraybuffercopyanddetach
40+
3941
module.exports = function ArrayBufferCopyAndDetach(arrayBuffer, newLength, preserveResizability) {
4042
if (preserveResizability !== 'PRESERVE-RESIZABILITY' && preserveResizability !== 'FIXED-LENGTH') {
4143
throw new $TypeError('`preserveResizability` must be ~PRESERVE-RESIZABILITY~ or ~FIXED-LENGTH~');
4244
}
4345

4446
if (!isArrayBuffer(arrayBuffer) || isSharedArrayBuffer(arrayBuffer)) {
45-
throw new $TypeError('`arrayBuffer` must be an ArrayBuffer'); // steps 1 - 2
47+
throw new $TypeError('`arrayBuffer` must be a non-shared ArrayBuffer'); // steps 1 - 2
4648
}
4749

4850
var abByteLength;
@@ -77,7 +79,7 @@ module.exports = function ArrayBufferCopyAndDetach(arrayBuffer, newLength, prese
7779
abByteLength = byteLength(arrayBuffer);
7880
}
7981
var copyLength = min(newByteLength, abByteLength); // step 10
80-
if (newByteLength > copyLength) {
82+
if (newByteLength > copyLength || newMaxByteLength !== 'EMPTY') {
8183
var taNew = new $Uint8Array(newBuffer);
8284
var taOld = new $Uint8Array(arrayBuffer);
8385
for (var i = 0; i < copyLength; i++) {

test/tests.js

+97
Original file line numberDiff line numberDiff line change
@@ -15048,6 +15048,103 @@ var es2024 = function ES2024(ES, ops, expectedMissing, skips) {
1504815048
t.end();
1504915049
});
1505015050

15051+
test('ArrayBufferCopyAndDetach', function (t) {
15052+
forEach([].concat(
15053+
v.primitives,
15054+
v.objects
15055+
), function (nonAB) {
15056+
t['throws'](
15057+
function () { ES.ArrayBufferCopyAndDetach(nonAB, 0, 'FIXED-LENGTH'); },
15058+
TypeError,
15059+
debug(nonAB) + ' is not an ArrayBuffer or a SharedArrayBuffer'
15060+
);
15061+
});
15062+
15063+
t.test('ArrayBuffers supported', { skip: typeof ArrayBuffer !== 'function' }, function (st) {
15064+
var ab = new Uint8Array([1, 2, 3, 4]).buffer;
15065+
15066+
st.test('can not detach', { skip: canDetach }, function (s2t) {
15067+
s2t['throws'](
15068+
function () { ES.ArrayBufferCopyAndDetach(new ArrayBuffer(8), 0, 'FIXED-LENGTH'); },
15069+
SyntaxError,
15070+
'throws a syntax error when it can not detach'
15071+
);
15072+
15073+
s2t.end();
15074+
});
15075+
15076+
st.test('can detach', { skip: !canDetach }, function (s2t) {
15077+
forEach(v.nonStrings, function (nonString) {
15078+
s2t['throws'](
15079+
function () { ES.ArrayBufferCopyAndDetach(ab, 0, nonString); },
15080+
TypeError,
15081+
debug(nonString) + ' is not a valid preserveResizability value'
15082+
);
15083+
});
15084+
15085+
s2t.equal(ES.IsDetachedBuffer(ab), false, 'buffer is not detached');
15086+
var newBuffer = ES.ArrayBufferCopyAndDetach(ab, undefined, 'FIXED-LENGTH');
15087+
s2t.equal(ES.IsDetachedBuffer(ab), true, 'buffer is now detached');
15088+
s2t.deepEqual(new Uint8Array(newBuffer), new Uint8Array([1, 2, 3, 4]), 'new buffer has expected data');
15089+
15090+
var newSameBuffer = ES.ArrayBufferCopyAndDetach(newBuffer, 4, 'FIXED-LENGTH');
15091+
s2t.equal(ES.IsDetachedBuffer(newBuffer), true, 'buffer is now detached');
15092+
s2t.deepEqual(new Uint8Array(newSameBuffer), new Uint8Array([1, 2, 3, 4]), 'new buffer has expected data');
15093+
15094+
var newSmallerBuffer = ES.ArrayBufferCopyAndDetach(newSameBuffer, 2, 'FIXED-LENGTH');
15095+
s2t.equal(ES.IsDetachedBuffer(newSameBuffer), true, 'buffer is now detached');
15096+
s2t.deepEqual(new Uint8Array(newSmallerBuffer), new Uint8Array([1, 2]), 'new buffer has expected data');
15097+
15098+
var newLargerBuffer = ES.ArrayBufferCopyAndDetach(newSmallerBuffer, 4, 'FIXED-LENGTH');
15099+
s2t.equal(ES.IsDetachedBuffer(newSmallerBuffer), true, 'buffer is now detached');
15100+
s2t.deepEqual(new Uint8Array(newLargerBuffer), new Uint8Array([1, 2, 0, 0]), 'new buffer has expected data');
15101+
15102+
s2t['throws'](
15103+
function () { ES.ArrayBufferCopyAndDetach(ab, 0, 'FIXED-LENGTH'); },
15104+
TypeError,
15105+
'throws on already-detached buffer'
15106+
);
15107+
15108+
s2t.test('resizables', { skip: !('resizable' in ArrayBuffer.prototype) }, function (s3t) {
15109+
var rab = new ArrayBuffer(4, { maxByteLength: 64 });
15110+
assign(new Uint8Array(rab), [1, 2, 3, 4]);
15111+
15112+
s3t.equal(ES.IsDetachedBuffer(rab), false, 'buffer is not detached');
15113+
s3t.equal(rab.resizable, true, 'buffer is resizable');
15114+
var newResizableBuffer = ES.ArrayBufferCopyAndDetach(rab, undefined, 'PRESERVE-RESIZABILITY');
15115+
s3t.equal(ES.IsDetachedBuffer(rab), true, 'buffer is now detached');
15116+
s3t.deepEqual(new Uint8Array(newResizableBuffer), new Uint8Array([1, 2, 3, 4]), 'new buffer has expected data');
15117+
s3t.equal(newResizableBuffer.resizable, true, 'new buffer is resizable');
15118+
15119+
var newFixedBuffer = ES.ArrayBufferCopyAndDetach(newResizableBuffer, undefined, 'FIXED-LENGTH');
15120+
s3t.equal(ES.IsDetachedBuffer(newResizableBuffer), true, 'buffer is now detached');
15121+
s3t.deepEqual(new Uint8Array(newFixedBuffer), new Uint8Array([1, 2, 3, 4]), 'new buffer has expected data');
15122+
s3t.equal(newFixedBuffer.resizable, false, 'new buffer is not resizable');
15123+
15124+
s3t.end();
15125+
});
15126+
15127+
s2t.end();
15128+
});
15129+
15130+
st.end();
15131+
});
15132+
15133+
t.test('SharedArrayBuffers supported', { skip: typeof SharedArrayBuffer !== 'function' }, function (st) {
15134+
var sab = new SharedArrayBuffer(1);
15135+
15136+
st['throws'](
15137+
function () { ES.ArrayBufferCopyAndDetach(sab, undefined, 'FIXED-LENGTH'); },
15138+
TypeError,
15139+
debug(sab) + ' is not a non-shared ArrayBuffer'
15140+
);
15141+
15142+
st.end();
15143+
});
15144+
15145+
t.end();
15146+
});
15147+
1505115148
test('FindViaPredicate', function (t) {
1505215149
forEach(v.primitives, function (primitive) {
1505315150
t['throws'](

0 commit comments

Comments
 (0)