This is the mail archive of the
libc-alpha@sourceware.org
mailing list for the glibc project.
Re: [PATCH 2/3] posix: Improve default posix_spawn implementation
- From: Adhemerval Zanella <adhemerval dot zanella at linaro dot org>
- To: Andreas Schwab <schwab at suse dot de>
- Cc: libc-alpha at sourceware dot org
- Date: Thu, 29 Jun 2017 12:01:18 -0300
- Subject: Re: [PATCH 2/3] posix: Improve default posix_spawn implementation
- Authentication-results: sourceware.org; auth=none
- References: <1494876985-21990-1-git-send-email-adhemerval.zanella@linaro.org> <1494876985-21990-2-git-send-email-adhemerval.zanella@linaro.org> <mvm7ezulvqi.fsf@suse.de>
On 29/06/2017 11:22, Andreas Schwab wrote:
> On Mai 15 2017, Adhemerval Zanella <adhemerval.zanella@linaro.org> wrote:
>
>> + if ((ret = close_not_cancel (new_fd) != 0))
>
> This assigns the wrong value to ret.
Ugh, this should not be here...
>
>> +fail:
>> + /* Since sizeof errno < PIPE_BUF, the write is atomic. */
>> + ret = -ret;
>
> posix_spwan is supposed to return errno, but none of the arms going here
> set ret appropriately.
Fixed below.
>
>> + /* Generate the new process. */
>> + pid_t new_pid = __fork ();
>> +
>> + if (new_pid == 0)
>> + __spawni_child (&args);
>> + else if (new_pid > 0)
>> + {
>> + __close (args.pipe[1]);
>> +
>> + if (__read (args.pipe[0], &ec, sizeof ec) != sizeof ec)
>> + ec = 0;
>> + else
>> + __waitpid (new_pid, &(int) { 0 }, 0);
>> }
>> - while (*p++ != '\0');
>> + else
>> + ec = -new_pid;
>
> new_pid isn't an errno either.
Since posix_spawn is not support to set errno in case of failure we will
need to save/restore for fork call. And this should be fixed on Linux
implementation as well since clone will also clobber errno in case of
an error (I will send a fix).
Ideally I think the exported clone should not set errno and just return
errno as a negative number.
>
> Andreas.
>
I intended to push this change:
diff --git a/sysdeps/posix/spawni.c b/sysdeps/posix/spawni.c
index 1979830..93767a2 100644
--- a/sysdeps/posix/spawni.c
+++ b/sysdeps/posix/spawni.c
@@ -117,30 +117,30 @@ __spawni_child (void *arguments)
if ((attr->__flags & (POSIX_SPAWN_SETSCHEDPARAM | POSIX_SPAWN_SETSCHEDULER))
== POSIX_SPAWN_SETSCHEDPARAM)
{
- if ((ret = __sched_setparam (0, &attr->__sp)) == -1)
+ if (__sched_setparam (0, &attr->__sp) == -1)
goto fail;
}
else if ((attr->__flags & POSIX_SPAWN_SETSCHEDULER) != 0)
{
- if ((ret = __sched_setscheduler (0, attr->__policy, &attr->__sp) == -1))
+ if (__sched_setscheduler (0, attr->__policy, &attr->__sp) == -1)
goto fail;
}
#endif
/* Set the process session ID. */
if ((attr->__flags & POSIX_SPAWN_SETSID) != 0
- && (ret = __setsid ()) < 0)
+ && __setsid () < 0)
goto fail;
/* Set the process group ID. */
if ((attr->__flags & POSIX_SPAWN_SETPGROUP) != 0
- && (ret =__setpgid (0, attr->__pgrp)) != 0)
+ && __setpgid (0, attr->__pgrp) != 0)
goto fail;
/* Set the effective user and group IDs. */
if ((attr->__flags & POSIX_SPAWN_RESETIDS) != 0
- && ((ret = local_seteuid (__getuid ())) != 0
- || (ret = local_setegid (__getgid ())) != 0))
+ && (local_seteuid (__getuid ()) != 0
+ || local_setegid (__getgid ())) != 0)
goto fail;
/* Execute the file actions. */
@@ -168,10 +168,7 @@ __spawni_child (void *arguments)
/* Only signal errors for file descriptors out of range. */
if (action->action.close_action.fd < 0
|| action->action.close_action.fd >= fdlimit.rlim_cur)
- {
- ret = -1;
- goto fail;
- }
+ goto fail;
}
break;
@@ -190,25 +187,25 @@ __spawni_child (void *arguments)
| O_LARGEFILE,
action->action.open_action.mode);
- if ((ret = new_fd) == -1)
+ if (new_fd == -1)
goto fail;
/* Make sure the desired file descriptor is used. */
if (new_fd != action->action.open_action.fd)
{
- if ((ret = __dup2 (new_fd, action->action.open_action.fd))
+ if (__dup2 (new_fd, action->action.open_action.fd)
!= action->action.open_action.fd)
goto fail;
- if ((ret = close_not_cancel (new_fd) != 0))
+ if (close_not_cancel (new_fd) != 0)
goto fail;
}
}
break;
case spawn_do_dup2:
- if ((ret = __dup2 (action->action.dup2_action.fd,
- action->action.dup2_action.newfd))
+ if (__dup2 (action->action.dup2_action.fd,
+ action->action.dup2_action.newfd)
!= action->action.dup2_action.newfd)
goto fail;
break;
@@ -228,12 +225,15 @@ __spawni_child (void *arguments)
(2.15). */
maybe_script_execute (args);
- ret = -errno;
-
fail:
- /* Since sizeof errno < PIPE_BUF, the write is atomic. */
- ret = -ret;
+ /* errno should have an appropriate non-zero value; otherwise,
+ there's a bug in glibc or the kernel. For lack of an error code
+ (EINTERNALBUG) describing that, use ECHILD. Another option would
+ be to set args->err to some negative sentinel and have the parent
+ abort(), but that seems needlessly harsh. */
+ ret = errno ? : ECHILD;
if (ret)
+ /* Since sizeof errno < PIPE_BUF, the write is atomic. */
while (write_not_cancel (args->pipe[1], &ret, sizeof (ret)) < 0);
_exit (SPAWN_ERROR);
@@ -278,6 +278,7 @@ __spawnix (pid_t *pid, const char *file,
args.xflags = xflags;
/* Generate the new process. */
+ int old_errno = errno;
pid_t new_pid = __fork ();
if (new_pid == 0)
@@ -292,7 +293,8 @@ __spawnix (pid_t *pid, const char *file,
__waitpid (new_pid, &(int) { 0 }, 0);
}
else
- ec = -new_pid;
+ ec = errno;
+ errno = old_errno;
__close (args.pipe[0]);