rktio: use only async-signal safe after fork

In particular, `malloc` is not async-signal safe.
This commit is contained in:
Matthew Flatt 2019-06-26 10:00:09 -06:00
parent 0e2805a0db
commit 5e59ae0586
3 changed files with 35 additions and 17 deletions

View File

@ -56,6 +56,7 @@ int rktio_file_lock_try(rktio_t *rktio, rktio_fd_t *rfd, int excl)
if (!pipe(ifds)) {
if (!pipe(ofds)) {
int pid;
int close_len = rktio_close_fds_len();
#ifdef SUBPROCESS_USE_FORK1
pid = fork1();
@ -110,7 +111,7 @@ int rktio_file_lock_try(rktio_t *rktio, rktio_fd_t *rfd, int excl)
rktio_reliably_close(ifds[0]);
rktio_reliably_close(ofds[1]);
rktio_close_fds_after_fork(ifds[1], ofds[0], fd);
rktio_close_fds_after_fork(close_len, ifds[1], ofds[0], fd);
fl.l_start = 0;
fl.l_len = 0;

View File

@ -333,7 +333,8 @@ void *rktio_get_proc_address(HANDLE m, rktio_const_string_t name);
#ifdef RKTIO_SYSTEM_UNIX
int rktio_reliably_close_err(intptr_t s);
void rktio_reliably_close(intptr_t s);
void rktio_close_fds_after_fork(int skip1, int skip2, int skip3);
int rktio_close_fds_len();
void rktio_close_fds_after_fork(int len, int skip1, int skip2, int skip3);
#endif
int rktio_system_fd_is_terminal(rktio_t *rktio, intptr_t fd);

View File

@ -1229,6 +1229,8 @@ rktio_process_result_t *rktio_process(rktio_t *rktio,
#endif
void *env;
rktio_process_t *subproc;
int close_after_len;
rktio_const_string_t *new_argv;
#if defined(RKTIO_SYSTEM_WINDOWS)
intptr_t spawn_status;
#endif
@ -1352,6 +1354,18 @@ rktio_process_result_t *rktio_process(rktio_t *rktio,
init_sigchld(rktio);
#endif
close_after_len = rktio_close_fds_len();
/* add a NULL terminator */
{
int i;
new_argv = malloc(sizeof(char *) * (argc + 1));
for (i = 0; i < argc; i++) {
new_argv[i] = argv[i];
}
new_argv[i] = NULL;
}
#if defined(__QNX__)
pid = vfork();
#elif defined(SUBPROCESS_USE_FORK1)
@ -1360,8 +1374,6 @@ rktio_process_result_t *rktio_process(rktio_t *rktio,
pid = fork();
#endif
if (pid > 0) {
/* This is the original process, which needs to manage the
newly created child process. */
@ -1444,6 +1456,7 @@ rktio_process_result_t *rktio_process(rktio_t *rktio,
if (env)
free(env);
free(new_argv);
return NULL;
@ -1498,7 +1511,7 @@ rktio_process_result_t *rktio_process(rktio_t *rktio,
close_non_standard_fd(err_subprocess[0]);
}
rktio_close_fds_after_fork(0, 1, 2);
rktio_close_fds_after_fork(close_after_len, 0, 1, 2);
}
/* Set real CWD: */
@ -1510,25 +1523,18 @@ rktio_process_result_t *rktio_process(rktio_t *rktio,
/* Exec new process */
{
int err, i;
rktio_const_string_t *new_argv;
/* add a NULL terminator */
new_argv = malloc(sizeof(char *) * (argc + 1));
for (i = 0; i < argc; i++) {
new_argv[i] = argv[i];
}
new_argv[i] = NULL;
int err;
if (!env)
env = rktio_get_environ_array();
err = MSC_IZE(execve)(command, (char **)new_argv, (char **)env);
if (err)
err = errno;
if (env)
free(env);
free(new_argv);
/* If we get here it failed; give up */
@ -1631,11 +1637,12 @@ static void close_non_standard_fd(int fd)
}
}
void rktio_close_fds_after_fork(int skip1, int skip2, int skip3)
int rktio_close_fds_len()
{
int i;
/* These functions are not async-signal safe, so use them before
a fork: */
# ifdef USE_ULIMIT
i = ulimit(4, 0);
# elif defined(__ANDROID__)
@ -1643,6 +1650,15 @@ void rktio_close_fds_after_fork(int skip1, int skip2, int skip3)
# else
i = getdtablesize();
# endif
return i;
}
void rktio_close_fds_after_fork(int i, int skip1, int skip2, int skip3)
{
/* incoming `i` should be the result of `rktio_close_fds_len` before
a fork */
while (i--) {
if ((i != skip1) && (i != skip2) && (i != skip3)) {
rktio_reliably_close(i);