[njs] Fixed String.toLowerCase() and String.toUpperCase().
Valentin Bartenev
vbart at nginx.com
Sat Jul 27 14:35:45 UTC 2019
details: https://hg.nginx.org/njs/rev/cba3bd29f263
branches:
changeset: 1076:cba3bd29f263
user: Valentin Bartenev <vbart at nginx.com>
date: Sat Jul 27 17:03:02 2019 +0300
description:
Fixed String.toLowerCase() and String.toUpperCase().
Previously these functions didn't took into account that the size of
a string may change during case transformation resulting in buffer
underflow or overflow.
diffstat:
njs/njs_string.c | 88 +++++++++++++++++++++++++++++++++--------------
njs/test/njs_unit_test.c | 11 ++++-
2 files changed, 71 insertions(+), 28 deletions(-)
diffs (176 lines):
diff -r 0b82f1c9268c -r cba3bd29f263 njs/njs_string.c
--- a/njs/njs_string.c Sat Jul 27 16:12:26 2019 +0300
+++ b/njs/njs_string.c Sat Jul 27 17:03:02 2019 +0300
@@ -2171,24 +2171,24 @@ njs_string_prototype_to_lower_case(njs_v
nxt_uint_t nargs, njs_index_t unused)
{
size_t size, length;
- u_char *p, *start;
+ u_char *p;
+ uint32_t code;
const u_char *s, *end;
njs_string_prop_t string;
(void) njs_string_prop(&string, &args[0]);
- start = njs_string_alloc(vm, &vm->retval, string.size, string.length);
- if (nxt_slow_path(start == NULL)) {
- return NXT_ERROR;
- }
-
- p = start;
- s = string.start;
- size = string.size;
-
- if (string.length == 0 || string.length == size) {
+ if (string.length == 0 || string.length == string.size) {
/* Byte or ASCII string. */
+ p = njs_string_alloc(vm, &vm->retval, string.size, string.length);
+ if (nxt_slow_path(p == NULL)) {
+ return NXT_ERROR;
+ }
+
+ s = string.start;
+ size = string.size;
+
while (size != 0) {
*p++ = nxt_lower_case(*s++);
size--;
@@ -2196,11 +2196,29 @@ njs_string_prototype_to_lower_case(njs_v
} else {
/* UTF-8 string. */
- end = s + size;
+ s = string.start;
+ end = s + string.size;
+ length = string.length;
+
+ size = 0;
+
+ while (length != 0) {
+ code = nxt_utf8_lower_case(&s, end);
+ size += nxt_utf8_size(code);
+ length--;
+ }
+
+ p = njs_string_alloc(vm, &vm->retval, size, string.length);
+ if (nxt_slow_path(p == NULL)) {
+ return NXT_ERROR;
+ }
+
+ s = string.start;
length = string.length;
while (length != 0) {
- p = nxt_utf8_encode(p, nxt_utf8_lower_case(&s, end));
+ code = nxt_utf8_lower_case(&s, end);
+ p = nxt_utf8_encode(p, code);
length--;
}
}
@@ -2220,24 +2238,24 @@ njs_string_prototype_to_upper_case(njs_v
nxt_uint_t nargs, njs_index_t unused)
{
size_t size, length;
- u_char *p, *start;
+ u_char *p;
+ uint32_t code;
const u_char *s, *end;
njs_string_prop_t string;
(void) njs_string_prop(&string, &args[0]);
- start = njs_string_alloc(vm, &vm->retval, string.size, string.length);
- if (nxt_slow_path(start == NULL)) {
- return NXT_ERROR;
- }
-
- p = start;
- s = string.start;
- size = string.size;
-
- if (string.length == 0 || string.length == size) {
+ if (string.length == 0 || string.length == string.size) {
/* Byte or ASCII string. */
+ p = njs_string_alloc(vm, &vm->retval, string.size, string.length);
+ if (nxt_slow_path(p == NULL)) {
+ return NXT_ERROR;
+ }
+
+ s = string.start;
+ size = string.size;
+
while (size != 0) {
*p++ = nxt_upper_case(*s++);
size--;
@@ -2245,11 +2263,29 @@ njs_string_prototype_to_upper_case(njs_v
} else {
/* UTF-8 string. */
- end = s + size;
+ s = string.start;
+ end = s + string.size;
+ length = string.length;
+
+ size = 0;
+
+ while (length != 0) {
+ code = nxt_utf8_upper_case(&s, end);
+ size += nxt_utf8_size(code);
+ length--;
+ }
+
+ p = njs_string_alloc(vm, &vm->retval, size, string.length);
+ if (nxt_slow_path(p == NULL)) {
+ return NXT_ERROR;
+ }
+
+ s = string.start;
length = string.length;
while (length != 0) {
- p = nxt_utf8_encode(p, nxt_utf8_upper_case(&s, end));
+ code = nxt_utf8_upper_case(&s, end);
+ p = nxt_utf8_encode(p, code);
length--;
}
}
diff -r 0b82f1c9268c -r cba3bd29f263 njs/test/njs_unit_test.c
--- a/njs/test/njs_unit_test.c Sat Jul 27 16:12:26 2019 +0300
+++ b/njs/test/njs_unit_test.c Sat Jul 27 17:03:02 2019 +0300
@@ -5561,16 +5561,24 @@ static njs_unit_test_t njs_test[] =
{ nxt_string("'АБВ'.toLowerCase()"),
nxt_string("абв") },
+ { nxt_string("'Ȿ'.repeat(256).toLowerCase() === 'ȿ'.repeat(256)"),
+ nxt_string("true") },
+
{ nxt_string("'abc'.toUpperCase()"),
nxt_string("ABC") },
{ nxt_string("'αβγ'.toUpperCase()"),
nxt_string("ΑΒΓ") },
+ { nxt_string("'ȿ'.repeat(256).toUpperCase() === 'Ȿ'.repeat(256)"),
+ nxt_string("true") },
+
{ nxt_string("'\x00абвгдеёжз'.toUpperCase().length"),
nxt_string("10") },
-#if 0 /* FIXME */
+ { nxt_string("['ȿ', 'Ȿ', 'ȿ'.toUpperCase(), 'Ȿ'.toLowerCase()].map((v)=>v.toUTF8().length)"),
+ nxt_string("2,3,3,2") },
+
{ nxt_string("var a = [], code;"
"for (code = 0; code < 65536; code++) {"
" var s = String.fromCharCode(code);"
@@ -5588,7 +5596,6 @@ static njs_unit_test_t njs_test[] =
" a.push(code);"
"} a"),
nxt_string("304,453,456,459,498,1012,7838,8486,8490,8491") },
-#endif
{ nxt_string("'abc'.trim()"),
nxt_string("abc") },
More information about the nginx-devel
mailing list