[njs] Fixed String.prototype.replace(re) if re.exec() returns non-flat array.

Vadim Zhestikov v.zhestikov at f5.com
Mon Nov 7 22:10:31 UTC 2022


details:   https://hg.nginx.org/njs/rev/b80c24512157
branches:  
changeset: 1988:b80c24512157
user:      Vadim Zhestikov <v.zhestikov at f5.com>
date:      Mon Nov 07 14:08:28 2022 -0800
description:
Fixed String.prototype.replace(re) if re.exec() returns non-flat array.

This fixes #587 issue on Github.

diffstat:

 src/njs_regexp.c         |  58 +++++++++++++++--------------------------------
 src/test/njs_unit_test.c |  29 ++++++++++++++++++++++++
 2 files changed, 48 insertions(+), 39 deletions(-)

diffs (116 lines):

diff -r 4f66a66ef300 -r b80c24512157 src/njs_regexp.c
--- a/src/njs_regexp.c	Wed Oct 26 16:33:15 2022 -0700
+++ b/src/njs_regexp.c	Mon Nov 07 14:08:28 2022 -0800
@@ -1362,54 +1362,34 @@ njs_regexp_prototype_symbol_replace(njs_
 
         pos = njs_max(njs_min(pos, (int64_t) s.size), 0);
 
-        if (njs_fast_path(njs_is_fast_array(r) && njs_array_len(r) != 0)) {
-            array = njs_array(r);
+        ret = njs_object_length(vm, r, &ncaptures);
+        if (njs_slow_path(ret != NJS_OK)) {
+            goto exception;
+        }
 
-            arguments = array->start;
-            arguments[0] = matched;
-            ncaptures = njs_max((int64_t) array->length - 1, 0);
+        ncaptures = njs_min(njs_max(ncaptures - 1, 0), 99);
 
-            for (n = 1; n <= ncaptures; n++) {
-                if (njs_is_undefined(&arguments[n])) {
-                    continue;
-                }
+        array = njs_array_alloc(vm, 1, ncaptures + 1, 0);
+        if (njs_slow_path(array == NULL)) {
+            goto exception;
+        }
 
-                ret = njs_value_to_string(vm, &arguments[n], &arguments[n]);
-                if (njs_slow_path(ret == NJS_ERROR)) {
-                    goto exception;
-                }
-            }
+        arguments = array->start;
+        arguments[0] = matched;
 
-        } else {
-            ret = njs_object_length(vm, r, &ncaptures);
-            if (njs_slow_path(ret != NJS_OK)) {
+        for (n = 1; n <= ncaptures; n++) {
+            ret = njs_value_property_i64(vm, r, n, &arguments[n]);
+            if (njs_slow_path(ret == NJS_ERROR)) {
                 goto exception;
             }
 
-            ncaptures = njs_max(ncaptures - 1, 0);
-
-            array = njs_array_alloc(vm, 0, ncaptures + 1, 0);
-            if (njs_slow_path(array == NULL)) {
-                goto exception;
+            if (njs_is_undefined(&arguments[n])) {
+                continue;
             }
 
-            arguments = array->start;
-            arguments[0] = matched;
-
-            for (n = 1; n <= ncaptures; n++) {
-                ret = njs_value_property_i64(vm, r, n, &arguments[n]);
-                if (njs_slow_path(ret == NJS_ERROR)) {
-                    goto exception;
-                }
-
-                if (njs_is_undefined(&arguments[n])) {
-                    continue;
-                }
-
-                ret = njs_value_to_string(vm, &arguments[n], &arguments[n]);
-                if (njs_slow_path(ret == NJS_ERROR)) {
-                    goto exception;
-                }
+            ret = njs_value_to_string(vm, &arguments[n], &arguments[n]);
+            if (njs_slow_path(ret == NJS_ERROR)) {
+                goto exception;
             }
         }
 
diff -r 4f66a66ef300 -r b80c24512157 src/test/njs_unit_test.c
--- a/src/test/njs_unit_test.c	Wed Oct 26 16:33:15 2022 -0700
+++ b/src/test/njs_unit_test.c	Mon Nov 07 14:08:28 2022 -0800
@@ -8937,6 +8937,35 @@ static njs_unit_test_t  njs_test[] =
     { njs_str("String.bytesFrom([255,149,15,97,95]).replace(/_/g, 'X')[4]"),
       njs_str("X") },
 
+    { njs_str("var a = [];"
+              "a[2] = '';"
+              "var re = /any_regexp/;"
+              "re.exec = function () {"
+              "    return a;"
+              "};"
+              "var r = 'any_string'.replace(re);"),
+      njs_str("undefined") },
+
+    { njs_str("var a = [];"
+              "a[2] = {toString() {a[2**20] = 1; return 'X';}}; "
+              "a[4] = 'Y';"
+              "a[99] = 'Z';"
+              "a[100] = '*';"
+              "a[200] = '!';"
+              "var re = /b/;"
+              "re.exec = () => a;"
+              "'abc'.replace(re, '@$1|$2|$3|$4|$99|$100|@')"),
+      njs_str("@|X||Y|Z|0|@") },
+
+    { njs_str("var a = [];"
+              "Object.defineProperty(a, 32768, {});"
+              "var re = /any_regexp/;"
+              "re.exec = function () {"
+              "    return a;"
+              "};"
+              "var r = 'any_string'.replace(re);"),
+      njs_str("undefined") },
+
     { njs_str("/=/"),
       njs_str("/=/") },
 



More information about the nginx-devel mailing list