Welcome! Log In Create A New Profile

Advanced

[njs] Fixed Array.prototype.slice() when array is changed while iterating.

Dmitry Volyntsev
January 14, 2022 10:00AM
details: https://hg.nginx.org/njs/rev/d940c6aaec5d
branches:
changeset: 1803:d940c6aaec5d
user: Dmitry Volyntsev <xeioex@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-leave@nginx.org
Subject Author Views Posted

[njs] Fixed Array.prototype.slice() when array is changed while iterating.

Dmitry Volyntsev 355 January 14, 2022 10:00AM



Sorry, you do not have permission to post/reply in this forum.

Online Users

Guests: 158
Record Number of Users: 8 on April 13, 2023
Record Number of Guests: 421 on December 02, 2018
Powered by nginx      Powered by FreeBSD      PHP Powered      Powered by MariaDB      ipv6 ready