Commit 9b01f517012 for php.net
commit 9b01f517012b2612d0e1c8789eb540a36faf1346
Author: David Carlier <devnexen@gmail.com>
Date: Mon Feb 23 21:56:02 2026 +0000
ext/pcntl: Reject negative values in pcntl_alarm()
internal refactorings:
- pcntl_signal_get_handler() max signals handling simplification,
reusing the num_signals global.
- pcntl_alarm() accepts a zend_long (signed) but passes it to alarm(),
which takes an unsigned int. Negative values silently wrap to large
unsigned values, scheduling an alarm far in the future instead of
raising an error. Also reject large values above unsigned long
max value.
close GH-21282
diff --git a/UPGRADING b/UPGRADING
index e034d0b0235..9a1b37d98f7 100644
--- a/UPGRADING
+++ b/UPGRADING
@@ -105,6 +105,10 @@ PHP 8.6 UPGRADE NOTES
. Output of openssl_x509_parse() contains criticalExtensions listing all
critical certificate extensions.
+- PCNTL:
+ . pcntl_alarm() now throws a ValueError if the seconds argument is
+ lower than zero or greater than platform's UINT_MAX.
+
- Phar:
. Phar::mungServer() now supports reference values.
diff --git a/ext/pcntl/pcntl.c b/ext/pcntl/pcntl.c
index 53286723e19..0ef87fffa28 100644
--- a/ext/pcntl/pcntl.c
+++ b/ext/pcntl/pcntl.c
@@ -212,7 +212,7 @@ PHP_RINIT_FUNCTION(pcntl)
PCNTL_G(last_error) = 0;
PCNTL_G(num_signals) = NSIG;
#ifdef SIGRTMAX
- /* At least FreeBSD reports an incorrecrt NSIG that does not include realtime signals.
+ /* At least FreeBSD reports an incorrect NSIG that does not include realtime signals.
* As SIGRTMAX may be a dynamic value, adjust the value in INIT. */
if (NSIG < SIGRTMAX + 1) {
PCNTL_G(num_signals) = SIGRTMAX + 1;
@@ -314,6 +314,11 @@ PHP_FUNCTION(pcntl_alarm)
Z_PARAM_LONG(seconds);
ZEND_PARSE_PARAMETERS_END();
+ if (seconds < 0 || seconds > UINT_MAX) {
+ zend_argument_value_error(1, "must be between 0 and %u", UINT_MAX);
+ RETURN_THROWS();
+ }
+
RETURN_LONG((zend_long) alarm(seconds));
}
/* }}} */
@@ -870,17 +875,8 @@ PHP_FUNCTION(pcntl_signal_get_handler)
Z_PARAM_LONG(signo)
ZEND_PARSE_PARAMETERS_END();
- // note: max signal on mac is SIGUSR2 (31), no real time signals.
- int sigmax = NSIG - 1;
-#if defined(SIGRTMAX)
- // oddily enough, NSIG on freebsd reports only 32 whereas SIGRTMIN starts at 65.
- if (sigmax < SIGRTMAX) {
- sigmax = SIGRTMAX;
- }
-#endif
-
- if (signo < 1 || signo > sigmax) {
- zend_argument_value_error(1, "must be between 1 and %d", sigmax);
+ if (signo < 1 || signo >= PCNTL_G(num_signals)) {
+ zend_argument_value_error(1, "must be between 1 and %d", PCNTL_G(num_signals) - 1);
RETURN_THROWS();
}
@@ -1153,7 +1149,7 @@ static void pcntl_siginfo_to_zval(int signo, siginfo_t *siginfo, zval *user_sigi
case SIGFPE:
case SIGSEGV:
case SIGBUS:
- add_assoc_double_ex(user_siginfo, "addr", sizeof("addr")-1, (zend_long)siginfo->si_addr);
+ add_assoc_long_ex(user_siginfo, "addr", sizeof("addr")-1, (zend_long)siginfo->si_addr);
break;
#if defined(SIGPOLL) && !defined(__CYGWIN__)
case SIGPOLL:
diff --git a/ext/pcntl/tests/pcntl_alarm_invalid_value.phpt b/ext/pcntl/tests/pcntl_alarm_invalid_value.phpt
new file mode 100644
index 00000000000..59e74662f6f
--- /dev/null
+++ b/ext/pcntl/tests/pcntl_alarm_invalid_value.phpt
@@ -0,0 +1,35 @@
+--TEST--
+pcntl_alarm() rejects invalid values
+--EXTENSIONS--
+pcntl
+--SKIPIF--
+<?php if (PHP_INT_SIZE < 8) die("skip 64-bit only"); ?>
+--FILE--
+<?php
+
+try {
+ pcntl_alarm(-1);
+} catch (\ValueError $e) {
+ echo $e->getMessage() . \PHP_EOL;
+}
+
+try {
+ pcntl_alarm(PHP_INT_MIN);
+} catch (\ValueError $e) {
+ echo $e->getMessage() . \PHP_EOL;
+}
+
+try {
+ pcntl_alarm(PHP_INT_MAX);
+} catch (\ValueError $e) {
+ echo $e->getMessage() . \PHP_EOL;
+}
+
+var_dump(pcntl_alarm(0));
+
+?>
+--EXPECTF--
+pcntl_alarm(): Argument #1 ($seconds) must be between 0 and %d
+pcntl_alarm(): Argument #1 ($seconds) must be between 0 and %d
+pcntl_alarm(): Argument #1 ($seconds) must be between 0 and %d
+int(0)