From 44fe9c1c0cd490fdefc5748174cd1c0d1c8aab11 Mon Sep 17 00:00:00 2001 From: Igor Sysoev Date: Wed, 1 Jun 2016 15:31:34 +0300 Subject: [PATCH] Using nxt_regex interface in nJSVM. --- Makefile | 2 + njs/njs_disassembler.c | 1 - njs/njs_lexer_keyword.c | 1 - njs/njs_regexp.c | 234 +++++++++++++++++---------------------- njs/njs_regexp.h | 3 +- njs/njs_regexp_pattern.h | 4 +- njs/njs_string.c | 91 ++++++++++----- njs/njs_string.h | 2 + njs/njs_vm.h | 13 ++- njs/njscript.c | 15 ++- njs/test/njs_unit_test.c | 3 + 11 files changed, 203 insertions(+), 166 deletions(-) diff --git a/Makefile b/Makefile index e12f9ed9..74b6b78a 100644 --- a/Makefile +++ b/Makefile @@ -36,6 +36,7 @@ $(NXT_BUILDDIR)/libnjs.a: \ $(NXT_BUILDDIR)/nxt_rbtree.o \ $(NXT_BUILDDIR)/nxt_lvlhsh.o \ $(NXT_BUILDDIR)/nxt_random.o \ + $(NXT_BUILDDIR)/nxt_pcre.o \ $(NXT_BUILDDIR)/nxt_malloc.o \ $(NXT_BUILDDIR)/nxt_mem_cache_pool.o \ @@ -67,6 +68,7 @@ $(NXT_BUILDDIR)/libnjs.a: \ $(NXT_BUILDDIR)/nxt_rbtree.o \ $(NXT_BUILDDIR)/nxt_lvlhsh.o \ $(NXT_BUILDDIR)/nxt_random.o \ + $(NXT_BUILDDIR)/nxt_pcre.o \ $(NXT_BUILDDIR)/nxt_malloc.o \ $(NXT_BUILDDIR)/nxt_mem_cache_pool.o \ diff --git a/njs/njs_disassembler.c b/njs/njs_disassembler.c index 748ec8bf..93514e06 100644 --- a/njs/njs_disassembler.c +++ b/njs/njs_disassembler.c @@ -14,7 +14,6 @@ #include #include #include -#include #include #include #include diff --git a/njs/njs_lexer_keyword.c b/njs/njs_lexer_keyword.c index 0a3a6228..c699342d 100644 --- a/njs/njs_lexer_keyword.c +++ b/njs/njs_lexer_keyword.c @@ -16,7 +16,6 @@ #include #include #include -#include #include #include #include diff --git a/njs/njs_regexp.c b/njs/njs_regexp.c index 7e81708c..a0a93969 100644 --- a/njs/njs_regexp.c +++ b/njs/njs_regexp.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -30,16 +31,50 @@ #include +static void *njs_regexp_malloc(size_t size, void *memory_data); +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 int njs_regexp_pattern_compile(pcre **code, pcre_extra **extra, +static int njs_regexp_pattern_compile(njs_vm_t *vm, nxt_regex_t *regex, u_char *source, int options); static njs_ret_t njs_regexp_exec_result(njs_vm_t *vm, njs_regexp_t *regexp, - u_char *string, int *captures, nxt_uint_t utf8); + u_char *string, nxt_regex_match_data_t *match_data, nxt_uint_t utf8); static njs_ret_t njs_regexp_string_create(njs_vm_t *vm, njs_value_t *value, u_char *start, uint32_t size, int32_t length); +njs_ret_t +njs_regexp_init(njs_vm_t *vm) +{ + vm->regex_context = nxt_regex_context_create(njs_regexp_malloc, + njs_regexp_free, vm->mem_cache_pool); + if (nxt_slow_path(vm->regex_context == NULL)) { + return NXT_ERROR; + } + + vm->single_match_data = nxt_regex_match_data(NULL, vm->regex_context); + if (nxt_slow_path(vm->single_match_data == NULL)) { + return NXT_ERROR; + } + + return NXT_OK; +} + + +static void * +njs_regexp_malloc(size_t size, void *memory_data) +{ + return nxt_mem_cache_alloc(memory_data, size); +} + + +static void +njs_regexp_free(void *p, void *memory_data) +{ + nxt_mem_cache_free(memory_data, p); +} + + njs_ret_t njs_regexp_constructor(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused) @@ -205,18 +240,14 @@ njs_regexp_pattern_create(njs_vm_t *vm, u_char *start, size_t length, size += ((flags & NJS_REGEXP_IGNORE_CASE) != 0); size += ((flags & NJS_REGEXP_MULTILINE) != 0); - pattern = nxt_mem_cache_alloc(vm->mem_cache_pool, - sizeof(njs_regexp_pattern_t) - + 1 + length + size + 1); + pattern = nxt_mem_cache_zalloc(vm->mem_cache_pool, + sizeof(njs_regexp_pattern_t) + + 1 + length + size + 1); if (nxt_slow_path(pattern == NULL)) { return NULL; } pattern->flags = size; - pattern->code[0] = NULL; - pattern->code[1] = NULL; - pattern->extra[0] = NULL; - pattern->extra[1] = NULL; pattern->next = NULL; p = (u_char *) pattern + sizeof(njs_regexp_pattern_t); @@ -254,18 +285,16 @@ njs_regexp_pattern_create(njs_vm_t *vm, u_char *start, size_t length, *p++ = '\0'; - ret = njs_regexp_pattern_compile(&pattern->code[0], &pattern->extra[0], + ret = njs_regexp_pattern_compile(vm, &pattern->regex[0], &pattern->source[1], options); - if (nxt_slow_path(ret < 0)) { return NULL; } pattern->ncaptures = ret; - ret = njs_regexp_pattern_compile(&pattern->code[1], &pattern->extra[1], + ret = njs_regexp_pattern_compile(vm, &pattern->regex[1], &pattern->source[1], options | PCRE_UTF8); - if (nxt_fast_path(ret >= 0)) { if (nxt_slow_path((u_int) ret != pattern->ncaptures)) { @@ -273,75 +302,35 @@ njs_regexp_pattern_create(njs_vm_t *vm, u_char *start, size_t length, "and UTF-8 versions of RegExp \"%s\" vary: %d vs %d", &pattern->source[1], pattern->ncaptures, ret); - njs_regexp_pattern_free(pattern); + nxt_mem_cache_free(vm->mem_cache_pool, pattern); return NULL; } } else if (ret != NXT_DECLINED) { - njs_regexp_pattern_free(pattern); + nxt_mem_cache_free(vm->mem_cache_pool, pattern); return NULL; } *end = '/'; - pattern->next = vm->pattern; - vm->pattern = pattern; - return pattern; } static int -njs_regexp_pattern_compile(pcre **code, pcre_extra **extra, u_char *source, +njs_regexp_pattern_compile(njs_vm_t *vm, nxt_regex_t *regex, u_char *source, int options) { - int ret, erroff, captures; - u_char *error; - const char *errstr; - - *code = pcre_compile((char *) source, options, &errstr, &erroff, NULL); - - if (nxt_slow_path(*code == NULL)) { - - if ((options & PCRE_UTF8) != 0) { - return NXT_DECLINED; - } - - error = source + erroff; - - if (*error != '\0') { - nxt_thread_log_error(NXT_LOG_ERR, - "pcre_compile(\"%s\") failed: %s at \"%s\"", - source, errstr, error); - } else { - nxt_thread_log_error(NXT_LOG_ERR, - "pcre_compile(\"%s\") failed: %s", - source, errstr); - } - - return NXT_ERROR; - } - - *extra = pcre_study(*code, 0, &errstr); - - if (nxt_slow_path(errstr != NULL)) { - nxt_thread_log_error(NXT_LOG_ERR, "pcre_study(\"%s\") failed: %s", - source, errstr); - return NXT_ERROR; - } + nxt_int_t ret; - ret = pcre_fullinfo(*code, NULL, PCRE_INFO_CAPTURECOUNT, &captures); + /* Zero length means a zero-terminated string. */ + ret = nxt_regex_compile(regex, source, 0, options, vm->regex_context); - if (nxt_fast_path(ret >= 0)) { - /* Reserve additional elements for the first "$0" capture. */ - return captures + 1; + if (nxt_fast_path(ret == NXT_OK)) { + return regex->ncaptures; } - nxt_thread_log_error(NXT_LOG_ERR, - "pcre_fullinfo(\"%s\", PCRE_INFO_CAPTURECOUNT) failed: %d", - source, ret); - - return NXT_ERROR; + return njs_string_exception(vm, NJS_SYNTAX_ERROR, vm->regex_context->error); } @@ -491,16 +480,15 @@ njs_regexp_prototype_test(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, pattern = args[0].data.u.regexp->pattern; - if (pattern->code[n] != NULL) { - ret = pcre_exec(pattern->code[n], pattern->extra[n], - (char *) string.start, string.size, 0, 0, NULL, 0); - + if (nxt_regex_is_valid(&pattern->regex[n])) { + ret = nxt_regex_match(&pattern->regex[n], string.start, string.size, + vm->single_match_data, vm->regex_context); if (ret >= 0) { retval = &njs_value_true; - } else if (ret != PCRE_ERROR_NOMATCH) { - vm->exception = &njs_exception_internal_error; - return NXT_ERROR; + } else if (ret != NGX_REGEX_NOMATCH) { + return njs_string_exception(vm, NJS_INTERNAL_ERROR, + vm->regex_context->error); } } @@ -514,13 +502,13 @@ njs_ret_t njs_regexp_prototype_exec(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused) { - int *captures, ncaptures; - njs_ret_t ret; - nxt_uint_t n, utf8; - njs_value_t *value; - njs_regexp_t *regexp; - njs_string_prop_t string; - njs_regexp_pattern_t *pattern; + njs_ret_t ret; + nxt_uint_t n, utf8; + njs_value_t *value; + njs_regexp_t *regexp; + njs_string_prop_t string; + njs_regexp_pattern_t *pattern; + nxt_regex_match_data_t *match_data; if (!njs_is_regexp(&args[0])) { vm->exception = &njs_exception_type_error; @@ -553,27 +541,28 @@ njs_regexp_prototype_exec(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, pattern = regexp->pattern; - if (pattern->code[n] != NULL) { + if (nxt_regex_is_valid(&pattern->regex[n])) { string.start += regexp->last_index; string.size -= regexp->last_index; - /* Each capture is stored in 3 vector elements. */ - ncaptures = pattern->ncaptures * 3; - - captures = alloca(ncaptures * sizeof(int)); - - ret = pcre_exec(pattern->code[n], pattern->extra[n], - (char *) string.start, string.size, - 0, 0, captures, ncaptures); + match_data = nxt_regex_match_data(&pattern->regex[n], + vm->regex_context); + if (nxt_slow_path(match_data == NULL)) { + return NXT_ERROR; + } + ret = nxt_regex_match(&pattern->regex[n], string.start, string.size, + match_data, vm->regex_context); if (ret >= 0) { - return njs_regexp_exec_result(vm, regexp, string.start, - captures, utf8); + return njs_regexp_exec_result(vm, regexp, string.start, match_data, + utf8); } - if (nxt_slow_path(ret != PCRE_ERROR_NOMATCH)) { - vm->exception = &njs_exception_internal_error; - return NXT_ERROR; + if (nxt_slow_path(ret != NGX_REGEX_NOMATCH)) { + nxt_regex_match_data_free(match_data, vm->regex_context); + + return njs_string_exception(vm, NJS_INTERNAL_ERROR, + vm->regex_context->error); } } @@ -586,8 +575,9 @@ njs_regexp_prototype_exec(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, static njs_ret_t njs_regexp_exec_result(njs_vm_t *vm, njs_regexp_t *regexp, u_char *string, - int *captures, nxt_uint_t utf8) + nxt_regex_match_data_t *match_data, nxt_uint_t utf8) { + int *captures; u_char *start; int32_t size, length; njs_ret_t ret; @@ -601,9 +591,11 @@ njs_regexp_exec_result(njs_vm_t *vm, njs_regexp_t *regexp, u_char *string, array = njs_array_alloc(vm, regexp->pattern->ncaptures, 0); if (nxt_slow_path(array == NULL)) { - return NXT_ERROR; + goto fail; } + captures = nxt_regex_captures(match_data); + for (i = 0; i < regexp->pattern->ncaptures; i++) { n = 2 * i; @@ -626,7 +618,7 @@ njs_regexp_exec_result(njs_vm_t *vm, njs_regexp_t *regexp, u_char *string, ret = njs_regexp_string_create(vm, &array->start[i], start, size, length); if (nxt_slow_path(ret != NXT_OK)) { - return NXT_ERROR; + goto fail; } } else { @@ -636,7 +628,7 @@ njs_regexp_exec_result(njs_vm_t *vm, njs_regexp_t *regexp, u_char *string, prop = njs_object_prop_alloc(vm, &njs_string_index); if (nxt_slow_path(prop == NULL)) { - return NXT_ERROR; + goto fail; } /* TODO: Non UTF-8 position */ @@ -657,13 +649,12 @@ njs_regexp_exec_result(njs_vm_t *vm, njs_regexp_t *regexp, u_char *string, ret = nxt_lvlhsh_insert(&array->object.hash, &lhq); if (nxt_slow_path(ret != NXT_OK)) { - /* Only NXT_ERROR can be returned here. */ - return ret; + goto fail; } prop = njs_object_prop_alloc(vm, &njs_string_input); if (nxt_slow_path(prop == NULL)) { - return NXT_ERROR; + goto fail; } njs_string_copy(&prop->value, ®exp->string); @@ -674,16 +665,25 @@ njs_regexp_exec_result(njs_vm_t *vm, njs_regexp_t *regexp, u_char *string, lhq.value = prop; ret = nxt_lvlhsh_insert(&array->object.hash, &lhq); - if (nxt_slow_path(ret != NXT_OK)) { - /* Only NXT_ERROR can be returned here. */ - return ret; + + if (nxt_fast_path(ret == NXT_OK)) { + vm->retval.data.u.array = array; + vm->retval.type = NJS_ARRAY; + vm->retval.data.truth = 1; + + ret = NXT_OK; + goto done; } - vm->retval.data.u.array = array; - vm->retval.type = NJS_ARRAY; - vm->retval.data.truth = 1; +fail: - return NXT_OK; + ret = NXT_ERROR; + +done: + + nxt_regex_match_data_free(match_data, vm->regex_context); + + return ret; } @@ -789,29 +789,3 @@ const njs_object_init_t njs_regexp_prototype_init = { njs_regexp_prototype_properties, nxt_nitems(njs_regexp_prototype_properties), }; - - -void -njs_regexp_pattern_free(njs_regexp_pattern_t *pattern) -{ - /* - * pcre_free() is enough to free PCRE extra study data. - * pcre_free_study() is required for JIT optimization, pcreapi(3): - * - * When you are finished with a pattern, you can free the memory used - * for the study data by calling pcre_free_study(). This function was - * added to the API for release 8.20. For earlier versions, the memory - * could be freed with pcre_free(), just like the pattern itself. This - * will still work in cases where JIT optimization is not used, but it - * is advisable to change to the new function when convenient. - */ - while (pattern != NULL) { - pcre_free(pattern->extra[0]); - pcre_free(pattern->code[0]); - - pcre_free(pattern->extra[1]); - pcre_free(pattern->code[1]); - - pattern = pattern->next; - } -} diff --git a/njs/njs_regexp.h b/njs/njs_regexp.h index 32661c5d..2743b679 100644 --- a/njs/njs_regexp.h +++ b/njs/njs_regexp.h @@ -32,6 +32,7 @@ struct njs_regexp_s { }; +njs_ret_t njs_regexp_init(njs_vm_t *vm); njs_ret_t njs_regexp_constructor(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused); nxt_int_t njs_regexp_literal(njs_vm_t *vm, njs_parser_t *parser, @@ -41,7 +42,7 @@ njs_regexp_pattern_t *njs_regexp_pattern_create(njs_vm_t *vm, njs_regexp_t *njs_regexp_alloc(njs_vm_t *vm, njs_regexp_pattern_t *pattern); njs_ret_t njs_regexp_prototype_exec(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused); -void njs_regexp_pattern_free(njs_regexp_pattern_t *pattern); + extern const njs_object_init_t njs_regexp_constructor_init; extern const njs_object_init_t njs_regexp_prototype_init; diff --git a/njs/njs_regexp_pattern.h b/njs/njs_regexp_pattern.h index 79ce501e..99bd302e 100644 --- a/njs/njs_regexp_pattern.h +++ b/njs/njs_regexp_pattern.h @@ -11,8 +11,8 @@ struct njs_regexp_pattern_s { - pcre *code[2]; - pcre_extra *extra[2]; + nxt_regex_t regex[2]; + njs_regexp_pattern_t *next; /* * A pattern source is used by RegExp.toString() method and diff --git a/njs/njs_string.c b/njs/njs_string.c index d4a07b1c..7eff704a 100644 --- a/njs/njs_string.c +++ b/njs/njs_string.c @@ -14,6 +14,7 @@ #include #include #include +#include #include #include #include @@ -1409,12 +1410,11 @@ static njs_ret_t njs_string_prototype_search(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_index_t unused) { - int ret; + int ret, *captures; nxt_int_t index; nxt_uint_t n; njs_string_prop_t string; njs_regexp_pattern_t *pattern; - int captures[3]; index = 0; @@ -1450,17 +1450,16 @@ njs_string_prototype_search(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, n = (string.length != 0 && string.length != string.size); - if (pattern->code[n] != NULL) { - ret = pcre_exec(pattern->code[n], pattern->extra[n], - (char *) string.start, string.size, - 0, 0, captures, 3); - + if (nxt_regex_is_valid(&pattern->regex[n])) { + ret = nxt_regex_match(&pattern->regex[n], string.start, string.size, + vm->single_match_data, vm->regex_context); if (ret >= 0) { + captures = nxt_regex_captures(vm->single_match_data); index = njs_string_index(&string, captures[0]); - } else if (ret != PCRE_ERROR_NOMATCH) { - vm->exception = &njs_exception_internal_error; - return NXT_ERROR; + } else if (ret != NGX_REGEX_NOMATCH) { + return njs_string_exception(vm, NJS_INTERNAL_ERROR, + vm->regex_context->error); } } } @@ -1489,7 +1488,7 @@ njs_string_prototype_match(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, njs_array_t *array; njs_string_prop_t string; njs_regexp_pattern_t *pattern; - int captures[3]; + int *captures; if (nargs == 1) { goto empty; @@ -1549,14 +1548,12 @@ njs_string_prototype_match(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, } } - if (pattern->code[n] != NULL) { + if (nxt_regex_is_valid(&pattern->regex[n])) { array = NULL; do { - ret = pcre_exec(pattern->code[n], pattern->extra[n], - (char *) string.start, string.size, - 0, 0, captures, 3); - + ret = nxt_regex_match(&pattern->regex[n], string.start, string.size, + vm->single_match_data, vm->regex_context); if (ret >= 0) { if (array != NULL) { if (array->length == array->size) { @@ -1577,6 +1574,7 @@ njs_string_prototype_match(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, vm->retval.data.truth = 1; } + captures = nxt_regex_captures(vm->single_match_data); start = &string.start[captures[0]]; string.start += captures[1]; @@ -1595,8 +1593,10 @@ njs_string_prototype_match(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, default: length = nxt_utf8_length(start, size); + if (nxt_slow_path(length < 0)) { - goto error; + vm->exception = &njs_exception_internal_error; + return NXT_ERROR; } break; @@ -1610,11 +1610,12 @@ njs_string_prototype_match(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, array->length++; - } else if (ret == PCRE_ERROR_NOMATCH) { + } else if (ret == NGX_REGEX_NOMATCH) { break; } else { - goto error; + return njs_string_exception(vm, NJS_INTERNAL_ERROR, + vm->regex_context->error); } } while (string.size > 0); @@ -1626,12 +1627,6 @@ njs_string_prototype_match(njs_vm_t *vm, njs_value_t *args, nxt_uint_t nargs, return NXT_OK; -error: - - vm->exception = &njs_exception_internal_error; - - return NXT_ERROR; - empty: array = njs_array_alloc(vm, 1, 0); @@ -2049,3 +2044,49 @@ njs_value_index(njs_vm_t *vm, njs_parser_t *parser, const njs_value_t *src) return (njs_index_t) value; } + + +nxt_int_t +njs_string_exception(njs_vm_t *vm, njs_exception_error_t exception, u_char *msg) +{ + u_char *p, *start; + uint32_t msg_length, size, length; + nxt_str_t *error; + njs_value_t *value; + + static nxt_str_t errors[] = { + nxt_string("SyntaxError: "), + nxt_string("InternalError: "), + }; + + value = nxt_mem_cache_alloc(vm->mem_cache_pool, sizeof(njs_value_t)); + if (nxt_slow_path(value == NULL)) { + return NXT_ERROR; + } + + error = &errors[exception]; + + msg_length = (msg != NULL) ? strlen((char *) msg) : 0; + length = nxt_utf8_length(msg, msg_length); + + size = error->len + msg_length; + length += error->len; + + start = njs_string_alloc(vm, value, size, length); + + if (nxt_fast_path(start != NULL)) { + memcpy(start, error->data, error->len); + p = start + error->len; + + memcpy(p, msg, msg_length); + + if (size != length && length >= NJS_STRING_MAP_OFFSET) { + njs_string_offset_map_init(start, size); + } + } + + vm->exception = value; + + return NXT_ERROR; +} + diff --git a/njs/njs_string.h b/njs/njs_string.h index e651c705..79428f59 100644 --- a/njs/njs_string.h +++ b/njs/njs_string.h @@ -107,6 +107,8 @@ double njs_string_to_number(njs_value_t *value, nxt_bool_t exact); njs_index_t njs_value_index(njs_vm_t *vm, njs_parser_t *parser, const njs_value_t *src); +nxt_int_t njs_string_exception(njs_vm_t *vm, njs_exception_error_t exception, + u_char *msg); extern const njs_object_init_t njs_string_constructor_init; extern const njs_object_init_t njs_string_prototype_init; diff --git a/njs/njs_vm.h b/njs/njs_vm.h index 00748208..a21a0e9f 100644 --- a/njs/njs_vm.h +++ b/njs/njs_vm.h @@ -8,6 +8,9 @@ #define _NJS_VM_H_INCLUDED_ +#include + + /* * Negative return values handled by nJSVM interpreter as special events. * The values must be in range from -1 to -11, because -12 is minimal jump @@ -790,7 +793,9 @@ struct njs_vm_s { njs_vm_shared_t *shared; njs_parser_t *parser; - njs_regexp_pattern_t *pattern; + + nxt_regex_context_t *regex_context; + nxt_regex_match_data_t *single_match_data; nxt_array_t *code; /* of njs_vm_code_t */ @@ -822,6 +827,12 @@ struct njs_vm_shared_s { }; +typedef enum { + NJS_SYNTAX_ERROR = 0, + NJS_INTERNAL_ERROR, +} njs_exception_error_t; + + nxt_int_t njs_vmcode_interpreter(njs_vm_t *vm); void njs_value_retain(njs_value_t *value); diff --git a/njs/njscript.c b/njs/njscript.c index ef41b2e7..37144ed2 100644 --- a/njs/njscript.c +++ b/njs/njscript.c @@ -116,12 +116,16 @@ njs_vm_create(nxt_mem_cache_pool_t *mcp, njs_vm_shared_t **shared, if (nxt_fast_path(vm != NULL)) { vm->mem_cache_pool = mcp; + ret = njs_regexp_init(vm); + if (nxt_slow_path(ret != NXT_OK)) { + return NULL; + } + if (shared != NULL && *shared != NULL) { vm->shared = *shared; } else { vm->shared = nxt_mem_cache_zalloc(mcp, sizeof(njs_vm_shared_t)); - if (nxt_slow_path(vm->shared == NULL)) { return NULL; } @@ -133,7 +137,6 @@ njs_vm_create(nxt_mem_cache_pool_t *mcp, njs_vm_shared_t **shared, nxt_lvlhsh_init(&vm->shared->keywords_hash); ret = njs_lexer_keywords_init(mcp, &vm->shared->keywords_hash); - if (nxt_slow_path(ret != NXT_OK)) { return NULL; } @@ -141,7 +144,6 @@ njs_vm_create(nxt_mem_cache_pool_t *mcp, njs_vm_shared_t **shared, nxt_lvlhsh_init(&vm->shared->values_hash); ret = njs_builtin_objects_create(vm); - if (nxt_slow_path(ret != NXT_OK)) { return NULL; } @@ -161,8 +163,6 @@ njs_vm_create(nxt_mem_cache_pool_t *mcp, njs_vm_shared_t **shared, void njs_vm_destroy(njs_vm_t *vm) { - njs_regexp_pattern_free(vm->pattern); - nxt_mem_cache_pool_destroy(vm->mem_cache_pool); } @@ -312,6 +312,11 @@ njs_vm_clone(njs_vm_t *vm, nxt_mem_cache_pool_t *mcp, void **external) memcpy(values + NJS_INDEX_GLOBAL_OFFSET, vm->global_scope, vm->scope_size); + ret = njs_regexp_init(nvm); + if (nxt_slow_path(ret != NXT_OK)) { + goto fail; + } + ret = njs_builtin_objects_clone(nvm); if (nxt_slow_path(ret != NXT_OK)) { goto fail; diff --git a/njs/test/njs_unit_test.c b/njs/test/njs_unit_test.c index 59f80c51..e07ca74f 100644 --- a/njs/test/njs_unit_test.c +++ b/njs/test/njs_unit_test.c @@ -3369,6 +3369,9 @@ static njs_unit_test_t njs_test[] = /* RegExp. */ + { nxt_string("/(/.test('')"), + nxt_string("SyntaxError: pcre_compile(\"(\") failed: missing )") }, + { nxt_string("/^$/.test('')"), nxt_string("true") }, -- 2.47.3