]> git.kaiwu.me - njs.git/commitdiff
Fixed String.fromCharCode() for code points > 65535 and NaN.
authorValentin Bartenev <vbart@nginx.com>
Sat, 27 Jul 2019 13:12:26 +0000 (16:12 +0300)
committerValentin Bartenev <vbart@nginx.com>
Sat, 27 Jul 2019 13:12:26 +0000 (16:12 +0300)
According to the specification the code units must be truncated to uint16.

njs/njs_number.h
njs/njs_string.c
njs/test/njs_interactive_test.c
njs/test/njs_unit_test.c
nxt/nxt_utf8.h

index ddb9a15723b48993ebd51f5274ee9eaca79d42bc..bc47e49ad133a801db09757a1c231950bada3be2 100644 (file)
@@ -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)
 {
index 6425d0af8e15b0743c9ad7d2c8f7f5ba93c4c09e..55134f4c730d6feb3ca6f687906378c2f49e6459 100644 (file)
@@ -1694,9 +1694,8 @@ njs_string_from_char_code(njs_vm_t *vm, njs_value_t *args,
     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, njs_value_t *args,
     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, njs_value_t *args,
     }
 
     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;
 }
 
 
index 65653197ce9a88be94bd9f9cc95347c4266346d5..185825e4d91a3e5081674e8796d1b0bacce38719 100644 (file)
@@ -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),
index dcf35a2be1fb96c1c73cf36507a6c32176263e5c..5f774e48c3519cd7dc37db462b1da3c14199ae9a 100644 (file)
@@ -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('_').charCodeAt(0)"),
+      nxt_string("0") },
 
-    { nxt_string("String.fromCharCode(3.14)"),
-      nxt_string("RangeError") },
+    { 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,14 +5581,13 @@ 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())"
                  "        a.push(code);"
                  "} a"),
       nxt_string("304,453,456,459,498,1012,7838,8486,8490,8491") },
-#endif
 #endif
 
     { nxt_string("'abc'.trim()"),
index a3df2087e46cf0bfe75831338d74b3187158fe4e..e2d78aa916577b72331c5c4182d74e2f1260bf95 100644 (file)
@@ -118,4 +118,8 @@ nxt_utf8_copy(u_char *dst, const u_char **src, const u_char *end)
     ((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_ */