Skip to content

Commit a950747

Browse files
committed
Fix bug #52173 (ext/pcntl doesn't store/report errors) (patch
by nick dot telford at gmail dot com)
1 parent 8f8b248 commit a950747

File tree

3 files changed

+143
-0
lines changed

3 files changed

+143
-0
lines changed

ext/pcntl/pcntl.c

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@
4444
#include <sys/resource.h>
4545
#endif
4646

47+
#include <errno.h>
48+
4749
ZEND_DECLARE_MODULE_GLOBALS(pcntl)
4850
static PHP_GINIT_FUNCTION(pcntl);
4951

@@ -134,6 +136,10 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_setpriority, 0, 0, 1)
134136
ZEND_ARG_INFO(0, process_identifier)
135137
ZEND_END_ARG_INFO()
136138
#endif
139+
140+
ZEND_BEGIN_ARG_INFO_EX(arginfo_pcntl_strerror, 0, 0, 1)
141+
ZEND_ARG_INFO(0, errno)
142+
ZEND_END_ARG_INFO()
137143
/* }}} */
138144

139145
const zend_function_entry pcntl_functions[] = {
@@ -150,6 +156,9 @@ const zend_function_entry pcntl_functions[] = {
150156
PHP_FE(pcntl_wstopsig, arginfo_pcntl_wstopsig)
151157
PHP_FE(pcntl_exec, arginfo_pcntl_exec)
152158
PHP_FE(pcntl_alarm, arginfo_pcntl_alarm)
159+
PHP_FE(pcntl_get_last_error, arginfo_pcntl_void)
160+
PHP_FALIAS(pcntl_errno, pcntl_get_last_error, NULL)
161+
PHP_FE(pcntl_strerror, arginfo_pcntl_strerror)
153162
#ifdef HAVE_GETPRIORITY
154163
PHP_FE(pcntl_getpriority, arginfo_pcntl_getpriority)
155164
#endif
@@ -407,6 +416,73 @@ void php_register_signal_constants(INIT_FUNC_ARGS)
407416
/* }}} */
408417
}
409418

419+
static void php_pcntl_register_errno_constants(INIT_FUNC_ARGS)
420+
{
421+
#ifdef EINTR
422+
REGISTER_PCNTL_ERRNO_CONSTANT(EINTR);
423+
#endif
424+
#ifdef ECHILD
425+
REGISTER_PCNTL_ERRNO_CONSTANT(ECHILD);
426+
#endif
427+
#ifdef EINVAL
428+
REGISTER_PCNTL_ERRNO_CONSTANT(EINVAL);
429+
#endif
430+
#ifdef EAGAIN
431+
REGISTER_PCNTL_ERRNO_CONSTANT(EAGAIN);
432+
#endif
433+
#ifdef ESRCH
434+
REGISTER_PCNTL_ERRNO_CONSTANT(ESRCH);
435+
#endif
436+
#ifdef EACCES
437+
REGISTER_PCNTL_ERRNO_CONSTANT(EACCES);
438+
#endif
439+
#ifdef EPERM
440+
REGISTER_PCNTL_ERRNO_CONSTANT(EPERM);
441+
#endif
442+
#ifdef ENOMEM
443+
REGISTER_PCNTL_ERRNO_CONSTANT(ENOMEM);
444+
#endif
445+
#ifdef E2BIG
446+
REGISTER_PCNTL_ERRNO_CONSTANT(E2BIG);
447+
#endif
448+
#ifdef EFAULT
449+
REGISTER_PCNTL_ERRNO_CONSTANT(EFAULT);
450+
#endif
451+
#ifdef EIO
452+
REGISTER_PCNTL_ERRNO_CONSTANT(EIO);
453+
#endif
454+
#ifdef EISDIR
455+
REGISTER_PCNTL_ERRNO_CONSTANT(EISDIR);
456+
#endif
457+
#ifdef ELIBBAD
458+
REGISTER_PCNTL_ERRNO_CONSTANT(ELIBBAD);
459+
#endif
460+
#ifdef ELOOP
461+
REGISTER_PCNTL_ERRNO_CONSTANT(ELOOP);
462+
#endif
463+
#ifdef EMFILE
464+
REGISTER_PCNTL_ERRNO_CONSTANT(EMFILE);
465+
#endif
466+
#ifdef ENAMETOOLONG
467+
REGISTER_PCNTL_ERRNO_CONSTANT(ENAMETOOLONG);
468+
#endif
469+
#ifdef ENFILE
470+
REGISTER_PCNTL_ERRNO_CONSTANT(ENFILE);
471+
#endif
472+
#ifdef ENOENT
473+
REGISTER_PCNTL_ERRNO_CONSTANT(ENOENT);
474+
#endif
475+
#ifdef ENOEXEC
476+
REGISTER_PCNTL_ERRNO_CONSTANT(ENOEXEC);
477+
#endif
478+
#ifdef ENOTDIR
479+
REGISTER_PCNTL_ERRNO_CONSTANT(ENOTDIR);
480+
#endif
481+
#ifdef ETXTBSY
482+
REGISTER_PCNTL_ERRNO_CONSTANT(ETXTBSY);
483+
#endif
484+
}
485+
410486
static PHP_GINIT_FUNCTION(pcntl)
411487
{
412488
memset(pcntl_globals, 0, sizeof(*pcntl_globals));
@@ -422,6 +498,7 @@ PHP_RINIT_FUNCTION(pcntl)
422498
PHP_MINIT_FUNCTION(pcntl)
423499
{
424500
php_register_signal_constants(INIT_FUNC_ARGS_PASSTHRU);
501+
php_pcntl_register_errno_constants(INIT_FUNC_ARGS_PASSTHRU);
425502
php_add_tick_function(pcntl_signal_dispatch);
426503

427504
return SUCCESS;
@@ -467,6 +544,7 @@ PHP_FUNCTION(pcntl_fork)
467544

468545
id = fork();
469546
if (id == -1) {
547+
PCNTL_G(last_error) = errno;
470548
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error %d", errno);
471549
}
472550

@@ -505,6 +583,10 @@ PHP_FUNCTION(pcntl_waitpid)
505583

506584
child_id = waitpid((pid_t) pid, &status, options);
507585

586+
if (child_id < 0) {
587+
PCNTL_G(last_error) = errno;
588+
}
589+
508590
Z_LVAL_P(z_status) = status;
509591

510592
RETURN_LONG((long) child_id);
@@ -536,6 +618,10 @@ PHP_FUNCTION(pcntl_wait)
536618
#else
537619
child_id = wait(&status);
538620
#endif
621+
if (child_id < 0) {
622+
PCNTL_G(last_error) = errno;
623+
}
624+
539625
Z_LVAL_P(z_status) = status;
540626

541627
RETURN_LONG((long) child_id);
@@ -729,6 +815,7 @@ PHP_FUNCTION(pcntl_exec)
729815
*(pair) = NULL;
730816

731817
if (execve(path, argv, envp) == -1) {
818+
PCNTL_G(last_error) = errno;
732819
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error has occured: (errno %d) %s", errno, strerror(errno));
733820
}
734821

@@ -738,6 +825,7 @@ PHP_FUNCTION(pcntl_exec)
738825
} else {
739826

740827
if (execv(path, argv) == -1) {
828+
PCNTL_G(last_error) = errno;
741829
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error has occured: (errno %d) %s", errno, strerror(errno));
742830
}
743831
}
@@ -780,13 +868,15 @@ PHP_FUNCTION(pcntl_signal)
780868
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid value for handle argument specified");
781869
}
782870
if (php_signal(signo, (Sigfunc *) Z_LVAL_P(handle), (int) restart_syscalls) == SIG_ERR) {
871+
PCNTL_G(last_error) = errno;
783872
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error assigning signal");
784873
RETURN_FALSE;
785874
}
786875
RETURN_TRUE;
787876
}
788877

