Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions NEWS
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
16 changes: 13 additions & 3 deletions ext/intl/formatter/formatter_parse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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. */
Expand Down Expand Up @@ -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);
Expand Down
46 changes: 46 additions & 0 deletions ext/intl/tests/formatter_parse_offset_overflow.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
--TEST--
NumberFormatter parse offset overflow
--EXTENSIONS--
intl
--SKIPIF--
<?php if (PHP_INT_SIZE != 8) die("skip: 64-bit only"); ?>
--FILE--
<?php
$fmt = new NumberFormatter('en_US', NumberFormatter::DECIMAL);
$currencyFmt = new NumberFormatter('en_US', NumberFormatter::CURRENCY);

function print_error(callable $callback): void {
try {
$callback();
} catch (Throwable $e) {
echo $e::class, ': ', $e->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
Loading