From: Dmitry Volyntsev Date: Fri, 12 Jun 2026 01:44:01 +0000 (-0700) Subject: Fix Array.prototype.slice() of large arrays in the non-fast keys path X-Git-Tag: 1.0.0~2 X-Git-Url: http://git.kaiwu.me/postgresql/log/contrib/postgres_fdw/static/gitweb.js?a=commitdiff_plain;h=66c6cdf9e15d56bd9442716bd5c854d5f19d005b;p=njs.git Fix Array.prototype.slice() of large arrays in the non-fast keys path When the slice result length was 32761 or more, the destination array was non-fast and slice_copy() reached the keys path, which enumerated every own index of the source and copied each at its original key, ignoring the requested [start, start + length) window and the destination-relative position. Array.prototype.slice() thus returned wrong results for such arrays. Filter the enumerated keys to the window and write them at index - start, matching the fast-array path. While here, also remove dead fast object path in slice_copy. --- diff --git a/src/njs_array.c b/src/njs_array.c index 636dcfca..5c30e833 100644 --- a/src/njs_array.c +++ b/src/njs_array.c @@ -788,6 +788,7 @@ static njs_int_t njs_array_prototype_slice_copy(njs_vm_t *vm, njs_value_t *this, int64_t start, int64_t length, njs_value_t *retval) { + double idx; size_t size; uint32_t n; njs_int_t ret; @@ -871,39 +872,24 @@ njs_array_prototype_slice_copy(njs_vm_t *vm, njs_value_t *this, njs_set_array(&self, array); - if (njs_fast_object(length)) { - do { - ret = njs_value_property_i64(vm, this, start++, &val); - if (njs_slow_path(ret == NJS_ERROR)) { - return NJS_ERROR; - } - - if (ret == NJS_OK) { - ret = njs_value_property_i64_set(vm, &self, start, &val); - if (njs_slow_path(ret == NJS_ERROR)) { - return ret; - } - } - - length--; - } while (length != 0); - - ret = NJS_OK; - goto done; - } - keys = njs_array_indices(vm, this); if (njs_slow_path(keys == NULL)) { return NJS_ERROR; } for (n = 0; n < keys->length; n++) { + idx = njs_string_to_index(&keys->start[n]); + + if (idx < start || idx >= start + length) { + continue; + } + ret = njs_value_property(vm, this, keys->start[n].atom_id, &val); if (njs_slow_path(ret == NJS_ERROR)) { goto done; } - ret = njs_value_property_set(vm, &self, keys->start[n].atom_id, &val); + ret = njs_value_property_i64_set(vm, &self, idx - start, &val); if (njs_slow_path(ret == NJS_ERROR)) { goto done; } diff --git a/src/test/njs_unit_test.c b/src/test/njs_unit_test.c index 7a28332c..8cc0e8be 100644 --- a/src/test/njs_unit_test.c +++ b/src/test/njs_unit_test.c @@ -5315,6 +5315,13 @@ static njs_unit_test_t njs_test[] = { njs_str("Array.prototype.slice.call({ length: Object.create(null) })"), njs_str("TypeError: Cannot convert object to primitive value") }, + /* Large sparse slice goes through the non-fast keys path. */ + + { njs_str("var a = []; a[10] = 'a'; a[40000] = 'b'; a.length = 50000;" + "var s = a.slice(5, 45000);" + "[s.length, s[5], s[39995], (10 in s), (40000 in s)].join(',')"), + njs_str("44995,a,b,false,false") }, + { njs_str("Array.prototype.slice.call({length:-1})"), njs_str("") },