diff --git a/Userland/Libraries/LibJS/Runtime/IndexedProperties.cpp b/Userland/Libraries/LibJS/Runtime/IndexedProperties.cpp index a8d50882d0..ae492d600c 100644 --- a/Userland/Libraries/LibJS/Runtime/IndexedProperties.cpp +++ b/Userland/Libraries/LibJS/Runtime/IndexedProperties.cpp @@ -168,13 +168,32 @@ ValueAndAttributes GenericIndexedPropertyStorage::take_last() void GenericIndexedPropertyStorage::set_array_like_size(size_t new_size) { - m_array_size = new_size; + if (new_size == m_array_size) + return; + + if (new_size >= m_array_size) { + m_array_size = new_size; + return; + } + + size_t highest_index = 0; + bool any_left = false; HashMap new_sparse_elements; for (auto& entry : m_sparse_elements) { - if (entry.key < new_size) + if (entry.key < new_size || !entry.value.attributes.is_configurable()) { new_sparse_elements.set(entry.key, entry.value); + any_left = true; + highest_index = max(highest_index, (size_t)entry.key); + } } + + if (any_left) { + m_array_size = max(highest_index + 1, new_size); + } else { + m_array_size = new_size; + } + m_sparse_elements = move(new_sparse_elements); } diff --git a/Userland/Libraries/LibJS/Tests/builtins/Array/array-length-setter.js b/Userland/Libraries/LibJS/Tests/builtins/Array/array-length-setter.js index 662fd6e04e..14a8269110 100644 --- a/Userland/Libraries/LibJS/Tests/builtins/Array/array-length-setter.js +++ b/Userland/Libraries/LibJS/Tests/builtins/Array/array-length-setter.js @@ -44,4 +44,14 @@ describe("normal behavior", () => { b.length = 0x80000001; expect(b.length).toEqual(0x80000001); }); + + test("should not remove non-configurable values", () => { + var a = [1, undefined, 3]; + Object.defineProperty(a, 1, { configurable: false, value: 2 }); + expect(a.length).toEqual(3); + + expect((a.length = 1)).toEqual(1); + expect(a.length).toEqual(2); + expect(a[1]).toEqual(2); + }); });