From bc4e62b1db80f521785c80f6aa6e5877ec8e6fd7 Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Sun, 2 Feb 2020 12:26:03 +0100 Subject: [PATCH 1/2] Fix #79212: NumberFormatter::format() may detect wrong type We have to convert to number *before* detecting the type, to cater to internal objects implementing `cast_object`. We also get rid of the fallback behavior of using `FORMAT_TYPE_INT32`, because that can no longer happen; after `convert_to_numer()` the type is either `IS_LONG` or `IS_DOUBLE`. --- ext/intl/formatter/formatter_format.c | 26 +++++++++++--------------- ext/intl/tests/bug79212.phpt | 14 ++++++++++++++ 2 files changed, 25 insertions(+), 15 deletions(-) create mode 100644 ext/intl/tests/bug79212.phpt diff --git a/ext/intl/formatter/formatter_format.c b/ext/intl/formatter/formatter_format.c index f3253dcdb2a63..47ffbdf488eb7 100644 --- a/ext/intl/formatter/formatter_format.c +++ b/ext/intl/formatter/formatter_format.c @@ -53,25 +53,21 @@ PHP_FUNCTION( numfmt_format ) /* Fetch the object. */ FORMATTER_METHOD_FETCH_OBJECT; - if(type == FORMAT_TYPE_DEFAULT) { - if(Z_TYPE_P(number) == IS_STRING) { - convert_scalar_to_number_ex(number); - } + convert_scalar_to_number_ex(number); - if(Z_TYPE_P(number) == IS_LONG) { - /* take INT32 on 32-bit, int64 on 64-bit */ - type = (sizeof(zend_long) == 8)?FORMAT_TYPE_INT64:FORMAT_TYPE_INT32; - } else if(Z_TYPE_P(number) == IS_DOUBLE) { - type = FORMAT_TYPE_DOUBLE; - } else { - type = FORMAT_TYPE_INT32; + if(type == FORMAT_TYPE_DEFAULT) { + switch(Z_TYPE_P(number)) { + case IS_LONG: + /* take INT32 on 32-bit, int64 on 64-bit */ + type = (sizeof(zend_long) == 8)?FORMAT_TYPE_INT64:FORMAT_TYPE_INT32; + break; + case IS_DOUBLE: + type = FORMAT_TYPE_DOUBLE; + break; + EMPTY_SWITCH_DEFAULT_CASE(); } } - if(Z_TYPE_P(number) != IS_DOUBLE && Z_TYPE_P(number) != IS_LONG) { - convert_scalar_to_number(number ); - } - switch(type) { case FORMAT_TYPE_INT32: convert_to_long_ex(number); diff --git a/ext/intl/tests/bug79212.phpt b/ext/intl/tests/bug79212.phpt new file mode 100644 index 0000000000000..295b20c168229 --- /dev/null +++ b/ext/intl/tests/bug79212.phpt @@ -0,0 +1,14 @@ +--TEST-- +Bug #79212 (NumberFormatter::format() may detect wrong type) +--SKIPIF-- + +--FILE-- +format(gmp_init('823749273428379492374'))); +?> +--EXPECT-- +string(21) "823749273428379400000" From 6301f40246accb58ffdbfc496d3f47caba354fc7 Mon Sep 17 00:00:00 2001 From: "Christoph M. Becker" Date: Sun, 2 Feb 2020 13:38:34 +0100 Subject: [PATCH 2/2] Cater to number being an array Like the name implies, `convert_scalar_to_number_ex()` does not convert array. We enforce array to integer conversion right away, to avoid triggering the type confusion when `::TYPE_INT64` is passed as `$type`. --- ext/intl/formatter/formatter_format.c | 6 +++++- ext/intl/tests/bug79212.phpt | 4 ++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/ext/intl/formatter/formatter_format.c b/ext/intl/formatter/formatter_format.c index 47ffbdf488eb7..9736674d77ea0 100644 --- a/ext/intl/formatter/formatter_format.c +++ b/ext/intl/formatter/formatter_format.c @@ -53,7 +53,11 @@ PHP_FUNCTION( numfmt_format ) /* Fetch the object. */ FORMATTER_METHOD_FETCH_OBJECT; - convert_scalar_to_number_ex(number); + if(Z_TYPE_P(number) != IS_ARRAY) { + convert_scalar_to_number_ex(number); + } else { + convert_to_long(number); + } if(type == FORMAT_TYPE_DEFAULT) { switch(Z_TYPE_P(number)) { diff --git a/ext/intl/tests/bug79212.phpt b/ext/intl/tests/bug79212.phpt index 295b20c168229..0f7897acc4a5d 100644 --- a/ext/intl/tests/bug79212.phpt +++ b/ext/intl/tests/bug79212.phpt @@ -9,6 +9,10 @@ if (!extension_loaded('gmp')) die('skip gmp extension not available'); format(gmp_init('823749273428379492374'))); + +$fmt = new NumberFormatter('en_US', NumberFormatter::PATTERN_DECIMAL); +var_dump($fmt->format([1], NumberFormatter::TYPE_INT64)); ?> --EXPECT-- string(21) "823749273428379400000" +string(1) "1"