Skip to content

Use posix_spawn for proc_open when supported by OS #7933

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 1 commit into from
Closed
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
2 changes: 2 additions & 0 deletions ext/standard/config.m4
Original file line number Diff line number Diff line change
Expand Up @@ -376,6 +376,8 @@ dnl

PHP_CHECK_FUNC(res_search, resolv, bind, socket)

PHP_CHECK_FUNC(posix_spawn_file_actions_addchdir_np)

dnl
dnl Check for strptime()
dnl
Expand Down
74 changes: 74 additions & 0 deletions ext/standard/proc_open.c
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,18 @@
#include <fcntl.h>
#endif

#ifdef HAVE_POSIX_SPAWN_FILE_ACTIONS_ADDCHDIR_NP
/* Only defined on glibc >= 2.29, FreeBSD CURRENT, musl >= 1.1.24,
* MacOS Catalina or later..
* It should be posible to modify this so it is also
* used in older systems when $cwd == NULL but care must be taken
* as at least glibc < 2.24 has a legacy implementation known
* to be really buggy.
*/
#include <spawn.h>
#define USE_POSIX_SPAWN
#endif

/* This symbol is defined in ext/standard/config.m4.
* Essentially, it is set if you HAVE_FORK || PHP_WIN32
* Other platforms may modify that configure check and add suitable #ifdefs
Expand Down Expand Up @@ -982,6 +994,36 @@ static zend_result set_proc_descriptor_from_resource(zval *resource, descriptors
}

#ifndef PHP_WIN32
#if defined(USE_POSIX_SPAWN)
static zend_result close_parentends_of_pipes(posix_spawn_file_actions_t * actions, descriptorspec_item *descriptors, int ndesc)
{
int r;
for (int i = 0; i < ndesc; i++) {
if (descriptors[i].type != DESCRIPTOR_TYPE_STD) {
r = posix_spawn_file_actions_addclose(actions, descriptors[i].parentend);
if (r != 0) {
php_error_docref(NULL, E_WARNING, "Cannot close file descriptor %d: %s", descriptors[i].parentend, strerror(r));
return FAILURE;
}
}
if (descriptors[i].childend != descriptors[i].index) {
r = posix_spawn_file_actions_adddup2(actions, descriptors[i].childend, descriptors[i].index);
if (r != 0) {
php_error_docref(NULL, E_WARNING, "Unable to copy file descriptor %d (for pipe) into "
"file descriptor %d: %s", descriptors[i].childend, descriptors[i].index, strerror(r));
return FAILURE;
}
r = posix_spawn_file_actions_addclose(actions, descriptors[i].childend);
if (r != 0) {
php_error_docref(NULL, E_WARNING, "Cannot close file descriptor %d: %s", descriptors[i].childend, strerror(r));
return FAILURE;
}
}
}

return SUCCESS;
}
#else
static zend_result close_parentends_of_pipes(descriptorspec_item *descriptors, int ndesc)
{
/* We are running in child process
Expand All @@ -1005,6 +1047,7 @@ static zend_result close_parentends_of_pipes(descriptorspec_item *descriptors, i
return SUCCESS;
}
#endif
#endif

static void close_all_descriptors(descriptorspec_item *descriptors, int ndesc)
{
Expand Down Expand Up @@ -1216,6 +1259,37 @@ PHP_FUNCTION(proc_open)
childHandle = pi.hProcess;
child = pi.dwProcessId;
CloseHandle(pi.hThread);
#elif defined(USE_POSIX_SPAWN)
posix_spawn_file_actions_t factions;
int r;
posix_spawn_file_actions_init(&factions);

if (close_parentends_of_pipes(&factions, descriptors, ndesc) == FAILURE) {
posix_spawn_file_actions_destroy(&factions);
close_all_descriptors(descriptors, ndesc);
goto exit_fail;
}

if (cwd) {
r = posix_spawn_file_actions_addchdir_np(&factions, cwd);
if (r != 0) {
php_error_docref(NULL, E_WARNING, "posix_spawn_file_actions_addchdir_np() failed: %s", strerror(r));
}
}

if (argv) {
r = posix_spawnp(&child, ZSTR_VAL(command_str), &factions, NULL, argv, (env.envarray ? env.envarray : environ));
} else {
r = posix_spawn(&child, "/bin/sh" , &factions, NULL,
(char * const[]) {"sh", "-c", ZSTR_VAL(command_str), NULL},
env.envarray ? env.envarray : environ);
}
posix_spawn_file_actions_destroy(&factions);
if (r != 0) {
close_all_descriptors(descriptors, ndesc);
php_error_docref(NULL, E_WARNING, "posix_spawn() failed: %s", strerror(r));
goto exit_fail;
}
#elif HAVE_FORK
/* the Unix way */
child = fork();
Expand Down