From 44533b1c2a86dc53c786bb059b7301f1cc9b7f73 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Mon, 23 Feb 2026 21:56:02 +0000 Subject: [PATCH 1/5] ext/pcntl: Reject negative values in pcntl_alarm() 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. --- ext/pcntl/pcntl.c | 5 ++++ .../tests/pcntl_alarm_negative_value.phpt | 26 +++++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 ext/pcntl/tests/pcntl_alarm_negative_value.phpt diff --git a/ext/pcntl/pcntl.c b/ext/pcntl/pcntl.c index 54d39a1eb0e73..fed0398420592 100644 --- a/ext/pcntl/pcntl.c +++ b/ext/pcntl/pcntl.c @@ -314,6 +314,11 @@ PHP_FUNCTION(pcntl_alarm) Z_PARAM_LONG(seconds); ZEND_PARSE_PARAMETERS_END(); + if (seconds < 0) { + zend_argument_value_error(1, "must be greater or equal to 0"); + RETURN_THROWS(); + } + RETURN_LONG((zend_long) alarm(seconds)); } /* }}} */ diff --git a/ext/pcntl/tests/pcntl_alarm_negative_value.phpt b/ext/pcntl/tests/pcntl_alarm_negative_value.phpt new file mode 100644 index 0000000000000..6c21c8dd882d5 --- /dev/null +++ b/ext/pcntl/tests/pcntl_alarm_negative_value.phpt @@ -0,0 +1,26 @@ +--TEST-- +pcntl_alarm() rejects negative values +--EXTENSIONS-- +pcntl +--FILE-- +getMessage() . \PHP_EOL; +} + +try { + pcntl_alarm(PHP_INT_MIN); +} catch (\ValueError $e) { + echo $e->getMessage() . \PHP_EOL; +} + +var_dump(pcntl_alarm(0)); + +?> +--EXPECT-- +pcntl_alarm(): Argument #1 ($seconds) must be greater or equal to 0 +pcntl_alarm(): Argument #1 ($seconds) must be greater or equal to 0 +int(0) From fcbcab2b2e5063f471a799bef4bad3cee0b80902 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Mon, 23 Feb 2026 22:30:16 +0000 Subject: [PATCH 2/5] pcntl_signal_get_handler() update. deduplicated max signals computation by using globals --- ext/pcntl/pcntl.c | 15 +++------------ 1 file changed, 3 insertions(+), 12 deletions(-) diff --git a/ext/pcntl/pcntl.c b/ext/pcntl/pcntl.c index fed0398420592..1da9eb2cccd43 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; @@ -875,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(); } From 0a900dc8aa72bc4d12cbec7b987619d33fdeef31 Mon Sep 17 00:00:00 2001 From: David Carlier Date: Mon, 23 Feb 2026 22:36:09 +0000 Subject: [PATCH 3/5] displaying siginfo si_addr update. since it is casted to zend_long, better using add_assoc_long_ex due to loss of precision with add_assoc_double_ex --- ext/pcntl/pcntl.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/pcntl/pcntl.c b/ext/pcntl/pcntl.c index 1da9eb2cccd43..5618119f83fcf 100644 --- a/ext/pcntl/pcntl.c +++ b/ext/pcntl/pcntl.c @@ -1149,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: From ce2fdb7303302c9613949791b173d7dfa6e9a0fb Mon Sep 17 00:00:00 2001 From: David Carlier Date: Tue, 24 Feb 2026 11:52:32 +0000 Subject: [PATCH 4/5] ext/pcntl: Also reject too large values in pcntl_alarm() --- ext/pcntl/pcntl.c | 4 +-- .../tests/pcntl_alarm_invalid_value.phpt | 33 +++++++++++++++++++ .../tests/pcntl_alarm_negative_value.phpt | 26 --------------- 3 files changed, 35 insertions(+), 28 deletions(-) create mode 100644 ext/pcntl/tests/pcntl_alarm_invalid_value.phpt delete mode 100644 ext/pcntl/tests/pcntl_alarm_negative_value.phpt diff --git a/ext/pcntl/pcntl.c b/ext/pcntl/pcntl.c index 5618119f83fcf..51fec247190c5 100644 --- a/ext/pcntl/pcntl.c +++ b/ext/pcntl/pcntl.c @@ -314,8 +314,8 @@ PHP_FUNCTION(pcntl_alarm) Z_PARAM_LONG(seconds); ZEND_PARSE_PARAMETERS_END(); - if (seconds < 0) { - zend_argument_value_error(1, "must be greater or equal to 0"); + if (seconds < 0 || seconds > UINT_MAX) { + zend_argument_value_error(1, "must be between 0 and %u", UINT_MAX); RETURN_THROWS(); } 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 0000000000000..fec97dca28d44 --- /dev/null +++ b/ext/pcntl/tests/pcntl_alarm_invalid_value.phpt @@ -0,0 +1,33 @@ +--TEST-- +pcntl_alarm() rejects invalid values +--EXTENSIONS-- +pcntl +--FILE-- +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) diff --git a/ext/pcntl/tests/pcntl_alarm_negative_value.phpt b/ext/pcntl/tests/pcntl_alarm_negative_value.phpt deleted file mode 100644 index 6c21c8dd882d5..0000000000000 --- a/ext/pcntl/tests/pcntl_alarm_negative_value.phpt +++ /dev/null @@ -1,26 +0,0 @@ ---TEST-- -pcntl_alarm() rejects negative values ---EXTENSIONS-- -pcntl ---FILE-- -getMessage() . \PHP_EOL; -} - -try { - pcntl_alarm(PHP_INT_MIN); -} catch (\ValueError $e) { - echo $e->getMessage() . \PHP_EOL; -} - -var_dump(pcntl_alarm(0)); - -?> ---EXPECT-- -pcntl_alarm(): Argument #1 ($seconds) must be greater or equal to 0 -pcntl_alarm(): Argument #1 ($seconds) must be greater or equal to 0 -int(0) From 63db61bd7c1841f9283c09c59b4a5fc77dd1cf0a Mon Sep 17 00:00:00 2001 From: David Carlier Date: Tue, 24 Feb 2026 12:46:17 +0000 Subject: [PATCH 5/5] 32 bits test discard --- ext/pcntl/tests/pcntl_alarm_invalid_value.phpt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ext/pcntl/tests/pcntl_alarm_invalid_value.phpt b/ext/pcntl/tests/pcntl_alarm_invalid_value.phpt index fec97dca28d44..59e74662f6f7c 100644 --- a/ext/pcntl/tests/pcntl_alarm_invalid_value.phpt +++ b/ext/pcntl/tests/pcntl_alarm_invalid_value.phpt @@ -2,6 +2,8 @@ pcntl_alarm() rejects invalid values --EXTENSIONS-- pcntl +--SKIPIF-- + --FILE--