[njs] Fixed Array.prototype.sort() when array is changed while sorting.

Dmitry Volyntsev xeioex at nginx.com
Sat Mar 4 02:50:10 UTC 2023


details:   https://hg.nginx.org/njs/rev/7ad9dd5da3fb
branches:  
changeset: 2063:7ad9dd5da3fb
user:      Dmitry Volyntsev <xeioex at nginx.com>
date:      Fri Mar 03 17:49:11 2023 -0800
description:
Fixed Array.prototype.sort() when array is changed while sorting.

Previously, the fast-path check did not take into account the fact that
the flat array may be resized as a side effect of the array's values
evaluation.

In addition, the slow_path fix ensures that "this" array is repopulated
again even if the array was resized.

This fixes #594 issue on Github.

diffstat:

 src/njs_array.c          |  13 +++++++------
 src/test/njs_unit_test.c |  28 ++++++++++++++++++++++++++++
 2 files changed, 35 insertions(+), 6 deletions(-)

diffs (68 lines):

diff -r 163229f0c552 -r 7ad9dd5da3fb src/njs_array.c
--- a/src/njs_array.c	Fri Mar 03 17:49:10 2023 -0800
+++ b/src/njs_array.c	Fri Mar 03 17:49:11 2023 -0800
@@ -2663,7 +2663,10 @@ slow_path:
         goto exception;
     }
 
-    if (njs_fast_path(fast_path && njs_is_fast_array(this))) {
+    if (njs_fast_path(fast_path
+                      && njs_is_fast_array(this)
+                      && (njs_array(this)->length == length)))
+    {
         array = njs_array(this);
         start = array->start;
 
@@ -2677,11 +2680,9 @@ slow_path:
 
     } else {
         for (i = 0; i < len; i++) {
-            if (slots[i].pos != i) {
-                ret = njs_value_property_i64_set(vm, this, i, &slots[i].value);
-                if (njs_slow_path(ret == NJS_ERROR)) {
-                    goto exception;
-                }
+            ret = njs_value_property_i64_set(vm, this, i, &slots[i].value);
+            if (njs_slow_path(ret == NJS_ERROR)) {
+                goto exception;
             }
         }
 
diff -r 163229f0c552 -r 7ad9dd5da3fb src/test/njs_unit_test.c
--- a/src/test/njs_unit_test.c	Fri Mar 03 17:49:10 2023 -0800
+++ b/src/test/njs_unit_test.c	Fri Mar 03 17:49:11 2023 -0800
@@ -7276,6 +7276,34 @@ static njs_unit_test_t  njs_test[] =
     { njs_str("var a = [1,2]; a.sort(() => {a.length = 65535}); a.length"),
       njs_str("65535") },
 
+    { njs_str("var a = [];"
+              "var shift = true;"
+              "for (let i = 0; i < 64; i++) {"
+              "    a[i] = { toString() {"
+              "                 if (shift) { a.shift() };"
+              "                 return (63 - i).toString().padStart(2, '0');"
+              "             }"
+              "           };"
+              "}"
+              "a.sort();"
+              "shift = false;"
+              "[a.length, a[0].toString(), a[63].toString()]"),
+      njs_str("64,00,63") },
+
+    { njs_str("var a = [];"
+              "var shift = true;"
+              "for (let i = 0; i < 64; i++) {"
+              "    a[i] = { toString() {"
+              "                 if (shift) { a.shift() };"
+              "                 return (i).toString().padStart(2, '0');"
+              "             }"
+              "           };"
+              "}"
+              "a.sort();"
+              "shift = false;"
+              "[a.length, a[0].toString(), a[63].toString()]"),
+      njs_str("64,00,63") },
+
     /*
       Array.prototype.keys()
       Array.prototype.values()


More information about the nginx-devel mailing list