From: Valentin Bartenev Date: Sat, 27 Jul 2019 14:03:02 +0000 (+0300) Subject: Fixed String.toLowerCase() and String.toUpperCase(). X-Git-Tag: 0.3.4~51 X-Git-Url: http://www.kaiwu.me/postgresql/commit/?a=commitdiff_plain;h=820d0da0d9e6f5acbf0bb9dd1739a6ff2ba332af;p=njs.git 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. --- diff --git a/njs/njs_string.c b/njs/njs_string.c index 55134f4c..50fc497b 100644 --- a/njs/njs_string.c +++ b/njs/njs_string.c @@ -2171,23 +2171,23 @@ njs_string_prototype_to_lower_case(njs_vm_t *vm, njs_value_t *args, 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; - } + if (string.length == 0 || string.length == string.size) { + /* Byte or ASCII string. */ - p = start; - s = string.start; - size = string.size; + p = njs_string_alloc(vm, &vm->retval, string.size, string.length); + if (nxt_slow_path(p == NULL)) { + return NXT_ERROR; + } - if (string.length == 0 || string.length == size) { - /* Byte or ASCII string. */ + s = string.start; + size = string.size; while (size != 0) { *p++ = nxt_lower_case(*s++); @@ -2196,11 +2196,29 @@ njs_string_prototype_to_lower_case(njs_vm_t *vm, njs_value_t *args, } 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,23 +2238,23 @@ njs_string_prototype_to_upper_case(njs_vm_t *vm, njs_value_t *args, 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; - } + if (string.length == 0 || string.length == string.size) { + /* Byte or ASCII string. */ - p = start; - s = string.start; - size = string.size; + p = njs_string_alloc(vm, &vm->retval, string.size, string.length); + if (nxt_slow_path(p == NULL)) { + return NXT_ERROR; + } - if (string.length == 0 || string.length == size) { - /* Byte or ASCII string. */ + s = string.start; + size = string.size; while (size != 0) { *p++ = nxt_upper_case(*s++); @@ -2245,11 +2263,29 @@ njs_string_prototype_to_upper_case(njs_vm_t *vm, njs_value_t *args, } 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 --git a/njs/test/njs_unit_test.c b/njs/test/njs_unit_test.c index 5f774e48..6bab1984 100644 --- a/njs/test/njs_unit_test.c +++ b/njs/test/njs_unit_test.c @@ -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") },