Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
40 changes: 37 additions & 3 deletions ext/gmp/gmp.c
Original file line number Diff line number Diff line change
Expand Up @@ -365,11 +365,37 @@ static zend_result shift_operator_helper(gmp_binary_ui_op_t op, zval *return_val
return FAILURE;
} else {
mpz_ptr gmpnum_op, gmpnum_result;

size_t bits;

if (!gmp_zend_parse_arg_into_mpz_ex(op1, &gmpnum_op, 1, true)) {
goto typeof_op_failure;
}

bits = mpz_sizeinbase(gmpnum_op, 2);
if (bits == 0) {
bits = 1;
}

if (opcode == ZEND_POW) {
if ((size_t) shift > (SIZE_MAX - 5) / bits) {
zend_value_error(
"exponent results in a value that exceeds the supported size"
);
return FAILURE;
}
}

if (opcode == ZEND_SL) {
size_t max_shift = ((size_t)INT_MAX * GMP_NUMB_BITS);

if ((size_t) shift > max_shift) {
zend_value_error(
"shift count results in a value that exceeds the supported size"
);
return FAILURE;
}
}

INIT_GMP_RETVAL(gmpnum_result);
op(gmpnum_result, gmpnum_op, (gmp_ulong) shift);
return SUCCESS;
Expand Down Expand Up @@ -1125,14 +1151,22 @@ ZEND_FUNCTION(gmp_pow)
mpz_ptr gmpnum_result;
mpz_ptr gmpnum_base;
zend_long exp;
size_t bits;

ZEND_PARSE_PARAMETERS_START(2, 2)
GMP_Z_PARAM_INTO_MPZ_PTR(gmpnum_base)
Z_PARAM_LONG(exp)
ZEND_PARSE_PARAMETERS_END();

if (exp < 0 || exp > ULONG_MAX) {
zend_argument_value_error(2, "must be between 0 and %lu", ULONG_MAX);
if (exp < 0) {
zend_argument_value_error(2, "must be greater than or equal to 0");
RETURN_THROWS();
}

bits = mpz_sizeinbase(gmpnum_base, 2);

if (exp > (SIZE_MAX - 5) / bits) {
zend_argument_value_error(2, "results in a value that exceeds the supported size");
RETURN_THROWS();
}

Expand Down
22 changes: 22 additions & 0 deletions ext/gmp/tests/gh22351.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
--TEST--
GH-22351: gmp_pow with PHP_INT_MAX should not crash
--EXTENSIONS--
gmp
--FILE--
<?php

echo "Testing gmp_pow overflow safety\n";

try {
$r = gmp_pow(2, PHP_INT_MAX);
var_dump($r);
} catch (ValueError $e) {
echo "ValueError: " . $e->getMessage() . PHP_EOL;
}

echo "Done\n";
?>
--EXPECTF--
Testing gmp_pow overflow safety
ValueError: gmp_pow(): Argument #2 ($exponent) results in a value that exceeds the supported size
Done
2 changes: 1 addition & 1 deletion ext/gmp/tests/gmp_overflow_llp64.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ try {
echo "Done\n";
?>
--EXPECTF--
gmp_pow(): Argument #2 ($exponent) must be between 0 and %d
gmp_pow(): Argument #2 ($exponent) results in a value that exceeds the supported size
gmp_binomial(): Argument #2 ($k) must be between 0 and %d
gmp_root(): Argument #2 ($nth) must be between 1 and %d
gmp_rootrem(): Argument #2 ($nth) must be between 1 and %d
Expand Down
4 changes: 2 additions & 2 deletions ext/gmp/tests/gmp_pow.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -49,11 +49,11 @@ string(4) "1024"
string(5) "-2048"
string(4) "1024"
string(1) "1"
gmp_pow(): Argument #2 ($exponent) must be between 0 and %d
gmp_pow(): Argument #2 ($exponent) must be greater than or equal to 0
string(4) "1024"
string(14) "10240000000000"
string(17) "97656250000000000"
gmp_pow(): Argument #2 ($exponent) must be between 0 and %d
gmp_pow(): Argument #2 ($exponent) must be greater than or equal to 0
string(14) "10240000000000"
string(14) "10240000000000"
gmp_pow(): Argument #2 ($exponent) must be of type int, array given
Expand Down
Loading