789878
if (!zend_is_callable(handle, 0, &func_name TSRMLS_CC)) {
879+
PCNTL_G(last_error) = EINVAL;
790880
php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s is not a callable function name error", func_name);
791881
efree(func_name);
792882
RETURN_FALSE;
@@ -798,6 +888,7 @@ PHP_FUNCTION(pcntl_signal)
798888
if (dest_handle) zval_add_ref(dest_handle);
799889

800890
if (php_signal(signo, pcntl_signal_handler, (int) restart_syscalls) == SIG_ERR) {
891+
PCNTL_G(last_error) = errno;
801892
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error assigning signal");
802893
RETURN_FALSE;
803894
}
@@ -829,6 +920,7 @@ PHP_FUNCTION(pcntl_sigprocmask)
829920
}
830921

831922
if (sigemptyset(&set) != 0 || sigemptyset(&oldset) != 0) {
923+
PCNTL_G(last_error) = errno;
832924
php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno));
833925
RETURN_FALSE;
834926
}
@@ -842,13 +934,15 @@ PHP_FUNCTION(pcntl_sigprocmask)
842934
}
843935
signo = Z_LVAL_PP(user_signo);
844936
if (sigaddset(&set, signo) != 0) {
937+
PCNTL_G(last_error) = errno;
845938
php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno));
846939
RETURN_FALSE;
847940
}
848941
zend_hash_move_forward_ex(Z_ARRVAL_P(user_set), &pos);
849942
}
850943

