diff --git a/Userland/Libraries/LibJS/Runtime/TypedArrayPrototype.cpp b/Userland/Libraries/LibJS/Runtime/TypedArrayPrototype.cpp index 5b9b873648..e5db01781b 100644 --- a/Userland/Libraries/LibJS/Runtime/TypedArrayPrototype.cpp +++ b/Userland/Libraries/LibJS/Runtime/TypedArrayPrototype.cpp @@ -732,7 +732,7 @@ JS_DEFINE_NATIVE_FUNCTION(TypedArrayPrototype::set) // ii. Perform SetValueInBuffer(targetBuffer, targetByteIndex, Uint8, value, true, Unordered). // iii. Set srcByteIndex to srcByteIndex + 1. // iv. Set targetByteIndex to targetByteIndex + 1. - target_buffer->buffer().overwrite(target_byte_index, source_buffer->buffer().data(), limit - target_byte_index); + target_buffer->buffer().overwrite(target_byte_index, source_buffer->buffer().data() + source_byte_index, limit - target_byte_index); } else { // a. Repeat, while targetByteIndex < limit, while (target_byte_index < limit) { diff --git a/Userland/Libraries/LibJS/Tests/builtins/TypedArray/TypedArray.prototype.set.js b/Userland/Libraries/LibJS/Tests/builtins/TypedArray/TypedArray.prototype.set.js new file mode 100644 index 0000000000..57495cf666 --- /dev/null +++ b/Userland/Libraries/LibJS/Tests/builtins/TypedArray/TypedArray.prototype.set.js @@ -0,0 +1,50 @@ +const TYPED_ARRAYS = [ + { array: Uint8Array, maxUnsignedInteger: 2 ** 8 - 1 }, + { array: Uint8ClampedArray, maxUnsignedInteger: 2 ** 8 - 1 }, + { array: Uint16Array, maxUnsignedInteger: 2 ** 16 - 1 }, + { array: Uint32Array, maxUnsignedInteger: 2 ** 32 - 1 }, + { array: Int8Array, maxUnsignedInteger: 2 ** 7 - 1 }, + { array: Int16Array, maxUnsignedInteger: 2 ** 15 - 1 }, + { array: Int32Array, maxUnsignedInteger: 2 ** 31 - 1 }, + { array: Float32Array, maxUnsignedInteger: 2 ** 24 - 1 }, + { array: Float64Array, maxUnsignedInteger: Number.MAX_SAFE_INTEGER }, +]; + +const BIGINT_TYPED_ARRAYS = [ + { array: BigUint64Array, maxUnsignedInteger: 2n ** 64n - 1n }, + { array: BigInt64Array, maxUnsignedInteger: 2n ** 63n - 1n }, +]; + +// FIXME: Write out a full test suite for this function. This currently only performs a single regression test. +describe("normal behavior", () => { + // Previously, we didn't apply source's byte offset on the code path for setting a typed array + // from another typed array of the same type. This means the result array would previously contain + // [maxUnsignedInteger - 3(n), maxUnsignedInteger - 2(n)] instead of [maxUnsignedInteger - 1(n), maxUnsignedInteger] + test("two typed arrays of the same type code path applies source's byte offset", () => { + TYPED_ARRAYS.forEach(({ array, maxUnsignedInteger }) => { + const firstTypedArray = new array([ + maxUnsignedInteger - 3, + maxUnsignedInteger - 2, + maxUnsignedInteger - 1, + maxUnsignedInteger, + ]); + const secondTypedArray = new array(2); + secondTypedArray.set(firstTypedArray.subarray(2, 4), 0); + expect(secondTypedArray[0]).toBe(maxUnsignedInteger - 1); + expect(secondTypedArray[1]).toBe(maxUnsignedInteger); + }); + + BIGINT_TYPED_ARRAYS.forEach(({ array, maxUnsignedInteger }) => { + const firstTypedArray = new array([ + maxUnsignedInteger - 3n, + maxUnsignedInteger - 2n, + maxUnsignedInteger - 1n, + maxUnsignedInteger, + ]); + const secondTypedArray = new array(2); + secondTypedArray.set(firstTypedArray.subarray(2, 4), 0); + expect(secondTypedArray[0]).toBe(maxUnsignedInteger - 1n); + expect(secondTypedArray[1]).toBe(maxUnsignedInteger); + }); + }); +});