Skip to content

Commit d25d725

Browse files
committed
Fix GH-16870: gmp_pow(64, 11) throws overflow exception
The current guard to prevent FPEs is way too restrictive; `64 ** 11` is a perfectly reasonable operation. Instead, we now estimate the number of bytes of the resulting GMP (assuming that numbers are stored base 256 encoded), and fail if that exceeds a given threshold. The chosen threshold is somewhat arbitrary. We also ensure that we do not prematurely convert a given non int base to an int to avoid overflow which could circumvent our early check.
1 parent ff3b4ec commit d25d725

File tree

2 files changed

+19
-4
lines changed

2 files changed

+19
-4
lines changed

ext/gmp/gmp.c

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1350,11 +1350,11 @@ ZEND_FUNCTION(gmp_pow)
13501350
RETURN_THROWS();
13511351
}
13521352

1353-
double powmax = log((double)ZEND_LONG_MAX);
1353+
double powmax = 2000;
13541354

13551355
if (Z_TYPE_P(base_arg) == IS_LONG && Z_LVAL_P(base_arg) >= 0) {
13561356
INIT_GMP_RETVAL(gmpnum_result);
1357-
if ((log(Z_LVAL_P(base_arg)) * exp) > powmax) {
1357+
if ((log(Z_LVAL_P(base_arg)) / log(256) * exp) > powmax) {
13581358
zend_value_error("base and exponent overflow");
13591359
RETURN_THROWS();
13601360
}
@@ -1364,8 +1364,7 @@ ZEND_FUNCTION(gmp_pow)
13641364
zend_ulong gmpnum;
13651365
FETCH_GMP_ZVAL(gmpnum_base, base_arg, temp_base, 1);
13661366
INIT_GMP_RETVAL(gmpnum_result);
1367-
gmpnum = mpz_get_ui(gmpnum_base);
1368-
if ((log(gmpnum) * exp) > powmax) {
1367+
if ((mpz_sizeinbase(gmpnum_base, 16) / 2.0 * exp) > powmax) {
13691368
FREE_GMP_TEMP(temp_base);
13701369
zend_value_error("base and exponent overflow");
13711370
RETURN_THROWS();

ext/gmp/tests/gh16870.phpt

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
--TEST--
2+
GH-16870 (gmp_pow(64, 11) throws overflow exception)
3+
--EXTENSIONS--
4+
gmp
5+
--FILE--
6+
<?php
7+
var_dump((string) gmp_pow(64, 11));
8+
try {
9+
gmp_pow("18446744073709551616", 0x7fffffff);
10+
} catch (ValueError $e) {
11+
echo $e->getMessage(), "\n";
12+
}
13+
?>
14+
--EXPECT--
15+
string(20) "73786976294838206464"
16+
base and exponent overflow

0 commit comments

Comments
 (0)