851944
if (sigprocmask(how, &set, &oldset) != 0) {
945+
PCNTL_G(last_error) = errno;
852946
php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno));
853947
RETURN_FALSE;
854948
}
@@ -895,6 +989,7 @@ static void pcntl_sigwaitinfo(INTERNAL_FUNCTION_PARAMETERS, int timedwait) /* {{
895989
}
896990

897991
if (sigemptyset(&set) != 0) {
992+
PCNTL_G(last_error) = errno;
898993
php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno));
899994
RETURN_FALSE;
900995
}
@@ -908,6 +1003,7 @@ static void pcntl_sigwaitinfo(INTERNAL_FUNCTION_PARAMETERS, int timedwait) /* {{
9081003
}
9091004
signo = Z_LVAL_PP(user_signo);
9101005
if (sigaddset(&set, signo) != 0) {
1006+
PCNTL_G(last_error) = errno;
9111007
php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno));
9121008
RETURN_FALSE;
9131009
}
@@ -922,6 +1018,7 @@ static void pcntl_sigwaitinfo(INTERNAL_FUNCTION_PARAMETERS, int timedwait) /* {{
9221018
signo = sigwaitinfo(&set, &siginfo);
9231019
}
9241020
if (signo == -1 && errno != EAGAIN) {
1021+
PCNTL_G(last_error) = errno;
9251022
php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", strerror(errno));
9261023
}
9271024

@@ -1015,6 +1112,7 @@ PHP_FUNCTION(pcntl_getpriority)
10151112
pri = getpriority(who, pid);
10161113

10171114
if (errno) {
1115+
PCNTL_G(last_error) = errno;
10181116
switch (errno) {
10191117
case ESRCH:
10201118
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error %d: No process was located using the given parameters", errno);
@@ -1048,6 +1146,7 @@ PHP_FUNCTION(pcntl_setpriority)
10481146
}
10491147

10501148
if (setpriority(who, pid, pri)) {
1149+
PCNTL_G(last_error) = errno;
10511150
switch (errno) {
10521151
case ESRCH:
10531152
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error %d: No process was located using the given parameters", errno);
@@ -1073,6 +1172,28 @@ PHP_FUNCTION(pcntl_setpriority)
10731172
/* }}} */
10741173
#endif
10751174

1175+
/* {{{ proto int pcntl_get_last_error(void)
1176+
Retrieve the error number set by the last pcntl function which failed. */
1177+
PHP_FUNCTION(pcntl_get_last_error)
1178+
{
1179+
RETURN_LONG(PCNTL_G(last_error));
1180+
}
1181+
/* }}} */
1182+
1183+
/* {{{ proto string pcntl_strerror(int errno)
1184+
Retrieve the system error message associated with the given errno. */
1185+
PHP_FUNCTION(pcntl_strerror)
1186+
{
1187+
long error;
1188+
1189+
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &error) == FAILURE) {
1190+
RETURN_FALSE;
1191+
}
1192+
1193+
RETURN_STRING(strerror(error), 1);
1194+
}
1195+
/* }}} */
1196+
10761197
/* Our custom signal handler that calls the appropriate php_function */
10771198
static void pcntl_signal_handler(int signo)
10781199
{

ext/pcntl/php_pcntl.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ PHP_FUNCTION(pcntl_wtermsig);
4242
PHP_FUNCTION(pcntl_wstopsig);
4343
PHP_FUNCTION(pcntl_signal);
4444
PHP_FUNCTION(pcntl_signal_dispatch);
45+
PHP_FUNCTION(pcntl_get_last_error);
46+
PHP_FUNCTION(pcntl_strerror);
4547
#ifdef HAVE_SIGPROCMASK
4648
PHP_FUNCTION(pcntl_sigprocmask);
4749
#endif
@@ -66,6 +68,7 @@ ZEND_BEGIN_MODULE_GLOBALS(pcntl)
6668
HashTable php_signal_table;
6769
int processing_signal_queue;
6870
struct php_pcntl_pending_signal *head, *tail, *spares;
71+
int last_error;
6972
ZEND_END_MODULE_GLOBALS(pcntl)
7073

7174
#ifdef ZTS
@@ -74,6 +77,8 @@ ZEND_END_MODULE_GLOBALS(pcntl)
7477
#define PCNTL_G(v) (pcntl_globals.v)
7578
#endif
7679

80+
#define REGISTER_PCNTL_ERRNO_CONSTANT(name) REGISTER_LONG_CONSTANT("PCNTL_" #name, name, CONST_CS | CONST_PERSISTENT)
81+
7782
#endif /* PHP_PCNTL_H */
7883

7984

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
--TEST--
2+
Test pcntl_get_last_error()
3+
--SKIPIF--
4+
<?php
5+
if (!extension_loaded("pcntl")) print "skip";
6+
?>
7+
--FILE--
8+
<?php
9+
var_dump(pcntl_get_last_error());
10+
$pid = pcntl_wait($status);
11+
var_dump($pid);
12+
var_dump(pcntl_get_last_error() == PCNTL_ECHILD);
13+
?>
14+
--EXPECT--
15+
int(0)
16+
int(-1)
17+
bool(true)

0 commit comments

Comments
 (0)