[njs] Fixed String.prototype.replace() with replacement containing "$'", "$`".

Dmitry Volyntsev xeioex at nginx.com
Wed Mar 8 05:09:25 UTC 2023


details:   https://hg.nginx.org/njs/rev/10127d70e941
branches:  
changeset: 2068:10127d70e941
user:      Dmitry Volyntsev <xeioex at nginx.com>
date:      Tue Mar 07 20:51:45 2023 -0800
description:
Fixed String.prototype.replace() with replacement containing "$'", "$`".

Previously, the resulting string was might be broken when the string to
replace and the search string were UTF-8.  pos is always a character
offset, it should not be directly used as a byte size or offset.

diffstat:

 src/njs_string.c         |  36 ++++++++++++++++++++----------------
 src/test/njs_unit_test.c |  11 +++++++++++
 2 files changed, 31 insertions(+), 16 deletions(-)

diffs (82 lines):

diff -r 107c7098bd6d -r 10127d70e941 src/njs_string.c
--- a/src/njs_string.c	Tue Mar 07 20:38:08 2023 -0800
+++ b/src/njs_string.c	Tue Mar 07 20:51:45 2023 -0800
@@ -3476,12 +3476,14 @@ njs_string_get_substitution(njs_vm_t *vm
     njs_value_t *string, int64_t pos, njs_value_t *captures, int64_t ncaptures,
     njs_value_t *groups, njs_value_t *replacement, njs_value_t *retval)
 {
-    int64_t      tail, n;
-    u_char       c, c2, *p, *r, *end;
-    njs_str_t    rep, m, str, cap;
-    njs_int_t    ret;
-    njs_chb_t    chain;
-    njs_value_t  name, value;
+    u_char             c, c2, *p, *r, *end;
+    size_t             length;
+    int64_t            tail, n;
+    njs_str_t          rep, str, cap;
+    njs_int_t          ret;
+    njs_chb_t          chain;
+    njs_value_t        name, value;
+    njs_string_prop_t  s, m;
 
     njs_string_get(replacement, &rep);
     p = rep.start;
@@ -3513,24 +3515,26 @@ njs_string_get_substitution(njs_vm_t *vm
             break;
 
         case '&':
-            njs_string_get(matched, &m);
-            njs_chb_append_str(&chain, &m);
+            (void) njs_string_prop(&m, matched);
+            njs_chb_append(&chain, m.start, m.size);
             p += 2;
             break;
 
         case '`':
-            njs_string_get(string, &str);
-            njs_chb_append(&chain, str.start, pos);
+            (void) njs_string_prop(&s, string);
+            n = njs_string_offset(&s, pos) - s.start;
+            njs_chb_append(&chain, s.start, n);
             p += 2;
             break;
 
         case '\'':
-            njs_string_get(matched, &m);
-            tail = pos + m.length;
-
-            njs_string_get(string, &str);
-            njs_chb_append(&chain, &str.start[tail],
-                           njs_max((int64_t) str.length - tail, 0));
+            length = njs_string_prop(&m, matched);
+            (void) njs_string_prop(&s, string);
+
+            tail = njs_string_offset(&s, pos + length) - s.start;
+
+            njs_chb_append(&chain, &s.start[tail],
+                           njs_max((int64_t) s.size - tail, 0));
             p += 2;
             break;
 
diff -r 107c7098bd6d -r 10127d70e941 src/test/njs_unit_test.c
--- a/src/test/njs_unit_test.c	Tue Mar 07 20:38:08 2023 -0800
+++ b/src/test/njs_unit_test.c	Tue Mar 07 20:51:45 2023 -0800
@@ -8887,6 +8887,17 @@ static njs_unit_test_t  njs_test[] =
     { njs_str("'abcdbe'.replaceAll('b', '|$`X$\\'|')"),
       njs_str("a|aXcdbe|cd|abcdXe|e") },
 
+    { njs_str("var r = 'αβγ'.replace('β', \"$'\"); [r, r.length]"),
+      njs_str("αγγ,3") },
+
+    { njs_str("var r = 'αβγαβγ'.replaceAll('β', \"$'\"); [r, r.length]"),
+      njs_str("αγαβγγαγγ,9") },
+
+    { njs_str("var r = 'αβγ'.replace('β', \"$`\"); [r, r.length]"),
+      njs_str("ααγ,3") },
+
+    { njs_str("var r = 'αβγαβγ'.replaceAll('β', \"$`\"); [r, r.length]"),
+      njs_str("ααγααβγαγ,9") },
 
     { njs_str("'ABC'.replace('B', '$<g>')"),
       njs_str("A$<g>C") },


More information about the nginx-devel mailing list