Welcome! Log In Create A New Profile

Advanced

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

Dmitry Volyntsev
January 14, 2022 10:06AM
details: https://hg.nginx.org/njs/rev/7467158d9f37
branches:
changeset: 1807:7467158d9f37
user: Dmitry Volyntsev <xeioex@nginx.com>
date: Fri Jan 14 14:40:27 2022 +0000
description:
Fixed Array.prototype.reverse() 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 commits.

diffstat:

src/njs_array.c | 47 -----------------------------------------------
src/test/njs_unit_test.c | 12 ++++++++++++
2 files changed, 12 insertions(+), 47 deletions(-)

diffs (86 lines):

diff -r dfbde7620ced -r 7467158d9f37 src/njs_array.c
--- a/src/njs_array.c Thu Jan 13 18:30:31 2022 +0000
+++ b/src/njs_array.c Fri Jan 14 14:40:27 2022 +0000
@@ -1367,7 +1367,6 @@ njs_array_prototype_reverse(njs_vm_t *vm
int64_t length, l, h;
njs_int_t ret, lret, hret;
njs_value_t value, lvalue, hvalue, *this;
- njs_array_t *array;

this = njs_argument(args, 0);

@@ -1386,52 +1385,6 @@ njs_array_prototype_reverse(njs_vm_t *vm
return NJS_OK;
}

- if (njs_is_fast_array(this)) {
- array = njs_array(this);
-
- for (l = 0, h = length - 1; l < h; l++, h--) {
- if (njs_fast_path(njs_is_valid(&array->start[l]))) {
- lvalue = array->start[l];
- lret = NJS_OK;
-
- } else {
- lret = njs_value_property_i64(vm, this, l, &lvalue);
- if (njs_slow_path(lret == NJS_ERROR)) {
- return NJS_ERROR;
- }
- }
-
- if (njs_fast_path(njs_is_valid(&array->start[h]))) {
- hvalue = array->start[h];
- hret = NJS_OK;
-
- } else {
- hret = njs_value_property_i64(vm, this, h, &hvalue);
- if (njs_slow_path(hret == NJS_ERROR)) {
- return NJS_ERROR;
- }
- }
-
- if (lret == NJS_OK) {
- array->start[h] = lvalue;
-
- if (hret == NJS_OK) {
- array->start[l] = hvalue;
-
- } else {
- array->start[l] = njs_value_invalid;
- }
-
- } else if (hret == NJS_OK) {
- array->start[l] = hvalue;
- array->start[h] = njs_value_invalid;
- }
- }
-
- njs_set_array(&vm->retval, array);
- return NJS_OK;
- }
-
for (l = 0, h = length - 1; l < h; l++, h--) {
lret = njs_value_property_i64(vm, this, l, &lvalue);
if (njs_slow_path(lret == NJS_ERROR)) {
diff -r dfbde7620ced -r 7467158d9f37 src/test/njs_unit_test.c
--- a/src/test/njs_unit_test.c Thu Jan 13 18:30:31 2022 +0000
+++ b/src/test/njs_unit_test.c Fri Jan 14 14:40:27 2022 +0000
@@ -4883,6 +4883,18 @@ static njs_unit_test_t njs_test[] =
{ njs_str("[,,,3,2,1].reverse()"),
njs_str("1,2,3,,,") },

+ { njs_str("var a = [,,2,1];"
+ "Object.defineProperty(a.__proto__, 0, {"
+ " get: () => {"
+ " a.length = 10**6;"
+ " return 4;"
+ " },"
+ " set: (setval) => { Object.defineProperty(a, 0, { value: setval }); },"
+ "});"
+ "a.reverse();"
+ "a.slice(0, 4)"),
+ njs_str("1,2,,4") },
+
{ njs_str("var o = {1:true, 2:'', length:-2}; Array.prototype.reverse.call(o) === o"),
njs_str("true") },

_______________________________________________
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.reverse() when array is changed while iterating.

Dmitry Volyntsev 69 January 14, 2022 10:06AM



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

Online Users

Guests: 48
Record Number of Users: 6 on February 13, 2018
Record Number of Guests: 421 on December 02, 2018
Powered by nginx      Powered by FreeBSD      PHP Powered      Powered by MariaDB      ipv6 ready