details: https://hg.nginx.org/njs/rev/d940c6aaec5d branches: changeset: 1803:d940c6aaec5d user: Dmitry Volyntsev <xei...@nginx.com> date: Thu Jan 13 15:59:08 2022 +0000 description: Fixed Array.prototype.slice() when array is changed while iterating.
Previously, the flat array may be converted to a slow one as a side-effect of a custom getter invocation for a proto array object. The function erroneously assumed that the this array remains flat while iterating. The fix is to eliminate the micro-optimization which uses direct pointers. The problem is similar to the previous (9578cc729205) commit. This closes #445 issue on Github. diffstat: src/njs_array.c | 49 +++++++++++------------------------------------ src/test/njs_unit_test.c | 10 +++++++++ 2 files changed, 22 insertions(+), 37 deletions(-) diffs (95 lines): diff -r 9578cc729205 -r d940c6aaec5d src/njs_array.c --- a/src/njs_array.c Wed Jan 12 17:59:42 2022 +0000 +++ b/src/njs_array.c Thu Jan 13 15:59:08 2022 +0000 @@ -729,7 +729,7 @@ njs_array_prototype_slice_copy(njs_vm_t uint32_t n; njs_int_t ret; njs_array_t *array, *keys; - njs_value_t *value, retval, self; + njs_value_t *value, *last, retval, self; const u_char *src, *end; njs_slice_prop_t string_slice; njs_string_prop_t string; @@ -748,34 +748,7 @@ njs_array_prototype_slice_copy(njs_vm_t n = 0; if (njs_fast_path(array->object.fast_array)) { - if (njs_fast_path(njs_is_fast_array(this))) { - value = njs_array_start(this); - - do { - if (njs_fast_path(njs_is_valid(&value[start]))) { - array->start[n++] = value[start++]; - - } else { - - /* src value may be in Array.prototype object. */ - - ret = njs_value_property_i64(vm, this, start++, - &array->start[n]); - if (njs_slow_path(ret == NJS_ERROR)) { - return NJS_ERROR; - } - - if (ret != NJS_OK) { - njs_set_invalid(&array->start[n]); - } - - n++; - } - - length--; - } while (length != 0); - - } else if (njs_is_string(this) || njs_is_object_string(this)) { + if (njs_is_string(this) || njs_is_object_string(this)) { if (njs_is_object_string(this)) { this = njs_object_value(this); @@ -816,16 +789,18 @@ njs_array_prototype_slice_copy(njs_vm_t } else if (njs_is_object(this)) { - do { - value = &array->start[n++]; - ret = njs_value_property_i64(vm, this, start++, value); - - if (ret != NJS_OK) { + last = &array->start[length]; + + for (value = array->start; value < last; value++, start++) { + ret = njs_value_property_i64(vm, this, start, value); + if (njs_slow_path(ret != NJS_OK)) { + if (ret == NJS_ERROR) { + return NJS_ERROR; + } + njs_set_invalid(value); } - - length--; - } while (length != 0); + } } else { diff -r 9578cc729205 -r d940c6aaec5d src/test/njs_unit_test.c --- a/src/test/njs_unit_test.c Wed Jan 12 17:59:42 2022 +0000 +++ b/src/test/njs_unit_test.c Thu Jan 13 15:59:08 2022 +0000 @@ -4525,6 +4525,16 @@ static njs_unit_test_t njs_test[] = "Array.prototype.slice.call(1, 0, 2)"), njs_str(",") }, + { njs_str("var a = [1, /**/, 3, 4];" + "Object.defineProperty(a.__proto__, 1, {" + " get: () => {" + " a.length = 10**6;" + " return 2;" + " }" + "});" + "a.slice(1)"), + njs_str("2,3,4") }, + { njs_str("Array.prototype.pop()"), njs_str("undefined") }, _______________________________________________ nginx-devel mailing list -- nginx-devel@nginx.org To unsubscribe send an email to nginx-devel-le...@nginx.org