Skip to content

Commit e596757

Browse files
committed
ext/standard: 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 PR: #22371
1 parent 78fc4cd commit e596757

12 files changed

Lines changed: 62 additions & 9 deletions

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,8 @@ PHP NEWS
276276
(David Carlier)
277277
. TSRM: make CG, EG, SCNG and AG compile-time offsets. (henderkes)
278278
. Deprecate returning values from __construct() and __destruct(). (timwolla)
279+
. base_convert, bindex, hexdec and octdec now raise a notice when they cannot
280+
precisely convert the given number. (Sjoerd Langkemper)
279281

280282
- BCMath:
281283
. Added NUL-byte validation to BCMath functions. (jorgsowa)

Zend/tests/zend_ini/zend_ini_parse_uquantity_overflow.phpt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ $tests = [
1515
'No overflow 007' => ' -1',
1616
'No overflow 008' => '-1 ',
1717
'No overflow 009' => ' -1 ',
18-
'Subject overflow 001' => base_convert(str_repeat('1', PHP_INT_SIZE*8+1), 2, 10),
19-
'Subject overflow 002' => '-'.base_convert(str_repeat('1', PHP_INT_SIZE*8+1), 2, 10),
18+
'Subject overflow 001' => PHP_INT_MAX.'0',
19+
'Subject overflow 002' => PHP_INT_MIN.'0',
2020
'Subject overflow 003' => strval(PHP_INT_MIN),
2121
'Subject overflow 004' => '-2',
2222
'Subject overflow 005' => '-1K',

ext/standard/math.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -899,6 +899,7 @@ PHPAPI void _php_math_basetozval(zend_string *str, int base, zval *ret)
899899
num = num * base + c;
900900
break;
901901
} else {
902+
zend_error(E_NOTICE, "Input number is larger than PHP_INT_MAX, precision has been lost in conversion");
902903
fnum = (double)num;
903904
mode = 1;
904905
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
--TEST--
2+
Test base_convert() - overflow test
3+
--FILE--
4+
<?php
5+
var_dump(base_convert('fffffffffffffffff', 16, 15));
6+
?>
7+
--EXPECTF--
8+
9+
Notice: Input number exceeds maximum integer value, precision has been lost in conversion in %s on line %d
10+
string(18) "2ee03c32ad644bd1e1"

ext/standard/tests/math/bindec_basic.phpt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,8 @@ int(129)
5050
int(455)
5151
int(224)
5252
int(2147483647)
53+
54+
Notice: Input number exceeds maximum integer value, precision has been lost in conversion in %s on line %d
5355
float(2147483648)
5456

5557
Deprecated: Invalid characters passed for attempted conversion, these have been ignored in %s on line %d

ext/standard/tests/math/bindec_basiclong_64bit.phpt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,18 +30,24 @@ foreach ($binLongStrs as $strVal) {
3030
}
3131

3232
?>
33-
--EXPECT--
33+
--EXPECTF--
3434
--- testing: 0111111111111111111111111111111111111111111111111111111111111111 ---
3535
int(9223372036854775807)
3636
--- testing: 1111111111111111111111111111111111111111111111111111111111111111 ---
37+
38+
Notice: Input number exceeds maximum integer value, precision has been lost in conversion in %s on line %d
3739
float(1.8446744073709552E+19)
3840
--- testing: 01111111111111111111111111111111 ---
3941
int(2147483647)
4042
--- testing: 11111111111111111111111111111111 ---
4143
int(4294967295)
4244
--- testing: 01111111111111111111111111111111111111111111111111111111111111111 ---
45+
46+
Notice: Input number exceeds maximum integer value, precision has been lost in conversion in %s on line %d
4347
float(1.8446744073709552E+19)
4448
--- testing: 11111111111111111111111111111111111111111111111111111111111111111 ---
49+
50+
Notice: Input number exceeds maximum integer value, precision has been lost in conversion in %s on line %d
4551
float(3.6893488147419103E+19)
4652
--- testing: 011111111111111111111111111111111 ---
4753
int(4294967295)

ext/standard/tests/math/hexdec.phpt

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@ var_dump(hexdec("12345"));
1010
var_dump(hexdec("q12345"));
1111
var_dump(hexdec("12345+?!"));
1212
var_dump(hexdec("12345q"));
13-
var_dump((float)hexdec("1234500001"));
14-
var_dump((float)hexdec("17fffffff"));
13+
var_dump(hexdec("12345678901234567"));
14+
var_dump(hexdec("17fffffffffffffff"));
1515

1616
?>
1717
--EXPECTF--
@@ -26,5 +26,9 @@ int(74565)
2626

2727
Deprecated: Invalid characters passed for attempted conversion, these have been ignored in %s on line %d
2828
int(74565)
29-
float(78187069441)
30-
float(6442450943)
29+
30+
Notice: Input number exceeds maximum integer value, precision has been lost in conversion in %s on line %d
31+
float(2.0988295476557332E+19)
32+
33+
Notice: Input number exceeds maximum integer value, precision has been lost in conversion in %s on line %d
34+
float(2.7670116110564327E+19)

ext/standard/tests/math/hexdec_basic.phpt

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,17 @@ for ($i = 0; $i < count($values); $i++) {
3232
--EXPECTF--
3333
int(18433668)
3434
int(126895953)
35+
36+
Notice: Input number exceeds maximum integer value, precision has been lost in conversion in %s on line %d
3537
float(142929835591)
38+
39+
Notice: Input number exceeds maximum integer value, precision has been lost in conversion in %s on line %d
3640
float(142929835592)
3741
int(1194684)
3842
int(7904751)
3943
int(2147483647)
44+
45+
Notice: Input number exceeds maximum integer value, precision has been lost in conversion in %s on line %d
4046
float(2147483648)
4147

4248
Deprecated: Invalid characters passed for attempted conversion, these have been ignored in %s on line %d

ext/standard/tests/math/hexdec_basiclong_64bit.phpt

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -30,18 +30,24 @@ foreach ($hexLongStrs as $strVal) {
3030
}
3131

3232
?>
33-
--EXPECT--
33+
--EXPECTF--
3434
--- testing: 7fffffffffffffff ---
3535
int(9223372036854775807)
3636
--- testing: ffffffffffffffff ---
37+
38+
Notice: Input number exceeds maximum integer value, precision has been lost in conversion in %s on line %d
3739
float(1.8446744073709552E+19)
3840
--- testing: 7fffffff ---
3941
int(2147483647)
4042
--- testing: ffffffff ---
4143
int(4294967295)
4244
--- testing: 7ffffffffffffffff ---
45+
46+
Notice: Input number exceeds maximum integer value, precision has been lost in conversion in %s on line %d
4347
float(1.4757395258967641E+20)
4448
--- testing: ffffffffffffffffff ---
49+
50+
Notice: Input number exceeds maximum integer value, precision has been lost in conversion in %s on line %d
4551
float(4.722366482869645E+21)
4652
--- testing: 7ffffffff ---
4753
int(34359738367)

ext/standard/tests/math/hexdec_variation1.phpt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,9 +86,13 @@ Deprecated: Invalid characters passed for attempted conversion, these have been
8686
int(9029)
8787

8888
-- Iteration 5 --
89+
90+
Notice: Input number exceeds maximum integer value, precision has been lost in conversion in %s on line %d
8991
float(285960729237)
9092

9193
-- Iteration 6 --
94+
95+
Notice: Input number exceeds maximum integer value, precision has been lost in conversion in %s on line %d
9296
float(285960729238)
9397

9498
-- Iteration 7 --
@@ -102,10 +106,14 @@ Deprecated: Invalid characters passed for attempted conversion, these have been
102106
int(261)
103107

104108
-- Iteration 9 --
109+
110+
Notice: Input number exceeds maximum integer value, precision has been lost in conversion in %s on line %d
105111
float(20015998341120)
106112

107113
-- Iteration 10 --
108114

115+
Notice: Input number exceeds maximum integer value, precision has been lost in conversion in %s on line %d
116+
109117
Deprecated: Invalid characters passed for attempted conversion, these have been ignored in %s on line %d
110118
float(1250999896553)
111119

0 commit comments

Comments
 (0)