From 916cb256de5896343e3d5f7eea8949bd6e494d6d Mon Sep 17 00:00:00 2001 From: Timothy Flynn Date: Wed, 27 Dec 2023 08:41:22 -0500 Subject: [PATCH] LibJS: Ensure enlarged ArrayBuffers are filled with zeros Otherwise, the newly allocated bytes are uninitialized, causing UB when reading from the buffer immediately after an enlarging resize. --- Userland/Libraries/LibJS/Runtime/VM.cpp | 2 +- .../ArrayBuffer.prototype.resize.js | 34 +++++++++++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/Userland/Libraries/LibJS/Runtime/VM.cpp b/Userland/Libraries/LibJS/Runtime/VM.cpp index 1970aeeef5..26751a4fa5 100644 --- a/Userland/Libraries/LibJS/Runtime/VM.cpp +++ b/Userland/Libraries/LibJS/Runtime/VM.cpp @@ -149,7 +149,7 @@ VM::VM(OwnPtr custom_data, ErrorMessages error_messages) // The default implementation of HostResizeArrayBuffer is to return NormalCompletion(unhandled). - if (auto result = buffer.buffer().try_resize(new_byte_length); result.is_error()) + if (auto result = buffer.buffer().try_resize(new_byte_length, ByteBuffer::ZeroFillNewElements::Yes); result.is_error()) return throw_completion(ErrorType::NotEnoughMemoryToAllocate, new_byte_length); return HandledByHost::Handled; diff --git a/Userland/Libraries/LibJS/Tests/builtins/ArrayBuffer/ArrayBuffer.prototype.resize.js b/Userland/Libraries/LibJS/Tests/builtins/ArrayBuffer/ArrayBuffer.prototype.resize.js index 0c62e80e0b..1b0a682740 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/ArrayBuffer/ArrayBuffer.prototype.resize.js +++ b/Userland/Libraries/LibJS/Tests/builtins/ArrayBuffer/ArrayBuffer.prototype.resize.js @@ -54,4 +54,38 @@ describe("normal behavior", () => { expect(buffer.byteLength).toBe(i); } }); + + test("enlarged buffers filled with zeros", () => { + let buffer = new ArrayBuffer(5, { maxByteLength: 10 }); + + const readBuffer = () => { + let array = new Uint8Array(buffer, 0, buffer.byteLength / Uint8Array.BYTES_PER_ELEMENT); + let values = []; + + for (let value of array) { + values.push(Number(value)); + } + + return values; + }; + + const writeBuffer = values => { + let array = new Uint8Array(buffer, 0, buffer.byteLength / Uint8Array.BYTES_PER_ELEMENT); + array.set(values); + }; + + expect(readBuffer()).toEqual([0, 0, 0, 0, 0]); + + writeBuffer([1, 2, 3, 4, 5]); + expect(readBuffer()).toEqual([1, 2, 3, 4, 5]); + + buffer.resize(8); + expect(readBuffer()).toEqual([1, 2, 3, 4, 5, 0, 0, 0]); + + writeBuffer([1, 2, 3, 4, 5, 6, 7, 8]); + expect(readBuffer()).toEqual([1, 2, 3, 4, 5, 6, 7, 8]); + + buffer.resize(10); + expect(readBuffer()).toEqual([1, 2, 3, 4, 5, 6, 7, 8, 0, 0]); + }); });