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
7 changes: 5 additions & 2 deletions ext/gmp/gmp.c
Original file line number Diff line number Diff line change
Expand Up @@ -1094,8 +1094,11 @@ ZEND_FUNCTION(gmp_fact)
RETURN_THROWS();
}

// TODO: Check that we don't an int that is larger than an unsigned long?
// Could use mpz_fits_slong_p() if we revert to using mpz_get_si()
/* mpz_fac_ui() takes an unsigned long; avoid truncation/overflow + huge work */
if (!mpz_fits_ulong_p(gmpnum) || mpz_cmp_ui(gmpnum, 100000) > 0) {
zend_argument_value_error(1, "is too large");
RETURN_THROWS();
}

INIT_GMP_RETVAL(gmpnum_result);
mpz_fac_ui(gmpnum_result, mpz_get_ui(gmpnum));
Expand Down
58 changes: 58 additions & 0 deletions ext/gmp/tests/gh16878.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
--TEST--
GH-16878: Core dump when gmp_fact allocates huge memory
--EXTENSIONS--
gmp
--FILE--
<?php
echo "Test 1: Factorial of 2^50 + 1\n";
try {
$value = gmp_add(gmp_pow(2, 50), 1);
echo "Calculating factorial of: ", gmp_strval($value), "\n";
$result = gmp_fact($value);
echo "Result: " . gmp_strval($result) . "\n";
} catch (\ValueError $e) {
echo "ValueError: " . $e->getMessage() . "\n";
} catch (\Error $e) {
echo "Error: " . $e->getMessage() . "\n";
}

echo "\nTest 2: Another large value\n";
try {
$value = gmp_init('1000000000000'); // 1 trillion
echo "Calculating factorial of: ", gmp_strval($value), "\n";
$result = gmp_fact($value);
echo "Result: " . gmp_strval($result) . "\n";
} catch (\ValueError $e) {
echo "ValueError: " . $e->getMessage() . "\n";
} catch (\Error $e) {
echo "Error: " . $e->getMessage() . "\n";
}

echo "\nTest 3: Moderately large value that should work\n";
try {
$value = 100;
echo "Calculating factorial of: $value\n";
$result = gmp_fact($value);
echo "Result length: " . strlen(gmp_strval($result)) . " digits\n";
} catch (\ValueError $e) {
echo "ValueError: " . $e->getMessage() . "\n";
} catch (\Error $e) {
echo "Error: " . $e->getMessage() . "\n";
}

echo "\nDone\n";
?>
--EXPECTF--
Test 1: Factorial of 2^50 + 1
Calculating factorial of: 1125899906842625
ValueError: %s

Test 2: Another large value
Calculating factorial of: 1000000000000
ValueError: %s

Test 3: Moderately large value that should work
Calculating factorial of: 100
Result length: 158 digits

Done
Loading