Skip to content

Commit 5eb9bbd

Browse files
authored
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: #22371
1 parent 2489264 commit 5eb9bbd

13 files changed

Lines changed: 64 additions & 10 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 is larger than PHP_INT_MAX, 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 is larger than PHP_INT_MAX, 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 is larger than PHP_INT_MAX, 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 is larger than PHP_INT_MAX, precision has been lost in conversion in %s on line %d
4347
float(1.8446744073709552E+19)
4448
--- testing: 11111111111111111111111111111111111111111111111111111111111111111 ---
49+
50+
Notice: Input number is larger than PHP_INT_MAX, 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/gh22395.phpt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ $result = base_convert(str_repeat("1", 61), 36, 16);
66
var_dump(strlen($result));
77
var_dump(substr($result, 0, 13));
88
?>
9-
--EXPECT--
9+
--EXPECTF--
10+
Notice: Input number is larger than PHP_INT_MAX, precision has been lost in conversion in %s on line %d
1011
int(78)
1112
string(13) "4b61b5e0639ff"

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 is larger than PHP_INT_MAX, precision has been lost in conversion in %s on line %d
31+
float(2.0988295476557332E+19)
32+
33+
Notice: Input number is larger than PHP_INT_MAX, 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 is larger than PHP_INT_MAX, precision has been lost in conversion in %s on line %d
3537
float(142929835591)
38+
39+
Notice: Input number is larger than PHP_INT_MAX, 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 is larger than PHP_INT_MAX, 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 is larger than PHP_INT_MAX, 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 is larger than PHP_INT_MAX, precision has been lost in conversion in %s on line %d
4347
float(1.4757395258967641E+20)
4448
--- testing: ffffffffffffffffff ---
49+
50+
Notice: Input number is larger than PHP_INT_MAX, precision has been lost in conversion in %s on line %d
4551
float(4.722366482869645E+21)
4652
--- testing: 7ffffffff ---
4753
int(34359738367)

0 commit comments

Comments
 (0)