[njs] Fixed RegExp.prototype[@@replace]().

noreply at nginx.com noreply at nginx.com
Wed May 29 00:36:04 UTC 2024


details:   https://hg.nginx.org/njs/rev/cb1baa3906f8
branches:  
changeset: 2342:cb1baa3906f8
user:      Dmitry Volyntsev <xeioex at nginx.com>
date:      Tue May 28 15:49:39 2024 -0700
description:
Fixed RegExp.prototype[@@replace]().

With replacement containing "$'", "$\`" and Unicode characters.

The similar issue was fixed for String.prototype.replace() in
10127d70e941 (0.7.11).

Found by OSS-Fuzz.

diffstat:

 src/njs_regexp.c         |  27 ++++++++++++---------------
 src/test/njs_unit_test.c |   3 +++
 2 files changed, 15 insertions(+), 15 deletions(-)

diffs (84 lines):

diff -r 29ffafd582a7 -r cb1baa3906f8 src/njs_regexp.c
--- a/src/njs_regexp.c	Fri Apr 05 13:27:37 2024 -0700
+++ b/src/njs_regexp.c	Tue May 28 15:49:39 2024 -0700
@@ -1330,7 +1330,8 @@ njs_int_t
 njs_regexp_prototype_symbol_replace(njs_vm_t *vm, njs_value_t *args,
     njs_uint_t nargs, njs_index_t unused, njs_value_t *retval)
 {
-    int64_t            n, last_index, ncaptures, pos, next_pos, length;
+    int64_t            n, last_index, ncaptures, pos, length;
+    const u_char       *p, *next;
     njs_str_t          rep, m;
     njs_int_t          ret;
     njs_arr_t          results;
@@ -1461,8 +1462,8 @@ njs_regexp_prototype_symbol_replace(njs_
     }
 
     i = 0;
-    pos = 0;
-    next_pos = 0;
+    p = s.start;
+    next = p;
 
     while (i < results.items) {
         r = njs_arr_item(&results, i++);
@@ -1491,13 +1492,7 @@ njs_regexp_prototype_symbol_replace(njs_
             goto exception;
         }
 
-        if ((size_t) length != s.size) {
-            /* UTF-8 string. */
-            pos = njs_string_utf8_offset(s.start, s.start + s.size, pos)
-                  - s.start;
-        }
-
-        pos = njs_max(njs_min(pos, (int64_t) s.size), 0);
+        pos = njs_max(njs_min(pos, (int64_t) length), 0);
 
         ret = njs_object_length(vm, r, &ncaptures);
         if (njs_slow_path(ret != NJS_OK)) {
@@ -1578,15 +1573,17 @@ njs_regexp_prototype_symbol_replace(njs_
             goto exception;
         }
 
-        if (pos >= next_pos) {
-            njs_chb_append(&chain, &s.start[next_pos], pos - next_pos);
+        p = njs_string_offset(&s, pos);
+
+        if (p >= next) {
+            njs_chb_append(&chain, next, p - next);
 
             njs_string_get(retval, &rep);
             njs_chb_append_str(&chain, &rep);
 
             njs_string_get(&matched, &m);
 
-            next_pos = pos + (int64_t) m.length;
+            next = p + m.length;
         }
 
         if (!func_replace && njs_object_slots(r)) {
@@ -1599,8 +1596,8 @@ njs_regexp_prototype_symbol_replace(njs_
         }
     }
 
-    if (next_pos < (int64_t) s.size) {
-        njs_chb_append(&chain, &s.start[next_pos], s.size - next_pos);
+    if (next < s.start + s.size) {
+        njs_chb_append(&chain, next, s.start + s.size - next);
     }
 
     ret = njs_string_create_chb(vm, retval, &chain);
diff -r 29ffafd582a7 -r cb1baa3906f8 src/test/njs_unit_test.c
--- a/src/test/njs_unit_test.c	Fri Apr 05 13:27:37 2024 -0700
+++ b/src/test/njs_unit_test.c	Tue May 28 15:49:39 2024 -0700
@@ -9321,6 +9321,9 @@ static njs_unit_test_t  njs_test[] =
     { njs_str("'ABCB'.replaceAll(/(?<b>B)/g, '|$<BB$$|>@')"),
       njs_str("A|@C|@") },
 
+    { njs_str("'α'.repeat(8).replace(/()/g, '$`') == 'α'.repeat(44)"),
+      njs_str("true") },
+
     { njs_str("('β' + 'α'.repeat(33)+'β').replace(/(α+)(β+)/, (m, p1) => p1[32])"),
       njs_str("βα") },
 


More information about the nginx-devel mailing list