[njs] Fixed RegExp constructor for regexp value arguments.

Dmitry Volyntsev xeioex at nginx.com
Thu Apr 18 15:15:04 UTC 2019


details:   https://hg.nginx.org/njs/rev/664d366b515a
branches:  
changeset: 903:664d366b515a
user:      Dmitry Volyntsev <xeioex at nginx.com>
date:      Thu Apr 18 18:14:56 2019 +0300
description:
Fixed RegExp constructor for regexp value arguments.

This closes #59 issue on Github.

diffstat:

 njs/njs_builtin.c        |    3 +-
 njs/njs_regexp.c         |  101 ++++++++++++++++++++++++++++++++++++++--------
 njs/test/njs_unit_test.c |   33 +++++++++++++++
 3 files changed, 117 insertions(+), 20 deletions(-)

diffs (193 lines):

diff -r e4ba35c2844b -r 664d366b515a njs/njs_builtin.c
--- a/njs/njs_builtin.c	Thu Apr 18 15:44:37 2019 +0300
+++ b/njs/njs_builtin.c	Thu Apr 18 18:14:56 2019 +0300
@@ -146,8 +146,7 @@ const njs_function_init_t  njs_native_co
     { njs_number_constructor,     { NJS_SKIP_ARG, NJS_NUMBER_ARG } },
     { njs_string_constructor,     { NJS_SKIP_ARG, NJS_STRING_ARG } },
     { njs_function_constructor,   { 0 } },
