Skip to content

Commit c293549

Browse files
committed
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_scalar_to_number_ex` the type is either `IS_LONG` or `IS_DOUBLE`. We cater explicitly to the `IS_ARRAY` case what also avoids triggering a type confusion when `::TYPE_INT64` is passed as `$type`.
1 parent ef1e489 commit c293549

File tree

3 files changed

+36
-15
lines changed

3 files changed

+36
-15
lines changed

NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,9 @@ PHP NEWS
1414
. Fixed bug #79078 (Hypothetical use-after-free in curl_multi_add_handle()).
1515
(cmb)
1616

17+
-Intl:
18+
. Fixed bug #79212 (NumberFormatter::format() may detect wrong type). (cmb)
19+
1720
- MBString:
1821
. Fixed bug #79154 (mb_convert_encoding() can modify $from_encoding). (cmb)
1922

ext/intl/formatter/formatter_format.c

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -53,23 +53,23 @@ PHP_FUNCTION( numfmt_format )
5353
/* Fetch the object. */
5454
FORMATTER_METHOD_FETCH_OBJECT;
5555

56-
if(type == FORMAT_TYPE_DEFAULT) {
57-
if(Z_TYPE_P(number) == IS_STRING) {
58-
convert_scalar_to_number_ex(number);
59-
}
60-
61-
if(Z_TYPE_P(number) == IS_LONG) {
62-
/* take INT32 on 32-bit, int64 on 64-bit */
63-
type = (sizeof(zend_long) == 8)?FORMAT_TYPE_INT64:FORMAT_TYPE_INT32;
64-
} else if(Z_TYPE_P(number) == IS_DOUBLE) {
65-
type = FORMAT_TYPE_DOUBLE;
66-
} else {
67-
type = FORMAT_TYPE_INT32;
68-
}
56+
if(Z_TYPE_P(number) != IS_ARRAY) {
57+
convert_scalar_to_number_ex(number);
58+
} else {
59+
convert_to_long(number);
6960
}
7061

71-
if(Z_TYPE_P(number) != IS_DOUBLE && Z_TYPE_P(number) != IS_LONG) {
72-
convert_scalar_to_number(number );
62+
if(type == FORMAT_TYPE_DEFAULT) {
63+
switch(Z_TYPE_P(number)) {
64+
case IS_LONG:
65+
/* take INT32 on 32-bit, int64 on 64-bit */
66+
type = (sizeof(zend_long) == 8)?FORMAT_TYPE_INT64:FORMAT_TYPE_INT32;
67+
break;
68+
case IS_DOUBLE:
69+
type = FORMAT_TYPE_DOUBLE;
70+
break;
71+
EMPTY_SWITCH_DEFAULT_CASE();
72+
}
7373
}
7474

7575
switch(type) {

ext/intl/tests/bug79212.phpt

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
--TEST--
2+
Bug #79212 (NumberFormatter::format() may detect wrong type)
3+
--SKIPIF--
4+
<?php
5+
if (!extension_loaded('intl')) die('skip intl extension not available');
6+
if (!extension_loaded('gmp')) die('skip gmp extension not available');
7+
?>
8+
--FILE--
9+
<?php
10+
$fmt = new NumberFormatter('en_US', NumberFormatter::PATTERN_DECIMAL);
11+
var_dump($fmt->format(gmp_init('823749273428379492374')));
12+
13+
$fmt = new NumberFormatter('en_US', NumberFormatter::PATTERN_DECIMAL);
14+
var_dump($fmt->format([1], NumberFormatter::TYPE_INT64));
15+
?>
16+
--EXPECT--
17+
string(21) "823749273428379400000"
18+
string(1) "1"

0 commit comments

Comments
 (0)