summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--Userland/Libraries/LibJS/Runtime/IndexedProperties.cpp11
-rw-r--r--Userland/Libraries/LibJS/Tests/builtins/Array/Array.prototype.shift.js12
2 files changed, 20 insertions, 3 deletions
diff --git a/Userland/Libraries/LibJS/Runtime/IndexedProperties.cpp b/Userland/Libraries/LibJS/Runtime/IndexedProperties.cpp
index 6ed90ff166..3b1af328ad 100644
--- a/Userland/Libraries/LibJS/Runtime/IndexedProperties.cpp
+++ b/Userland/Libraries/LibJS/Runtime/IndexedProperties.cpp
@@ -180,14 +180,19 @@ ValueAndAttributes GenericIndexedPropertyStorage::take_first()
VERIFY(m_array_size > 0);
m_array_size--;
+ auto first_element = m_packed_elements.take_first();
+
if (!m_sparse_elements.is_empty()) {
+ m_packed_elements.append(m_sparse_elements.get(SPARSE_ARRAY_THRESHOLD).value_or({}));
HashMap<u32, ValueAndAttributes> new_sparse_elements;
- for (auto& entry : m_sparse_elements)
- new_sparse_elements.set(entry.key - 1, entry.value);
+ for (auto& entry : m_sparse_elements) {
+ if (entry.key - 1 >= SPARSE_ARRAY_THRESHOLD)
+ new_sparse_elements.set(entry.key - 1, entry.value);
+ }
m_sparse_elements = move(new_sparse_elements);
}
- return m_packed_elements.take_first();
+ return first_element;
}
ValueAndAttributes GenericIndexedPropertyStorage::take_last()
diff --git a/Userland/Libraries/LibJS/Tests/builtins/Array/Array.prototype.shift.js b/Userland/Libraries/LibJS/Tests/builtins/Array/Array.prototype.shift.js
index 0e154eeeb6..45c7168e2e 100644
--- a/Userland/Libraries/LibJS/Tests/builtins/Array/Array.prototype.shift.js
+++ b/Userland/Libraries/LibJS/Tests/builtins/Array/Array.prototype.shift.js
@@ -21,3 +21,15 @@ describe("normal behavior", () => {
expect(a).toEqual([]);
});
});
+
+test("Issue #5884, GenericIndexedPropertyStorage::take_first() loses elements", () => {
+ const a = [];
+ for (let i = 0; i < 300; i++) {
+ a.push(i);
+ }
+ expect(a.length).toBe(300);
+ for (let i = 0; i < 300; i++) {
+ a.shift();
+ }
+ expect(a.length).toBe(0);
+});