-    { njs_regexp_constructor,
-      { NJS_SKIP_ARG, NJS_STRING_ARG, NJS_STRING_ARG } },
+    { njs_regexp_constructor,     { 0 } },
     { njs_date_constructor,       { 0 } },
     { njs_hash_constructor,       { NJS_SKIP_ARG, NJS_STRING_ARG } },
     { njs_hmac_constructor,       { NJS_SKIP_ARG, NJS_STRING_ARG,
diff -r e4ba35c2844b -r 664d366b515a njs/njs_regexp.c
--- a/njs/njs_regexp.c	Thu Apr 18 15:44:37 2019 +0300
+++ b/njs/njs_regexp.c	Thu Apr 18 18:14:56 2019 +0300
@@ -15,6 +15,8 @@ static void *njs_regexp_malloc(size_t si
 static void njs_regexp_free(void *p, void *memory_data);
 static njs_regexp_flags_t njs_regexp_flags(u_char **start, u_char *end,
     nxt_bool_t bound);
+static njs_ret_t njs_regexp_prototype_source(njs_vm_t *vm, njs_value_t *value,
+    njs_value_t *setval, njs_value_t *retval);
 static int njs_regexp_pattern_compile(njs_vm_t *vm, nxt_regex_t *regex,
     u_char *source, int options);
 static u_char *njs_regexp_compile_trace_handler(nxt_trace_t *trace,
@@ -63,43 +65,106 @@ njs_regexp_free(void *p, void *memory_da
 }
 
 
+static njs_regexp_flags_t
+njs_regexp_value_flags(njs_vm_t *vm, const njs_value_t *regexp)
+{
+    njs_regexp_flags_t    flags;
+    njs_regexp_pattern_t  *pattern;
+
+    flags = 0;
+
+    pattern = regexp->data.u.regexp->pattern;
+
+    if (pattern->global) {
+        flags |= NJS_REGEXP_GLOBAL;
+    }
+
+    if (pattern->ignore_case) {
+        flags |= NJS_REGEXP_IGNORE_CASE;
+    }
+
+    if (pattern->multiline) {
+        flags |= NJS_REGEXP_MULTILINE;
+    }
+
+    return flags;
+}
+
+
 njs_ret_t
 njs_regexp_constructor(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs,
     njs_index_t unused)
 {
     u_char              *start;
+    njs_ret_t           ret;
     nxt_str_t           string;
-    njs_regexp_flags_t  flags;
+    njs_value_t         source, flags_string;
+    const njs_value_t   *pattern, *flags;
+    njs_regexp_flags_t  re_flags;
+
+    pattern = njs_arg(args, nargs, 1);
+
+    if (!njs_is_regexp(pattern) && !njs_is_primitive(pattern)) {
+        njs_vm_trap_value(vm, &args[1]);
 
-    flags = 0;
+        return njs_trap(vm, NJS_TRAP_STRING_ARG);
+    }
+
+    flags = njs_arg(args, nargs, 2);
 
-    switch (nargs) {
+    if (!njs_is_primitive(flags)) {
+        njs_vm_trap_value(vm, &args[2]);
+
+        return njs_trap(vm, NJS_TRAP_STRING_ARG);
+    }
+
+    re_flags = 0;
 
-    case 1:
-        string.start = NULL;
-        string.length = 0;
-        break;
+    if (njs_is_regexp(pattern)) {
+        ret = njs_regexp_prototype_source(vm, (njs_value_t *) pattern, NULL,
+                                          &source);
+        if (nxt_slow_path(ret != NXT_OK)) {
+            return ret;
+        }
+
+        re_flags = njs_regexp_value_flags(vm, pattern);
+
+        pattern = &source;
+
+    } else {
+        if (njs_is_undefined(pattern)) {
+            pattern = &njs_string_empty;
+        }
 
-    default:
-        njs_string_get(&args[2], &string);
+        ret = njs_primitive_value_to_string(vm, &source, pattern);
+        if (nxt_slow_path(ret != NXT_OK)) {
+            return ret;
+        }
+
+        pattern = &source;
+    }
+
+    if (!njs_is_undefined(flags)) {
+        ret = njs_primitive_value_to_string(vm, &flags_string, flags);
+        if (nxt_slow_path(ret != NXT_OK)) {
+            return ret;
+        }
+
+        njs_string_get(&flags_string, &string);
 
         start = string.start;
 
-        flags = njs_regexp_flags(&start, start + string.length, 1);
-        if (nxt_slow_path(flags < 0)) {
+        re_flags = njs_regexp_flags(&start, start + string.length, 1);
+        if (nxt_slow_path(re_flags < 0)) {
             njs_syntax_error(vm, "Invalid RegExp flags \"%V\"", &string);
             return NXT_ERROR;
         }
-
-        /* Fall through. */
-
-    case 2:
-        njs_string_get(&args[1], &string);
-        break;
     }
 
+    njs_string_get(pattern, &string);
+
     return njs_regexp_create(vm, &vm->retval, string.start, string.length,
-                             flags);
+                             re_flags);
 }
 
 
diff -r e4ba35c2844b -r 664d366b515a njs/test/njs_unit_test.c
--- a/njs/test/njs_unit_test.c	Thu Apr 18 15:44:37 2019 +0300
+++ b/njs/test/njs_unit_test.c	Thu Apr 18 18:14:56 2019 +0300
@@ -6967,6 +6967,39 @@ static njs_unit_test_t  njs_test[] =
     { nxt_string("new RegExp('', 'x')"),
       nxt_string("SyntaxError: Invalid RegExp flags \"x\"") },
 
+    { nxt_string("RegExp({})"),
+      nxt_string("/[object Object]/") },
+
+    { nxt_string("RegExp(true)"),
+      nxt_string("/true/") },
+
+    { nxt_string("RegExp(undefined)"),
+      nxt_string("/(?:)/") },
+
+    { nxt_string("RegExp('abc', undefined)"),
+      nxt_string("/abc/") },
+
+    { nxt_string("RegExp('abc', {})"),
+      nxt_string("SyntaxError: Invalid RegExp flags \"[object Object]\"") },
+
+    { nxt_string("RegExp(/expr/)"),
+      nxt_string("/expr/") },
+
+    { nxt_string("RegExp(/expr/i).ignoreCase"),
+      nxt_string("true") },
+
+    { nxt_string("RegExp(/expr/, 'x')"),
+      nxt_string("SyntaxError: Invalid RegExp flags \"x\"") },
+
+    { nxt_string("RegExp(new RegExp('expr'))"),
+      nxt_string("/expr/") },
+
+    { nxt_string("RegExp(new RegExp('expr')).multiline"),
+      nxt_string("false") },
+
+    { nxt_string("RegExp(new RegExp('expr'), 'm').multiline"),
+      nxt_string("true") },
+
     { nxt_string("new RegExp('[')"),
       nxt_string("SyntaxError: pcre_compile(\"[\") failed: missing terminating ] for character class") },
 


More information about the nginx-devel mailing list