[njs] Fixed String.fromCharCode() for code points > 65535 and NaN.

Valentin Bartenev vbart at nginx.com
Sat Jul 27 13:13:01 UTC 2019


details:   https://hg.nginx.org/njs/rev/0b82f1c9268c
branches:  
changeset: 1075:0b82f1c9268c
user:      Valentin Bartenev <vbart at nginx.com>
date:      Sat Jul 27 16:12:26 2019 +0300
description:
Fixed String.fromCharCode() for code points > 65535 and NaN.

According to the specification the code units must be truncated to uint16.

diffstat:

 njs/njs_number.h                |   7 +++++++
 njs/njs_string.c                |  26 +++++---------------------
 njs/test/njs_interactive_test.c |   4 ++--
 njs/test/njs_unit_test.c        |  28 +++++++++++++++-------------
 nxt/nxt_utf8.h                  |   4 ++++
 5 files changed, 33 insertions(+), 36 deletions(-)

diffs (172 lines):

diff -r ab9fc6079788 -r 0b82f1c9268c njs/njs_number.h
--- a/njs/njs_number.h	Fri Jul 26 07:24:36 2019 +0300
+++ b/njs/njs_number.h	Sat Jul 27 16:12:26 2019 +0300
@@ -86,6 +86,13 @@ njs_number_to_uint32(double num)
 }
 
 
+nxt_inline uint16_t
+njs_number_to_uint16(double num)
+{
+    return (uint16_t) njs_number_to_int64(num);
+}
+
+
 nxt_inline uint32_t
 njs_number_to_length(double num)
 {
diff -r ab9fc6079788 -r 0b82f1c9268c njs/njs_string.c
--- a/njs/njs_string.c	Fri Jul 26 07:24:36 2019 +0300
+++ b/njs/njs_string.c	Sat Jul 27 16:12:26 2019 +0300
@@ -1694,9 +1694,8 @@ njs_string_from_char_code(njs_vm_t *vm, 
     nxt_uint_t nargs, njs_index_t unused)
 {
     u_char      *p;
-    double      num;
     size_t      size;
-    int32_t     code;
+    uint16_t    code;
     njs_ret_t   ret;
     nxt_uint_t  i;
 
@@ -1712,18 +1711,8 @@ njs_string_from_char_code(njs_vm_t *vm, 
     size = 0;
 
     for (i = 1; i < nargs; i++) {
-        num = njs_number(&args[i]);
-        if (isnan(num)) {
-            goto range_error;
-        }
-
-        code = num;
-
-        if (code != num || code < 0 || code >= 0x110000) {
-            goto range_error;
-        }
-
-        size += nxt_utf8_size(code);
+        code = njs_number_to_uint16(njs_number(&args[i]));
+        size += nxt_utf8_size_uint16(code);
     }
 
     p = njs_string_alloc(vm, &vm->retval, size, nargs - 1);
@@ -1732,16 +1721,11 @@ njs_string_from_char_code(njs_vm_t *vm, 
     }
 
     for (i = 1; i < nargs; i++) {
-        p = nxt_utf8_encode(p, njs_number(&args[i]));
+        code = njs_number_to_uint16(njs_number(&args[i]));
+        p = nxt_utf8_encode(p, code);
     }
 
     return NXT_OK;
-
-range_error:
-
-    njs_range_error(vm, NULL);
-
-    return NXT_ERROR;
 }
 
 
diff -r ab9fc6079788 -r 0b82f1c9268c njs/test/njs_interactive_test.c
--- a/njs/test/njs_interactive_test.c	Fri Jul 26 07:24:36 2019 +0300
+++ b/njs/test/njs_interactive_test.c	Sat Jul 27 16:12:26 2019 +0300
@@ -149,9 +149,9 @@ static njs_interactive_test_t  njs_test[
                  "    at f (:1)\n"
                  "    at main (native)\n") },
 
-    { nxt_string("String.fromCharCode(3.14)" ENTER),
+    { nxt_string("''.repeat(-1)" ENTER),
       nxt_string("RangeError\n"
-                 "    at String.fromCharCode (native)\n"
+                 "    at String.prototype.repeat (native)\n"
                  "    at main (native)\n") },
 
     { nxt_string("Math.log({}.a.a)" ENTER),
diff -r ab9fc6079788 -r 0b82f1c9268c njs/test/njs_unit_test.c
--- a/njs/test/njs_unit_test.c	Fri Jul 26 07:24:36 2019 +0300
+++ b/njs/test/njs_unit_test.c	Sat Jul 27 16:12:26 2019 +0300
@@ -5345,11 +5345,17 @@ static njs_unit_test_t  njs_test[] =
                  "         .length; a"),
       nxt_string("5") },
 
-    { nxt_string("String.fromCharCode('_')"),
-      nxt_string("RangeError") },
-
-    { nxt_string("String.fromCharCode(3.14)"),
-      nxt_string("RangeError") },
+    { nxt_string("String.fromCharCode('_').charCodeAt(0)"),
+      nxt_string("0") },
+
+    { nxt_string("String.fromCharCode(65.14)"),
+      nxt_string("A") },
+
+    { nxt_string("String.fromCharCode(65.14 + 65536)"),
+      nxt_string("A") },
+
+    { nxt_string("String.fromCharCode(2**53 + 10)"),
+      nxt_string("\n") },
 
     { nxt_string("String.fromCharCode(65, 90)"),
       nxt_string("AZ") },
@@ -5357,17 +5363,15 @@ static njs_unit_test_t  njs_test[] =
     { nxt_string("String.fromCharCode(945, 946, 947)"),
       nxt_string("αβγ") },
 
-#if (!NXT_HAVE_MEMORY_SANITIZER) /* very long test under MSAN */
     { nxt_string("(function() {"
                  "    var n;"
-                 "    for (n = 0; n <= 1114111; n++) {"
+                 "    for (n = 0; n <= 65536; n++) {"
                  "        if (String.fromCharCode(n).charCodeAt(0) !== n)"
                  "            return n;"
                  "    }"
                  "    return -1"
                  "})()"),
-      nxt_string("-1") },
-#endif
+      nxt_string("65536") },
 
     { nxt_string("var a = 'abcdef'; function f(a) {"
                  "return a.slice(a.indexOf('cd')) } f(a)"),
@@ -5567,9 +5571,8 @@ static njs_unit_test_t  njs_test[] =
       nxt_string("10") },
 
 #if 0 /* FIXME */
