[njs] Fixed String.prototype.replace() when first argument is not a string.
Alexander Borisov
alexander.borisov at nginx.com
Mon Sep 16 14:22:03 UTC 2019
details: https://hg.nginx.org/njs/rev/50cc68d71326
branches:
changeset: 1159:50cc68d71326
user: Alexander Borisov <alexander.borisov at nginx.com>
date: Mon Sep 16 17:21:36 2019 +0300
description:
Fixed String.prototype.replace() when first argument is not a string.
This closes #208 issue on GitHub.
diffstat:
src/njs_string.c | 121 ++++++++++++++++++++++++++++++----------------
src/test/njs_unit_test.c | 3 +
2 files changed, 81 insertions(+), 43 deletions(-)
diffs (317 lines):
diff -r bdeb67672e58 -r 50cc68d71326 src/njs_string.c
--- a/src/njs_string.c Wed Sep 11 19:46:30 2019 +0300
+++ b/src/njs_string.c Mon Sep 16 17:21:36 2019 +0300
@@ -78,16 +78,17 @@ static njs_int_t njs_string_match_multip
njs_regexp_pattern_t *pattern);
static njs_int_t njs_string_split_part_add(njs_vm_t *vm, njs_array_t *array,
njs_utf8_t utf8, const u_char *start, size_t size);
-static njs_int_t njs_string_replace_regexp(njs_vm_t *vm, njs_value_t *args,
- njs_string_replace_t *r);
+static njs_int_t njs_string_replace_regexp(njs_vm_t *vm, njs_value_t *this,
+ njs_value_t *regex, njs_string_replace_t *r);
static njs_int_t njs_string_replace_regexp_function(njs_vm_t *vm,
- njs_value_t *args, njs_string_replace_t *r, int *captures, njs_uint_t n);
+ njs_value_t *this, njs_value_t *regex, njs_string_replace_t *r,
+ int *captures, njs_uint_t n);
static njs_int_t njs_string_replace_regexp_join(njs_vm_t *vm,
njs_string_replace_t *r);
-static njs_int_t njs_string_replace_search(njs_vm_t *vm, njs_value_t *args,
- njs_string_replace_t *r);
+static njs_int_t njs_string_replace_search(njs_vm_t *vm, njs_value_t *this,
+ njs_value_t *search, njs_string_replace_t *r);
static njs_int_t njs_string_replace_search_function(njs_vm_t *vm,
- njs_value_t *args, njs_string_replace_t *r);
+ njs_value_t *this, njs_value_t *search, njs_string_replace_t *r);
static njs_int_t njs_string_replace_parse(njs_vm_t *vm,
njs_string_replace_t *r, u_char *p, u_char *end, size_t size,
njs_uint_t ncaptures);
@@ -3067,15 +3068,34 @@ njs_string_prototype_replace(njs_vm_t *v
u_char *p, *start, *end;
njs_int_t ret;
njs_uint_t ncaptures;
+ njs_value_t *this, *search, *replace;
njs_regex_t *regex;
njs_string_prop_t string;
njs_string_replace_t *r, string_replace;
+ this = njs_arg(args, nargs, 0);
+
+ if (njs_slow_path(njs_value_is_null_or_undefined(this))) {
+ njs_type_error(vm, "\"this\" argument cannot be "
+ "undefined or null value");
+ return NJS_ERROR;
+ }
+
+ if (!njs_is_string(this)) {
+ ret = njs_value_to_string(vm, this, this);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+ }
+
if (nargs == 1) {
goto original;
}
- (void) njs_string_prop(&string, &args[0]);
+ search = njs_arg(args, nargs, 1);
+ replace = njs_arg(args, nargs, 2);
+
+ (void) njs_string_prop(&string, this);
if (string.size == 0) {
goto original;
@@ -3095,8 +3115,8 @@ njs_string_prototype_replace(njs_vm_t *v
}
}
- if (njs_is_regexp(&args[1])) {
- regex = &njs_regexp_pattern(&args[1])->regex[r->type];
+ if (njs_is_regexp(search)) {
+ regex = &njs_regexp_pattern(search)->regex[r->type];
if (!njs_regex_is_valid(regex)) {
goto original;
@@ -3121,8 +3141,18 @@ njs_string_prototype_replace(njs_vm_t *v
if (nargs == 2) {
njs_string_replacement_copy(&r->part[1], &njs_string_undefined);
- } else if (njs_is_string(&args[2])) {
- njs_string_replacement_copy(&r->part[1], &args[2]);
+ } else if (njs_is_function(replace)) {
+ r->function = njs_function(replace);
+
+ } else {
+ if (!njs_is_string(replace)) {
+ ret = njs_value_to_string(vm, replace, replace);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+ }
+
+ njs_string_replacement_copy(&r->part[1], replace);
start = r->part[1].start;
@@ -3146,9 +3176,6 @@ njs_string_prototype_replace(njs_vm_t *v
break;
}
}
-
- } else {
- r->function = njs_function(&args[2]);
}
r->part[0].start = string.start;
@@ -3161,21 +3188,28 @@ njs_string_prototype_replace(njs_vm_t *v
return NJS_ERROR;
}
- return njs_string_replace_regexp(vm, args, r);
+ return njs_string_replace_regexp(vm, this, search, r);
}
- return njs_string_replace_search(vm, args, r);
+ if (!njs_is_string(search)) {
+ ret = njs_value_to_string(vm, search, search);
+ if (njs_slow_path(ret != NJS_OK)) {
+ return ret;
+ }
+ }
+
+ return njs_string_replace_search(vm, this, search, r);
original:
- njs_string_copy(&vm->retval, &args[0]);
+ njs_string_copy(&vm->retval, this);
return NJS_OK;
}
static njs_int_t
-njs_string_replace_regexp(njs_vm_t *vm, njs_value_t *args,
+njs_string_replace_regexp(njs_vm_t *vm, njs_value_t *this, njs_value_t *regex,
njs_string_replace_t *r)
{
int *captures;
@@ -3185,7 +3219,7 @@ njs_string_replace_regexp(njs_vm_t *vm,
njs_regexp_pattern_t *pattern;
njs_string_replace_part_t replace;
- pattern = njs_regexp_pattern(&args[1]);
+ pattern = njs_regexp_pattern(regex);
end = r->part[0].start + r->part[0].size;
replace = r->part[1];
@@ -3257,7 +3291,7 @@ njs_string_replace_regexp(njs_vm_t *vm,
}
if (r->function != NULL) {
- return njs_string_replace_regexp_function(vm, args, r,
+ return njs_string_replace_regexp_function(vm, this, regex, r,
captures, ret);
}
@@ -3269,7 +3303,7 @@ njs_string_replace_regexp(njs_vm_t *vm,
njs_set_invalid(&r->part[2].value);
if (r->function != NULL) {
- return njs_string_replace_regexp_function(vm, args, r,
+ return njs_string_replace_regexp_function(vm, this, regex, r,
captures, ret);
}
@@ -3294,15 +3328,15 @@ njs_string_replace_regexp(njs_vm_t *vm,
njs_arr_destroy(&r->parts);
- njs_string_copy(&vm->retval, &args[0]);
+ njs_string_copy(&vm->retval, this);
return NJS_OK;
}
static njs_int_t
-njs_string_replace_regexp_function(njs_vm_t *vm, njs_value_t *args,
- njs_string_replace_t *r, int *captures, njs_uint_t n)
+njs_string_replace_regexp_function(njs_vm_t *vm, njs_value_t *this,
+ njs_value_t *regex, njs_string_replace_t *r, int *captures, njs_uint_t n)
{
u_char *start;
size_t size, length;
@@ -3343,7 +3377,7 @@ njs_string_replace_regexp_function(njs_v
/* The whole string being examined. */
length = njs_string_calc_length(r->utf8, r->part[0].start, r->part[0].size);
- (void) njs_string_prop(&string, &args[0]);
+ (void) njs_string_prop(&string, this);
ret = njs_string_new(vm, &arguments[n + 2], string.start, string.size,
length);
@@ -3360,19 +3394,19 @@ njs_string_replace_regexp_function(njs_v
return ret;
}
- (void) njs_string_prop(&string, &args[0]);
+ (void) njs_string_prop(&string, this);
if (njs_is_string(&r->retval)) {
njs_string_replacement_copy(&r->part[r->empty ? 0 : 1], &r->retval);
- if (njs_regexp_pattern(&args[1])->global) {
+ if (njs_regexp_pattern(regex)->global) {
r->part += 2;
if (r->part[0].start > (string.start + string.size)) {
return njs_string_replace_regexp_join(vm, r);
}
- return njs_string_replace_regexp(vm, args, r);
+ return njs_string_replace_regexp(vm, this, regex, r);
}
return njs_string_replace_regexp_join(vm, r);
@@ -3397,26 +3431,26 @@ njs_string_replace_regexp_join(njs_vm_t
static njs_int_t
-njs_string_replace_search(njs_vm_t *vm, njs_value_t *args,
+njs_string_replace_search(njs_vm_t *vm, njs_value_t *this, njs_value_t *search,
njs_string_replace_t *r)
{
int captures[2];
u_char *p, *end;
size_t size;
njs_int_t ret;
- njs_str_t search;
-
- njs_string_get(&args[1], &search);
+ njs_str_t string;
+
+ njs_string_get(search, &string);
p = r->part[0].start;
- end = (p + r->part[0].size) - (search.length - 1);
+ end = (p + r->part[0].size) - (string.length - 1);
while (p < end) {
- if (memcmp(p, search.start, search.length) == 0) {
+ if (memcmp(p, string.start, string.length) == 0) {
if (r->substitutions != NULL) {
captures[0] = p - r->part[0].start;
- captures[1] = captures[0] + search.length;
+ captures[1] = captures[0] + string.length;
ret = njs_string_replace_substitute(vm, r, captures);
if (njs_slow_path(ret != NJS_OK)) {
@@ -3424,14 +3458,15 @@ njs_string_replace_search(njs_vm_t *vm,
}
} else {
- r->part[2].start = p + search.length;
+ r->part[2].start = p + string.length;
size = p - r->part[0].start;
- r->part[2].size = r->part[0].size - size - search.length;
+ r->part[2].size = r->part[0].size - size - string.length;
r->part[0].size = size;
njs_set_invalid(&r->part[2].value);
if (r->function != NULL) {
- return njs_string_replace_search_function(vm, args, r);
+ return njs_string_replace_search_function(vm, this, search,
+ r);
}
}
@@ -3446,15 +3481,15 @@ njs_string_replace_search(njs_vm_t *vm,
}
}
- njs_string_copy(&vm->retval, &args[0]);
+ njs_string_copy(&vm->retval, this);
return NJS_OK;
}
static njs_int_t
-njs_string_replace_search_function(njs_vm_t *vm, njs_value_t *args,
- njs_string_replace_t *r)
+njs_string_replace_search_function(njs_vm_t *vm, njs_value_t *this,
+ njs_value_t *search, njs_string_replace_t *r)
{
njs_int_t ret;
njs_value_t string;
@@ -3465,13 +3500,13 @@ njs_string_replace_search_function(njs_v
/* GC, args[0], args[1] */
/* Matched substring, it is the same as the args[1]. */
- arguments[1] = args[1];
+ arguments[1] = *search;
/* The offset of the matched substring. */
njs_set_number(&arguments[2], r->part[0].size);
/* The whole string being examined. */
- arguments[3] = args[0];
+ arguments[3] = *this;
ret = njs_function_apply(vm, r->function, arguments, 4, &r->retval);
diff -r bdeb67672e58 -r 50cc68d71326 src/test/njs_unit_test.c
--- a/src/test/njs_unit_test.c Wed Sep 11 19:46:30 2019 +0300
+++ b/src/test/njs_unit_test.c Mon Sep 16 17:21:36 2019 +0300
@@ -6081,6 +6081,9 @@ static njs_unit_test_t njs_test[] =
{ njs_str("'ABC'.replace(/((A)B)/g, '($1|$&|$2)')"),
njs_str("(AB|AB|A)C") },
+ { njs_str("'undefined'.replace(void 0, 'x')"),
+ njs_str("x") },
+
{ njs_str("/]/"),
njs_str("/\\]/") },
More information about the nginx-devel
mailing list