[PHP-CVS] [php-src] master: ext/standard: Warn when number base conversion loses precision (#22371)

[email protected] (Sjoerd Langkemper via GitHub) Wed, 29 Jul 2026 18:42:58 +0000
Newsgroups php.cvs
Message-ID <[email protected]>
Author: Sjoerd Langkemper (Sjord)
Committer: GitHub (web-flow)
Pusher: LamentXU123
Date: 2026-07-30T02:42:55+08:00

Commit: https://github.com/php/php-src/commit/5eb9bbddb4cb4c8cd0560ad933f27514cbaf9e91
Raw diff: https://github.com/php/php-src/commit/5eb9bbddb4cb4c8cd0560ad933f27514cbaf9e91.diff

ext/standard: Warn when number base conversion loses precision (#22371)

_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
PR: https://github.com/php/php-src/pull/22371

Changed paths:
  A  ext/standard/tests/math/base_convert_overflow.phpt
  M  NEWS
  M  Zend/tests/zend_ini/zend_ini_parse_uquantity_overflow.phpt
  M  ext/standard/math.c
  M  ext/standard/tests/math/bindec_basic.phpt
  M  ext/standard/tests/math/bindec_basiclong_64bit.phpt
  M  ext/standard/tests/math/gh22395.phpt
  M  ext/standard/tests/math/hexdec.phpt
  M  ext/standard/tests/math/hexdec_basic.phpt
  M  ext/standard/tests/math/hexdec_basiclong_64bit.phpt
  M  ext/standard/tests/math/hexdec_variation1.phpt
  M  ext/standard/tests/math/octdec_basic.phpt
  M  ext/standard/tests/math/octdec_basiclong_64bit.phpt


Diff:

diff --git a/NEWS b/NEWS
index c144b3c62c23..cb70bda237ff 100644
--- a/NEWS
+++ b/NEWS
@@ -276,6 +276,8 @@ PHP                                                                        NEWS
     (David Carlier)
   . TSRM: make CG, EG, SCNG and AG compile-time offsets. (henderkes)
   . Deprecate returning values from __construct() and __destruct(). (timwolla)
+  . base_convert, bindex, hexdec and octdec now raise a notice when they cannot
+    precisely convert the given number. (Sjoerd Langkemper)
 
 - BCMath:
   . Added NUL-byte validation to BCMath functions. (jorgsowa)
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',
diff --git a/ext/standard/math.c b/ext/standard/math.c
index 1498a1efc0b2..e13f153f63e2 100644
--- a/ext/standard/math.c
+++ b/ext/standard/math.c
@@ -899,6 +899,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 is larger than PHP_INT_MAX, precision has been lost in conversion");
 				fnum = (double)num;
 				mode = 1;
 			}
diff --git a/ext/standard/tests/math/base_convert_overflow.phpt b/ext/standard/tests/math/base_convert_overflow.phpt
new file mode 100644
index 000000000000..0f74bdc76a63
--- /dev/null
+++ b/ext/standard/tests/math/base_convert_overflow.phpt
@@ -0,0 +1,10 @@
+--TEST--
+Test base_convert() - overflow test
+--FILE--
+<?php
+var_dump(base_convert('fffffffffffffffff', 16, 15));
+?>
+--EXPECTF--
+
+Notice: Input number is larger than PHP_INT_MAX, precision has been lost in conversion in %s on line %d
+string(18) "2ee03c32ad644bd1e1"
\ No newline at end of file
diff --git a/ext/standard/tests/math/bindec_basic.phpt b/ext/standard/tests/math/bindec_basic.phpt
index 7640171fe61b..d1197ed1645c 100644
--- a/ext/standard/tests/math/bindec_basic.phpt
+++ b/ext/standard/tests/math/bindec_basic.phpt
@@ -50,6 +50,8 @@ int(129)
 int(455)
 int(224)
 int(2147483647)
+
+Notice: Input number is larger than PHP_INT_MAX, precision has been lost in conversion in %s on line %d
 float(2147483648)
 
 Deprecated: Invalid characters passed for attempted conversion, these have been ignored in %s on line %d
diff --git a/ext/standard/tests/math/bindec_basiclong_64bit.phpt b/ext/standard/tests/math/bindec_basiclong_64bit.phpt
index b4f28a091dbb..eb648c7c535f 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 is larger than PHP_INT_MAX, 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 is larger than PHP_INT_MAX, precision has been lost in conversion in %s on line %d
 float(1.8446744073709552E+19)
 --- testing: 11111111111111111111111111111111111111111111111111111111111111111 ---
+
+Notice: Input number is larger than PHP_INT_MAX, 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/gh22395.phpt b/ext/standard/tests/math/gh22395.phpt
index 73c2c66da199..6ccbb44d669f 100644
--- a/ext/standard/tests/math/gh22395.phpt
+++ b/ext/standard/tests/math/gh22395.phpt
@@ -6,6 +6,7 @@ $result = base_convert(str_repeat("1", 61), 36, 16);
 var_dump(strlen($result));
 var_dump(substr($result, 0, 13));
 ?>
---EXPECT--
+--EXPECTF--
+Notice: Input number is larger than PHP_INT_MAX, precision has been lost in conversion in %s on line %d
 int(78)
 string(13) "4b61b5e0639ff"
diff --git a/ext/standard/tests/math/hexdec.phpt b/ext/standard/tests/math/hexdec.phpt
index ba09875efc39..1f8b57d83fd0 100644
--- a/ext/standard/tests/math/hexdec.phpt
+++ b/ext/standard/tests/math/hexdec.phpt
@@ -10,8 +10,8 @@ var_dump(hexdec("12345"));
 var_dump(hexdec("q12345"));
 var_dump(hexdec("12345+?!"));
 var_dump(hexdec("12345q"));
-var_dump((float)hexdec("1234500001"));
-var_dump((float)hexdec("17fffffff"));
+var_dump(hexdec("12345678901234567"));
+var_dump(hexdec("17fffffffffffffff"));
 
 ?>
 --EXPECTF--
@@ -26,5 +26,9 @@ int(74565)
 
 Deprecated: Invalid characters passed for attempted conversion, these have been ignored in %s on line %d
 int(74565)
-float(78187069441)
-float(6442450943)
+
+Notice: Input number is larger than PHP_INT_MAX, precision has been lost in conversion in %s on line %d
+float(2.0988295476557332E+19)
+
+Notice: Input number is larger than PHP_INT_MAX, precision has been lost in conversion in %s on line %d
+float(2.7670116110564327E+19)
diff --git a/ext/standard/tests/math/hexdec_basic.phpt b/ext/standard/tests/math/hexdec_basic.phpt
index 2f06b9650aed..f1fd76778bfd 100644
--- a/ext/standard/tests/math/hexdec_basic.phpt
+++ b/ext/standard/tests/math/hexdec_basic.phpt
@@ -32,11 +32,17 @@ for ($i = 0; $i < count($values); $i++) {
 --EXPECTF--
 int(18433668)
 int(126895953)
+
+Notice: Input number is larger than PHP_INT_MAX, precision has been lost in conversion in %s on line %d
 float(142929835591)
+
+Notice: Input number is larger than PHP_INT_MAX, precision has been lost in conversion in %s on line %d
 float(142929835592)
 int(1194684)
 int(7904751)
 int(2147483647)
+
+Notice: Input number is larger than PHP_INT_MAX, precision has been lost in conversion in %s on line %d
 float(2147483648)
 
 Deprecated: Invalid characters passed for attempted conversion, these have been ignored in %s on line %d
diff --git a/ext/standard/tests/math/hexdec_basiclong_64bit.phpt b/ext/standard/tests/math/hexdec_basiclong_64bit.phpt
index af0b448cac01..7475d982004c 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 is larger than PHP_INT_MAX, 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 is larger than PHP_INT_MAX, precision has been lost in conversion in %s on line %d
 float(1.4757395258967641E+20)
 --- testing: ffffffffffffffffff ---
+
+Notice: Input number is larger than PHP_INT_MAX, 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/hexdec_variation1.phpt b/ext/standard/tests/math/hexdec_variation1.phpt
index 65ebbe347b9b..cf0d4e81411c 100644
--- a/ext/standard/tests/math/hexdec_variation1.phpt
+++ b/ext/standard/tests/math/hexdec_variation1.phpt
@@ -86,9 +86,13 @@ Deprecated: Invalid characters passed for attempted conversion, these have been
 int(9029)
 
 -- Iteration 5 --
+
+Notice: Input number is larger than PHP_INT_MAX, precision has been lost in conversion in %s on line %d
 float(285960729237)
 
 -- Iteration 6 --
+
+Notice: Input number is larger than PHP_INT_MAX, precision has been lost in conversion in %s on line %d
 float(285960729238)
 
 -- Iteration 7 --
@@ -102,10 +106,14 @@ Deprecated: Invalid characters passed for attempted conversion, these have been
 int(261)
 
 -- Iteration 9 --
+
+Notice: Input number is larger than PHP_INT_MAX, precision has been lost in conversion in %s on line %d
 float(20015998341120)
 
 -- Iteration 10 --
 
+Notice: Input number is larger than PHP_INT_MAX, precision has been lost in conversion in %s on line %d
+
 Deprecated: Invalid characters passed for attempted conversion, these have been ignored in %s on line %d
 float(1250999896553)
 
diff --git a/ext/standard/tests/math/octdec_basic.phpt b/ext/standard/tests/math/octdec_basic.phpt
index 4c3ffc8b8a91..935cb23e1d35 100644
--- a/ext/standard/tests/math/octdec_basic.phpt
+++ b/ext/standard/tests/math/octdec_basic.phpt
@@ -46,6 +46,8 @@ int(5349)
 int(342391)
 int(375)
 int(2147483647)
+
+Notice: Input number is larger than PHP_INT_MAX, precision has been lost in conversion in %s on line %d
 float(2147483648)
 
 Deprecated: Invalid characters passed for attempted conversion, these have been ignored in %s on line %d
diff --git a/ext/standard/tests/math/octdec_basiclong_64bit.phpt b/ext/standard/tests/math/octdec_basiclong_64bit.phpt
index 06e0dd3929d2..4637893d3470 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 is larger than PHP_INT_MAX, 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 is larger than PHP_INT_MAX, precision has been lost in conversion in %s on line %d
 float(2.3611832414348226E+21)
 --- testing: 17777777777777777777777777 ---
+
+Notice: Input number is larger than PHP_INT_MAX, precision has been lost in conversion in %s on line %d
 float(7.555786372591432E+22)
 --- testing: 377777777777 ---
 int(34359738367)