]> git.kaiwu.me - njs.git/commitdiff
Fixed RegExp.prototype.exec() with global regexp and unicode input.
authorDmitry Volyntsev <xeioex@nginx.com>
Wed, 18 Oct 2023 00:51:39 +0000 (17:51 -0700)
committerDmitry Volyntsev <xeioex@nginx.com>
Wed, 18 Oct 2023 00:51:39 +0000 (17:51 -0700)
Previously, when exactly 32 characters unicode string was provided and
the "lastIndex" value of "this" regexp was equal to 32 too, the
njs_string_utf8_offset() was called with invalid index argument (longer
than a size of the string).  As a result njs_string_utf8_offset()
returned garbage values.

This was manifested in the following ways:
1) InternalError: pcre2_match() failed: bad offset value

2) Very slow replace calls with global regexps, for
   example in expressions like: str.replace(/<re>/g).

This fixes #677 on Github.

src/njs_regexp.c
src/test/njs_unit_test.c

index 970041d6283d95e5dba7e19a641330eb7f89ca03..e61bf54ceaa2bfdcdd366d59c99c2757ff368ac8 100644 (file)
@@ -936,9 +936,14 @@ njs_regexp_builtin_exec(njs_vm_t *vm, njs_value_t *r, njs_value_t *s,
         offset = last_index;
 
     } else {
-        offset = njs_string_utf8_offset(string.start,
-                                        string.start + string.size, last_index)
-                 - string.start;
+        if ((size_t) last_index < string.length) {
+            offset = njs_string_utf8_offset(string.start,
+                                            string.start + string.size,
+                                            last_index)
+                     - string.start;
+        } else {
+            offset = string.size;
+        }
     }
 
     ret = njs_regexp_match(vm, &pattern->regex[type], string.start, offset,
index fbe9043eb54888397bbc0f47010773606699308d..bec1f53f0f80be63e293f09e7693976787241cf3 100644 (file)
@@ -9261,6 +9261,12 @@ static njs_unit_test_t  njs_test[] =
     { njs_str("'abc'.replaceAll(/^/g, '|$&|')"),
       njs_str("||abc") },
 
+    { njs_str("('α'.repeat(30) + 'aa').replace(/a/g, '#')"),
+      njs_str("αααααααααααααααααααααααααααααα##") },
+
+    { njs_str("('α'.repeat(30) + 'aa').replaceAll(/a/g, '#')"),
+      njs_str("αααααααααααααααααααααααααααααα##") },
+
     { njs_str("var uri ='/u/v1/Aa/bB?type=m3u8&mt=42';"
               "uri.replace(/^\\/u\\/v1\\/[^/]*\\/([^\?]*)\\?.*(mt=[^&]*).*$/, '$1|$2')"),
       njs_str("bB|mt=42") },