Commit 0236667bd94 for php.net

commit 0236667bd941bec856ffb95e39f8f95b80c68edd
Author: David Carlier <devnexen@gmail.com>
Date:   Sat Apr 18 07:17:48 2026 +0100

    ext/gmp: gmp_fact() reject values larger than unsigned long.

    close GH-21794

diff --git a/NEWS b/NEWS
index f5c9cfa7550..2000d5b4710 100644
--- a/NEWS
+++ b/NEWS
@@ -36,6 +36,9 @@ PHP                                                                        NEWS
   . imagesetstyle()/imagefilter()/imagecrop() check array argument entries
     types. (David Carlier)

+- GMP:
+  . gmp_fact() reject values larger than unsigned long. (David Carlier)
+
 - Hash:
   . Upgrade xxHash to 0.8.2. (timwolla)

diff --git a/UPGRADING b/UPGRADING
index 5e32a5418b5..10a63f6b03a 100644
--- a/UPGRADING
+++ b/UPGRADING
@@ -141,6 +141,10 @@ PHP 8.6 UPGRADE NOTES
 5. Changed Functions
 ========================================

+- GMP:
+  . gmp_fact() now throws a ValueError() if $num does not fit into
+    a unsigned long.
+
 - mysqli:
   . The return structure of mysqli_get_charset() no longer contains
     the undocumented "comment" element. The value of "charsetnr" is
diff --git a/ext/gmp/gmp.c b/ext/gmp/gmp.c
index cf6580e95e9..a2097458090 100644
--- a/ext/gmp/gmp.c
+++ b/ext/gmp/gmp.c
@@ -1092,8 +1092,10 @@ 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()
+	if (!mpz_fits_ulong_p(gmpnum)) {
+		zend_argument_value_error(1, "must be between 0 and %lu", ULONG_MAX);
+		RETURN_THROWS();
+	}

 	INIT_GMP_RETVAL(gmpnum_result);
 	mpz_fac_ui(gmpnum_result, mpz_get_ui(gmpnum));
diff --git a/ext/gmp/tests/gmp_fact_overflow.phpt b/ext/gmp/tests/gmp_fact_overflow.phpt
new file mode 100644
index 00000000000..2d22005818c
--- /dev/null
+++ b/ext/gmp/tests/gmp_fact_overflow.phpt
@@ -0,0 +1,25 @@
+--TEST--
+gmp_fact() rejects values larger than unsigned long
+--EXTENSIONS--
+gmp
+--FILE--
+<?php
+
+try {
+    var_dump(gmp_fact(gmp_pow(2, 100)));
+} catch (\ValueError $e) {
+    echo $e->getMessage() . \PHP_EOL;
+}
+
+try {
+    var_dump(gmp_fact(gmp_init("18446744073709551616")));
+} catch (\ValueError $e) {
+    echo $e->getMessage() . \PHP_EOL;
+}
+
+echo "Done\n";
+?>
+--EXPECTF--
+gmp_fact(): Argument #1 ($num) must be between 0 and %d
+gmp_fact(): Argument #1 ($num) must be between 0 and %d
+Done