From b140158104064ef082ddb58052f8c7c7cee9675c Mon Sep 17 00:00:00 2001 From: Zoltan Herczeg Date: Thu, 9 Mar 2017 15:03:46 +0100 Subject: [PATCH] Fix various number parsing issues. (#1648) For example Number(".") and Number("e5") should be NaN not zero. Parsing Number("e") caused buffer overflow as well. Infinity parsing is a bit faster now. Fixes #1636. JerryScript-DCO-1.0-Signed-off-by: Zoltan Herczeg zherczeg.u-szeged@partner.samsung.com --- .../ecma/base/ecma-helpers-conversion.c | 34 +++++++++++-------- tests/jerry/regression-test-issue-1636.js | 24 +++++++++++++ 2 files changed, 43 insertions(+), 15 deletions(-) create mode 100644 tests/jerry/regression-test-issue-1636.js diff --git a/jerry-core/ecma/base/ecma-helpers-conversion.c b/jerry-core/ecma/base/ecma-helpers-conversion.c index b50ed04dc..234528dbd 100644 --- a/jerry-core/ecma/base/ecma-helpers-conversion.c +++ b/jerry-core/ecma/base/ecma-helpers-conversion.c @@ -448,24 +448,17 @@ ecma_utf8_string_to_number (const lit_utf8_byte_t *str_p, /**< utf-8 string */ /* Checking if significant part of parse string is equal to "Infinity" */ const lit_utf8_byte_t *infinity_zt_str_p = lit_get_magic_string_utf8 (LIT_MAGIC_STRING_INFINITY_UL); - for (const lit_utf8_byte_t *iter_p = begin_p, *iter_infinity_p = infinity_zt_str_p; - ; - iter_infinity_p++, iter_p++) - { - if (*iter_p != *iter_infinity_p) - { - break; - } + JERRY_ASSERT (strlen ((const char *) infinity_zt_str_p) == 8); - if (iter_p == end_p) - { - return ecma_number_make_infinity (sign); - } + if ((end_p - begin_p) == (8 - 1) && memcmp (infinity_zt_str_p, begin_p, 8) == 0) + { + return ecma_number_make_infinity (sign); } uint64_t fraction_uint64 = 0; uint32_t digits = 0; int32_t e = 0; + bool digit_seen = false; /* Parsing digits before dot (or before end of digits part if there is no dot in number) */ while (begin_p <= end_p) @@ -475,6 +468,7 @@ ecma_utf8_string_to_number (const lit_utf8_byte_t *str_p, /**< utf-8 string */ if (*begin_p >= LIT_CHAR_0 && *begin_p <= LIT_CHAR_9) { + digit_seen = true; digit_value = (*begin_p - LIT_CHAR_0); } else @@ -489,9 +483,8 @@ ecma_utf8_string_to_number (const lit_utf8_byte_t *str_p, /**< utf-8 string */ fraction_uint64 = fraction_uint64 * 10 + (uint32_t) digit_value; digits++; } - else if (e <= 100000) /* Some limit to not overflow exponent value - (so big exponent anyway will make number - rounded to infinity) */ + else if (e <= 100000) /* Limit the exponent, since large + * exponent is rounded to infinity anyway. */ { e++; } @@ -505,6 +498,11 @@ ecma_utf8_string_to_number (const lit_utf8_byte_t *str_p, /**< utf-8 string */ { begin_p++; + if (!digit_seen && begin_p > end_p) + { + return ecma_number_make_nan (); + } + /* Parsing number's part that is placed after dot */ while (begin_p <= end_p) { @@ -513,6 +511,7 @@ ecma_utf8_string_to_number (const lit_utf8_byte_t *str_p, /**< utf-8 string */ if (*begin_p >= LIT_CHAR_0 && *begin_p <= LIT_CHAR_9) { + digit_seen = true; digit_value = (*begin_p - LIT_CHAR_0); } else @@ -545,6 +544,11 @@ ecma_utf8_string_to_number (const lit_utf8_byte_t *str_p, /**< utf-8 string */ { begin_p++; + if (!digit_seen || begin_p > end_p) + { + return ecma_number_make_nan (); + } + if (*begin_p == LIT_CHAR_PLUS) { begin_p++; diff --git a/tests/jerry/regression-test-issue-1636.js b/tests/jerry/regression-test-issue-1636.js new file mode 100644 index 000000000..d734674ad --- /dev/null +++ b/tests/jerry/regression-test-issue-1636.js @@ -0,0 +1,24 @@ +// Copyright JS Foundation and other contributors, http://js.foundation +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +assert(Number("Infinity") == Infinity); +assert(isNaN(Number("infinity"))); +assert(isNaN(Number("InfinitY"))); +assert(isNaN(Number("e"))); +assert(isNaN(Number("e3"))); +assert(Number("1e2") == 100); +assert(isNaN(Number("."))); +assert(isNaN(Number(".e2"))); +assert(Number("0.") == 0); +assert(Number(".0") == 0);