[njs] Fixed Regexp.prototype.test() for regexps with backreferences.

Dmitry Volyntsev xeioex at nginx.com
Fri Oct 4 14:19:29 UTC 2019


details:   https://hg.nginx.org/njs/rev/d62db2c99851
branches:  
changeset: 1170:d62db2c99851
user:      Dmitry Volyntsev <xeioex at nginx.com>
date:      Fri Oct 04 17:19:06 2019 +0300
description:
Fixed Regexp.prototype.test() for regexps with backreferences.

This closes #225 issue on Github.

diffstat:

 src/njs_pcre.c           |  18 ++++++++++++++++++
 src/njs_pcre.h           |   1 +
 src/njs_regex.h          |   1 +
 src/njs_regexp.c         |  42 ++++++++++++++++++++++++++++++++----------
 src/test/njs_unit_test.c |   4 ++++
 5 files changed, 56 insertions(+), 10 deletions(-)

diffs (139 lines):

diff -r 956b24477d59 -r d62db2c99851 src/njs_pcre.c
--- a/src/njs_pcre.c	Thu Oct 03 16:59:22 2019 +0300
+++ b/src/njs_pcre.c	Fri Oct 04 17:19:06 2019 +0300
@@ -111,6 +111,17 @@ njs_regex_compile(njs_regex_t *regex, u_
         goto done;
     }
 
+    err = pcre_fullinfo(regex->code, NULL, PCRE_INFO_BACKREFMAX,
+                        &regex->backrefmax);
+
+    if (njs_slow_path(err < 0)) {
+        njs_alert(ctx->trace, NJS_LEVEL_ERROR,
+                  "pcre_fullinfo(\"%s\", PCRE_INFO_BACKREFMAX) failed: %d",
+                  pattern, err);
+
+        goto done;
+    }
+
     /* Reserve additional elements for the first "$0" capture. */
     regex->ncaptures++;
 
@@ -175,6 +186,13 @@ njs_regex_ncaptures(njs_regex_t *regex)
 }
 
 
+njs_uint_t
+njs_regex_backrefs(njs_regex_t *regex)
+{
+    return regex->backrefmax;
+}
+
+
 njs_int_t
 njs_regex_named_captures(njs_regex_t *regex, njs_str_t *name, int n)
 {
diff -r 956b24477d59 -r d62db2c99851 src/njs_pcre.h
--- a/src/njs_pcre.h	Thu Oct 03 16:59:22 2019 +0300
+++ b/src/njs_pcre.h	Fri Oct 04 17:19:06 2019 +0300
@@ -18,6 +18,7 @@ struct njs_regex_s {
     pcre        *code;
     pcre_extra  *extra;
     int         ncaptures;
+    int         backrefmax;
     int         nentries;
     int         entry_size;
     char        *entries;
diff -r 956b24477d59 -r d62db2c99851 src/njs_regex.h
--- a/src/njs_regex.h	Thu Oct 03 16:59:22 2019 +0300
+++ b/src/njs_regex.h	Fri Oct 04 17:19:06 2019 +0300
@@ -31,6 +31,7 @@ NJS_EXPORT njs_int_t njs_regex_compile(n
     size_t len, njs_uint_t options, njs_regex_context_t *ctx);
 NJS_EXPORT njs_bool_t njs_regex_is_valid(njs_regex_t *regex);
 NJS_EXPORT njs_uint_t njs_regex_ncaptures(njs_regex_t *regex);
+NJS_EXPORT njs_uint_t njs_regex_backrefs(njs_regex_t *regex);
 NJS_EXPORT njs_int_t njs_regex_named_captures(njs_regex_t *regex,
     njs_str_t *name, int n);
 NJS_EXPORT njs_regex_match_data_t *njs_regex_match_data(njs_regex_t *regex,
diff -r 956b24477d59 -r d62db2c99851 src/njs_regexp.c
--- a/src/njs_regexp.c	Thu Oct 03 16:59:22 2019 +0300
+++ b/src/njs_regexp.c	Fri Oct 04 17:19:06 2019 +0300
@@ -842,11 +842,13 @@ static njs_int_t
 njs_regexp_prototype_test(njs_vm_t *vm, njs_value_t *args, njs_uint_t nargs,
     njs_index_t unused)
 {
-    njs_int_t             ret;
-    njs_uint_t            n;
-    const njs_value_t     *value, *retval;
-    njs_string_prop_t     string;
-    njs_regexp_pattern_t  *pattern;
+    njs_int_t               ret;
+    njs_uint_t              n;
+    njs_regex_t             *regex;
+    const njs_value_t       *value, *retval;
+    njs_string_prop_t       string;
+    njs_regexp_pattern_t    *pattern;
+    njs_regex_match_data_t  *match_data;
 
     if (!njs_is_regexp(njs_arg(args, nargs, 0))) {
         njs_type_error(vm, "\"this\" argument is not a regexp");
@@ -866,20 +868,40 @@ njs_regexp_prototype_test(njs_vm_t *vm, 
 
     pattern = njs_regexp_pattern(&args[0]);
 
-    if (njs_regex_is_valid(&pattern->regex[n])) {
-        ret = njs_regexp_match(vm, &pattern->regex[n], string.start,
-                               string.size, vm->single_match_data);
+    regex = &pattern->regex[n];
+    match_data = vm->single_match_data;
+
+    if (njs_regex_is_valid(regex)) {
+        if (njs_regex_backrefs(regex) != 0) {
+            match_data = njs_regex_match_data(regex, vm->regex_context);
+            if (njs_slow_path(match_data == NULL)) {
+                njs_memory_error(vm);
+                return NJS_ERROR;
+            }
+        }
+
+        ret = njs_regexp_match(vm, regex, string.start, string.size,
+                               match_data);
         if (ret >= 0) {
             retval = &njs_value_true;
 
         } else if (ret != NJS_REGEX_NOMATCH) {
-            return NJS_ERROR;
+            ret = NJS_ERROR;
+            goto done;
         }
     }
 
+    ret = NJS_OK;
+
     vm->retval = *retval;
 
-    return NJS_OK;
+done:
+
+    if (match_data != vm->single_match_data) {
+        njs_regex_match_data_free(match_data, vm->regex_context);
+    }
+
+    return ret;
 }
 
 
diff -r 956b24477d59 -r d62db2c99851 src/test/njs_unit_test.c
--- a/src/test/njs_unit_test.c	Thu Oct 03 16:59:22 2019 +0300
+++ b/src/test/njs_unit_test.c	Fri Oct 04 17:19:06 2019 +0300
@@ -8178,6 +8178,10 @@ static njs_unit_test_t  njs_test[] =
       njs_str("true") },
 #endif
 
+    { njs_str("var re = /<(?<key>[\\w\\-\\.\\:]+)>(?<body>.*?)<\\/\\1>/g;"
+              "['<A>XXX</A>', '<A>XX</B>'].map(s=>re.test(s))"),
+      njs_str("true,false") },
+
     { njs_str("/\\x80/.test('\\u0080')"),
       njs_str("true") },
 


More information about the nginx-devel mailing list