From 1301be7b04f252894875b1925467428a1ef0c488 Mon Sep 17 00:00:00 2001 From: Sjoerd Langkemper Date: Fri, 19 Jun 2026 11:46:59 +0000 Subject: [PATCH 1/2] Warn when number base conversion loses precision _php_math_basetozval is used for base_convert, bindec, hexdec and octdec. It uses an integer or double for the internal representation of the number. When the input number is too large to fit in there, it loses precision. This commit emits a notice when this happens. Discussion thread: https://news-web.php.net/php.internals/131364 --- ext/standard/math.c | 1 + .../tests/math/base_convert_basic.phpt | 38 ++++++++++++++++++- .../tests/math/bindec_basiclong_64bit.phpt | 8 +++- .../tests/math/hexdec_basiclong_64bit.phpt | 8 +++- .../tests/math/octdec_basiclong_64bit.phpt | 8 +++- 5 files changed, 59 insertions(+), 4 deletions(-) diff --git a/ext/standard/math.c b/ext/standard/math.c index 1898d210ce65..a85617eae334 100644 --- a/ext/standard/math.c +++ b/ext/standard/math.c @@ -898,6 +898,7 @@ PHPAPI void _php_math_basetozval(zend_string *str, int base, zval *ret) num = num * base + c; break; } else { + zend_error(E_NOTICE, "Input number exceeds maximum integer value, precision has been lost in conversion"); fnum = (double)num; mode = 1; } diff --git a/ext/standard/tests/math/base_convert_basic.phpt b/ext/standard/tests/math/base_convert_basic.phpt index bdef339f3b37..c65445102fb1 100644 --- a/ext/standard/tests/math/base_convert_basic.phpt +++ b/ext/standard/tests/math/base_convert_basic.phpt @@ -14,7 +14,8 @@ $values = array(10, "27", "39", "5F", - "3XYZ" + "3XYZ", + "1111111111111111" ); for ($f= 0; $f < count($frombase); $f++) { @@ -57,6 +58,7 @@ Deprecated: Invalid characters passed for attempted conversion, these have been Deprecated: Invalid characters passed for attempted conversion, these have been ignored in %s on line %d .........value= 3XYZ res = 0 +.........value= 1111111111111111 res = 1111111111111111 ......to base is 8 .........value= 10 res = 2 @@ -84,6 +86,7 @@ Deprecated: Invalid characters passed for attempted conversion, these have been Deprecated: Invalid characters passed for attempted conversion, these have been ignored in %s on line %d .........value= 3XYZ res = 0 +.........value= 1111111111111111 res = 177777 ......to base is 10 .........value= 10 res = 2 @@ -111,6 +114,7 @@ Deprecated: Invalid characters passed for attempted conversion, these have been Deprecated: Invalid characters passed for attempted conversion, these have been ignored in %s on line %d .........value= 3XYZ res = 0 +.........value= 1111111111111111 res = 65535 ......to base is 16 .........value= 10 res = 2 @@ -138,6 +142,7 @@ Deprecated: Invalid characters passed for attempted conversion, these have been Deprecated: Invalid characters passed for attempted conversion, these have been ignored in %s on line %d .........value= 3XYZ res = 0 +.........value= 1111111111111111 res = ffff ......to base is 36 .........value= 10 res = 2 @@ -165,6 +170,7 @@ Deprecated: Invalid characters passed for attempted conversion, these have been Deprecated: Invalid characters passed for attempted conversion, these have been ignored in %s on line %d .........value= 3XYZ res = 0 +.........value= 1111111111111111 res = 1ekf ...from base is 8 ......to base is 2 @@ -188,6 +194,7 @@ Deprecated: Invalid characters passed for attempted conversion, these have been Deprecated: Invalid characters passed for attempted conversion, these have been ignored in %s on line %d .........value= 3XYZ res = 11 +.........value= 1111111111111111 res = 1001001001001001001001001001001001001001001001 ......to base is 8 .........value= 10 res = 10 .........value= 27 res = 27 @@ -209,6 +216,7 @@ Deprecated: Invalid characters passed for attempted conversion, these have been Deprecated: Invalid characters passed for attempted conversion, these have been ignored in %s on line %d .........value= 3XYZ res = 3 +.........value= 1111111111111111 res = 1111111111111111 ......to base is 10 .........value= 10 res = 8 .........value= 27 res = 23 @@ -230,6 +238,7 @@ Deprecated: Invalid characters passed for attempted conversion, these have been Deprecated: Invalid characters passed for attempted conversion, these have been ignored in %s on line %d .........value= 3XYZ res = 3 +.........value= 1111111111111111 res = 40210710958665 ......to base is 16 .........value= 10 res = 8 .........value= 27 res = 17 @@ -251,6 +260,7 @@ Deprecated: Invalid characters passed for attempted conversion, these have been Deprecated: Invalid characters passed for attempted conversion, these have been ignored in %s on line %d .........value= 3XYZ res = 3 +.........value= 1111111111111111 res = 249249249249 ......to base is 36 .........value= 10 res = 8 .........value= 27 res = n @@ -272,6 +282,7 @@ Deprecated: Invalid characters passed for attempted conversion, these have been Deprecated: Invalid characters passed for attempted conversion, these have been ignored in %s on line %d .........value= 3XYZ res = 3 +.........value= 1111111111111111 res = e94jn3f49 ...from base is 10 ......to base is 2 @@ -289,6 +300,7 @@ Deprecated: Invalid characters passed for attempted conversion, these have been Deprecated: Invalid characters passed for attempted conversion, these have been ignored in %s on line %d .........value= 3XYZ res = 11 +.........value= 1111111111111111 res = 11111100101000110010110111000101010111000111000111 ......to base is 8 .........value= 10 res = 12 .........value= 27 res = 33 @@ -304,6 +316,7 @@ Deprecated: Invalid characters passed for attempted conversion, these have been Deprecated: Invalid characters passed for attempted conversion, these have been ignored in %s on line %d .........value= 3XYZ res = 3 +.........value= 1111111111111111 res = 37450626705270707 ......to base is 10 .........value= 10 res = 10 .........value= 27 res = 27 @@ -319,6 +332,7 @@ Deprecated: Invalid characters passed for attempted conversion, these have been Deprecated: Invalid characters passed for attempted conversion, these have been ignored in %s on line %d .........value= 3XYZ res = 3 +.........value= 1111111111111111 res = 1111111111111111 ......to base is 16 .........value= 10 res = a .........value= 27 res = 1b @@ -334,6 +348,7 @@ Deprecated: Invalid characters passed for attempted conversion, these have been Deprecated: Invalid characters passed for attempted conversion, these have been ignored in %s on line %d .........value= 3XYZ res = 3 +.........value= 1111111111111111 res = 3f28cb71571c7 ......to base is 36 .........value= 10 res = a .........value= 27 res = r @@ -349,6 +364,7 @@ Deprecated: Invalid characters passed for attempted conversion, these have been Deprecated: Invalid characters passed for attempted conversion, these have been ignored in %s on line %d .........value= 3XYZ res = 3 +.........value= 1111111111111111 res = axutebils7 ...from base is 16 ......to base is 2 @@ -364,6 +380,7 @@ Deprecated: Invalid characters passed for attempted conversion, these have been Deprecated: Invalid characters passed for attempted conversion, these have been ignored in %s on line %d .........value= 3XYZ res = 11 +.........value= 1111111111111111 res = 1000100010001000100010001000100010001000100010001000100010001 ......to base is 8 .........value= 10 res = 20 .........value= 27 res = 47 @@ -377,6 +394,7 @@ Deprecated: Invalid characters passed for attempted conversion, these have been Deprecated: Invalid characters passed for attempted conversion, these have been ignored in %s on line %d .........value= 3XYZ res = 3 +.........value= 1111111111111111 res = 104210421042104210421 ......to base is 10 .........value= 10 res = 16 .........value= 27 res = 39 @@ -390,6 +408,7 @@ Deprecated: Invalid characters passed for attempted conversion, these have been Deprecated: Invalid characters passed for attempted conversion, these have been ignored in %s on line %d .........value= 3XYZ res = 3 +.........value= 1111111111111111 res = 1229782938247303441 ......to base is 16 .........value= 10 res = 10 .........value= 27 res = 27 @@ -403,6 +422,7 @@ Deprecated: Invalid characters passed for attempted conversion, these have been Deprecated: Invalid characters passed for attempted conversion, these have been ignored in %s on line %d .........value= 3XYZ res = 3 +.........value= 1111111111111111 res = 1111111111111111 ......to base is 36 .........value= 10 res = g .........value= 27 res = 13 @@ -416,6 +436,7 @@ Deprecated: Invalid characters passed for attempted conversion, these have been Deprecated: Invalid characters passed for attempted conversion, these have been ignored in %s on line %d .........value= 3XYZ res = 3 +.........value= 1111111111111111 res = 9ccxo2jlx3ip ...from base is 36 ......to base is 2 @@ -429,6 +450,9 @@ Deprecated: Invalid characters passed for attempted conversion, these have been .........value= 39 res = 1110101 .........value= 5F res = 11000011 .........value= 3XYZ res = 101100111010111011 + +Notice: Input number exceeds maximum integer value, precision has been lost in conversion in %s on line %d +.........value= 1111111111111111 res = 1101101010010011001001100101101101110100000000000000000000000000 ......to base is 8 .........value= 10 res = 44 .........value= 27 res = 117 @@ -440,6 +464,9 @@ Deprecated: Invalid characters passed for attempted conversion, these have been .........value= 39 res = 165 .........value= 5F res = 303 .........value= 3XYZ res = 547273 + +Notice: Input number exceeds maximum integer value, precision has been lost in conversion in %s on line %d +.........value= 1111111111111111 res = 60115552231145556400000000 ......to base is 10 .........value= 10 res = 36 .........value= 27 res = 79 @@ -451,6 +478,9 @@ Deprecated: Invalid characters passed for attempted conversion, these have been .........value= 39 res = 117 .........value= 5F res = 195 .........value= 3XYZ res = 183995 + +Notice: Input number exceeds maximum integer value, precision has been lost in conversion in %s on line %d +.........value= 1111111111111111 res = 227390317427040000046866 ......to base is 16 .........value= 10 res = 24 .........value= 27 res = 4f @@ -462,6 +492,9 @@ Deprecated: Invalid characters passed for attempted conversion, these have been .........value= 39 res = 75 .........value= 5F res = c3 .........value= 3XYZ res = 2cebb + +Notice: Input number exceeds maximum integer value, precision has been lost in conversion in %s on line %d +.........value= 1111111111111111 res = 3026da93265b74000000 ......to base is 36 .........value= 10 res = 10 .........value= 27 res = 27 @@ -473,3 +506,6 @@ Deprecated: Invalid characters passed for attempted conversion, these have been .........value= 39 res = 39 .........value= 5F res = 5f .........value= 3XYZ res = 3xyz + +Notice: Input number exceeds maximum integer value, precision has been lost in conversion in %s on line %d +.........value= 1111111111111111 res = 11111111111wsws0 diff --git a/ext/standard/tests/math/bindec_basiclong_64bit.phpt b/ext/standard/tests/math/bindec_basiclong_64bit.phpt index b4f28a091dbb..1c2ca4723a69 100644 --- a/ext/standard/tests/math/bindec_basiclong_64bit.phpt +++ b/ext/standard/tests/math/bindec_basiclong_64bit.phpt @@ -30,18 +30,24 @@ foreach ($binLongStrs as $strVal) { } ?> ---EXPECT-- +--EXPECTF-- --- testing: 0111111111111111111111111111111111111111111111111111111111111111 --- int(9223372036854775807) --- testing: 1111111111111111111111111111111111111111111111111111111111111111 --- + +Notice: Input number exceeds maximum integer value, precision has been lost in conversion in %s on line %d float(1.8446744073709552E+19) --- testing: 01111111111111111111111111111111 --- int(2147483647) --- testing: 11111111111111111111111111111111 --- int(4294967295) --- testing: 01111111111111111111111111111111111111111111111111111111111111111 --- + +Notice: Input number exceeds maximum integer value, precision has been lost in conversion in %s on line %d float(1.8446744073709552E+19) --- testing: 11111111111111111111111111111111111111111111111111111111111111111 --- + +Notice: Input number exceeds maximum integer value, precision has been lost in conversion in %s on line %d float(3.6893488147419103E+19) --- testing: 011111111111111111111111111111111 --- int(4294967295) diff --git a/ext/standard/tests/math/hexdec_basiclong_64bit.phpt b/ext/standard/tests/math/hexdec_basiclong_64bit.phpt index af0b448cac01..71e5ad1e97fc 100644 --- a/ext/standard/tests/math/hexdec_basiclong_64bit.phpt +++ b/ext/standard/tests/math/hexdec_basiclong_64bit.phpt @@ -30,18 +30,24 @@ foreach ($hexLongStrs as $strVal) { } ?> ---EXPECT-- +--EXPECTF-- --- testing: 7fffffffffffffff --- int(9223372036854775807) --- testing: ffffffffffffffff --- + +Notice: Input number exceeds maximum integer value, precision has been lost in conversion in %s on line %d float(1.8446744073709552E+19) --- testing: 7fffffff --- int(2147483647) --- testing: ffffffff --- int(4294967295) --- testing: 7ffffffffffffffff --- + +Notice: Input number exceeds maximum integer value, precision has been lost in conversion in %s on line %d float(1.4757395258967641E+20) --- testing: ffffffffffffffffff --- + +Notice: Input number exceeds maximum integer value, precision has been lost in conversion in %s on line %d float(4.722366482869645E+21) --- testing: 7ffffffff --- int(34359738367) diff --git a/ext/standard/tests/math/octdec_basiclong_64bit.phpt b/ext/standard/tests/math/octdec_basiclong_64bit.phpt index 06e0dd3929d2..2ee58bcd9ecb 100644 --- a/ext/standard/tests/math/octdec_basiclong_64bit.phpt +++ b/ext/standard/tests/math/octdec_basiclong_64bit.phpt @@ -30,18 +30,24 @@ foreach ($octLongStrs as $strVal) { } ?> ---EXPECT-- +--EXPECTF-- --- testing: 777777777777777777777 --- int(9223372036854775807) --- testing: 1777777777777777777777 --- + +Notice: Input number exceeds maximum integer value, precision has been lost in conversion in %s on line %d float(1.8446744073709552E+19) --- testing: 17777777777 --- int(2147483647) --- testing: 37777777777 --- int(4294967295) --- testing: 377777777777777777777777 --- + +Notice: Input number exceeds maximum integer value, precision has been lost in conversion in %s on line %d float(2.3611832414348226E+21) --- testing: 17777777777777777777777777 --- + +Notice: Input number exceeds maximum integer value, precision has been lost in conversion in %s on line %d float(7.555786372591432E+22) --- testing: 377777777777 --- int(34359738367) From ff27d73e4ddab3b65a2fb0be8fd87d8a9136e11a Mon Sep 17 00:00:00 2001 From: Sjoerd Langkemper Date: Sat, 20 Jun 2026 13:40:30 +0000 Subject: [PATCH 2/2] Fix test by creating large integer differently The test for overflow used a large integer, larger than PHP_INT_MAX. Previously it used base_convert to create an integer 4 * PHP_INT_MAX, but that now raises an overflow warning. We now use PHP_INT_MAX and append a zero, giving 10 * PHP_INT_MAX. We can't just use 4 * PHP_INT_MAX, because that is converted to a float and represented as 3.6893488147419E+19 instead of 36893488147419104082. --- Zend/tests/zend_ini/zend_ini_parse_uquantity_overflow.phpt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Zend/tests/zend_ini/zend_ini_parse_uquantity_overflow.phpt b/Zend/tests/zend_ini/zend_ini_parse_uquantity_overflow.phpt index 0da9c4fac976..f770ccbcaf20 100644 --- a/Zend/tests/zend_ini/zend_ini_parse_uquantity_overflow.phpt +++ b/Zend/tests/zend_ini/zend_ini_parse_uquantity_overflow.phpt @@ -15,8 +15,8 @@ $tests = [ 'No overflow 007' => ' -1', 'No overflow 008' => '-1 ', 'No overflow 009' => ' -1 ', - 'Subject overflow 001' => base_convert(str_repeat('1', PHP_INT_SIZE*8+1), 2, 10), - 'Subject overflow 002' => '-'.base_convert(str_repeat('1', PHP_INT_SIZE*8+1), 2, 10), + 'Subject overflow 001' => PHP_INT_MAX.'0', + 'Subject overflow 002' => PHP_INT_MIN.'0', 'Subject overflow 003' => strval(PHP_INT_MIN), 'Subject overflow 004' => '-2', 'Subject overflow 005' => '-1K',