-#if (!NXT_HAVE_MEMORY_SANITIZER) /* very long test under MSAN */
     { nxt_string("var a = [], code;"
-                 "for (code = 0; code <= 1114111; code++) {"
+                 "for (code = 0; code < 65536; code++) {"
                  "    var s = String.fromCharCode(code);"
                  "    var n = s.toUpperCase();"
                  "    if (s != n && s != n.toLowerCase())"
@@ -5578,7 +5581,7 @@ static njs_unit_test_t  njs_test[] =
       nxt_string("181,305,383,453,456,459,498,837,962,976,977,981,982,1008,1009,1013,7296,7297,7298,7299,7300,7301,7302,7303,7304,7835,8126") },
 
     { nxt_string("var a = [], code;"
-                 "for (code = 0; code <= 1114111; code++) {"
+                 "for (code = 0; code < 65536; code++) {"
                  "    var s = String.fromCharCode(code);"
                  "    var n = s.toLowerCase();"
                  "    if (s != n && s != n.toUpperCase())"
@@ -5586,7 +5589,6 @@ static njs_unit_test_t  njs_test[] =
                  "} a"),
       nxt_string("304,453,456,459,498,1012,7838,8486,8490,8491") },
 #endif
-#endif
 
     { nxt_string("'abc'.trim()"),
       nxt_string("abc") },
diff -r ab9fc6079788 -r 0b82f1c9268c nxt/nxt_utf8.h
--- a/nxt/nxt_utf8.h	Fri Jul 26 07:24:36 2019 +0300
+++ b/nxt/nxt_utf8.h	Sat Jul 27 16:12:26 2019 +0300
@@ -118,4 +118,8 @@ nxt_utf8_copy(u_char *dst, const u_char 
     ((u < 0x80) ? 1 : ((u < 0x0800) ? 2 : ((u < 0x10000) ? 3 : 4)))
 
 
+#define nxt_utf8_size_uint16(u)                                               \
+    ((u < 0x80) ? 1 : ((u < 0x0800) ? 2 : 3))
+
+
 #endif /* _NXT_UTF8_H_INCLUDED_ */


More information about the nginx-devel mailing list