diff --git a/NEWS b/NEWS index 3ea51b89f234..61a49cc1750a 100644 --- a/NEWS +++ b/NEWS @@ -10,6 +10,9 @@ PHP NEWS warning when an IFD is not followed by a next-IFD offset). (Eyüp Can Akman) - Intl: + . Fixed NumberFormatter::parse() and NumberFormatter::parseCurrency() to + reject offset values outside the 32-bit range instead of silently + truncating them. (Weilin Du) . IntlDateFormatter::parse()/datefmt_parse() and IntlDateFormatter::localtime()/datefmt_localtime() now raise TypeError when the offset argument is not of type int. (Weilin Du) diff --git a/ext/intl/formatter/formatter_parse.cpp b/ext/intl/formatter/formatter_parse.cpp index a475960809b8..63c0fba4329f 100644 --- a/ext/intl/formatter/formatter_parse.cpp +++ b/ext/intl/formatter/formatter_parse.cpp @@ -50,7 +50,12 @@ U_CFUNC PHP_FUNCTION( numfmt_parse ) } if (zposition) { - position = (int32_t) zval_get_long(zposition); + zend_long long_position = zval_get_long(zposition); + if (long_position < INT32_MIN || long_position > INT32_MAX) { + zend_argument_value_error(hasThis() ? 3 : 4, "must be between %d and %d", INT32_MIN, INT32_MAX); + RETURN_THROWS(); + } + position = (int32_t) long_position; } /* Fetch the object. */ @@ -155,8 +160,13 @@ U_CFUNC PHP_FUNCTION( numfmt_parse_currency ) intl_stringFromChar(ustr, str, str_len, &INTL_DATA_ERROR_CODE(nfo)); INTL_METHOD_CHECK_STATUS( nfo, "String conversion to UTF-16 failed" ); - if(zposition) { - position = (int32_t) zval_get_long(zposition); + if (zposition) { + zend_long long_position = zval_get_long(zposition); + if (long_position < INT32_MIN || long_position > INT32_MAX) { + zend_argument_value_error(hasThis() ? 3 : 4, "must be between %d and %d", INT32_MIN, INT32_MAX); + RETURN_THROWS(); + } + position = (int32_t) long_position; } icu::ParsePosition pp(position); diff --git a/ext/intl/tests/formatter_parse_offset_overflow.phpt b/ext/intl/tests/formatter_parse_offset_overflow.phpt new file mode 100644 index 000000000000..9421c8897511 --- /dev/null +++ b/ext/intl/tests/formatter_parse_offset_overflow.phpt @@ -0,0 +1,46 @@ +--TEST-- +NumberFormatter parse offset overflow +--EXTENSIONS-- +intl +--SKIPIF-- + +--FILE-- +getMessage(), PHP_EOL; + } +} + +$offset = PHP_INT_MAX; +print_error(function () use ($fmt, &$offset) { + $fmt->parse('123', NumberFormatter::TYPE_DOUBLE, $offset); +}); + +$offset = PHP_INT_MAX; +print_error(function () use ($fmt, &$offset) { + numfmt_parse($fmt, '123', NumberFormatter::TYPE_DOUBLE, $offset); +}); + +$currency = ''; +$offset = PHP_INT_MAX; +print_error(function () use ($currencyFmt, &$currency, &$offset) { + $currencyFmt->parseCurrency('$123.00', $currency, $offset); +}); + +$currency = ''; +$offset = PHP_INT_MAX; +print_error(function () use ($currencyFmt, &$currency, &$offset) { + numfmt_parse_currency($currencyFmt, '$123.00', $currency, $offset); +}); +?> +--EXPECT-- +ValueError: NumberFormatter::parse(): Argument #3 ($offset) must be between -2147483648 and 2147483647 +ValueError: numfmt_parse(): Argument #4 ($offset) must be between -2147483648 and 2147483647 +ValueError: NumberFormatter::parseCurrency(): Argument #3 ($offset) must be between -2147483648 and 2147483647 +ValueError: numfmt_parse_currency(): Argument #4 ($offset) must be between -2147483648 and 2147483647