public inbox for libc-alpha@sourceware.org
 help / color / mirror / Atom feed
From: Adhemerval Zanella <adhemerval.zanella@linaro.org>
To: libc-alpha@sourceware.org
Subject: Re: [PATCH 2/3] posix: Use posix_spawn on popen
Date: Fri, 19 Oct 2018 22:08:00 -0000	[thread overview]
Message-ID: <d1e48281-a850-3bb2-2515-10122782a8c8@linaro.org> (raw)
In-Reply-To: <fe5f74ec-d817-2b6b-2b40-fb97c3b025a5@linaro.org>

I also fixed BZ#17490.  Although POSIX pthread_atfork [1] description only
list 'fork' as the function where should issue the atfork handlers and 
popen description [2] states that:

  '[...] shall be *as if* a child process were created within the popen() 
   call using the fork() function [...]' 

Other libc/system seems to follow the idea atfork handlers should not be
issue for popen:

libc/system	| run atfork handles   | notes 
----------------|----------------------|---------------------------------------	
freebsd	master  |        no            | uses vfork
solaris 11	|        no            |
MacOSX (11.13)  |        no            | implemented through posix_spawn syscall
----------------|----------------------|----------------------------------------

And I also agree that, as for posix_spawn and system, popen idea is to spawn 
a different binary so all the POSIX rationale to run the atfork handlers to 
avoid internal process inconsistent are not really required and in some cases
might be unsafe.

[1] http://pubs.opengroup.org/onlinepubs/9699919799/
[2] http://pubs.opengroup.org/onlinepubs/9699919799/

On 17/10/2018 14:11, Adhemerval Zanella wrote:
> Ping.
> 
> On 15/09/2018 12:16, Adhemerval Zanella wrote:
>> This patch uses posix_spawn on popen instead of fork and execl.  On Linux
>> this has the advantage of much lower memory consumption (usually 32 Kb
>> minimum for the mmap stack area).
>>
>> Checked on x86_64-linux-gnu and i686-linux-gnu.
>>
>> 	* libio/iopopen.c (_IO_new_proc_open): use posix_spawn instead of
>> 	fork and execl.
>> ---
>>  ChangeLog       |  3 ++
>>  libio/iopopen.c | 97 +++++++++++++++++++++++++++++--------------------
>>  2 files changed, 61 insertions(+), 39 deletions(-)
>>
>> diff --git a/libio/iopopen.c b/libio/iopopen.c
>> index 2eff45b4c8..3cce2e5596 100644
>> --- a/libio/iopopen.c
>> +++ b/libio/iopopen.c
>> @@ -34,7 +34,8 @@
>>  #include <not-cancel.h>
>>  #include <sys/types.h>
>>  #include <sys/wait.h>
>> -#include <kernel-features.h>
>> +#include <spawn.h>
>> +#include <paths.h>
>>  
>>  struct _IO_proc_file
>>  {
>> @@ -63,9 +64,8 @@ FILE *
>>  _IO_new_proc_open (FILE *fp, const char *command, const char *mode)
>>  {
>>    int read_or_write;
>> -  int parent_end, child_end;
>>    int pipe_fds[2];
>> -  pid_t child_pid;
>> +  int op;
>>  
>>    int do_read = 0;
>>    int do_write = 0;
>> @@ -108,59 +108,78 @@ _IO_new_proc_open (FILE *fp, const char *command, const char *mode)
>>  
>>    if (do_read)
>>      {
>> -      parent_end = pipe_fds[0];
>> -      child_end = pipe_fds[1];
>> +      op = 0;
>>        read_or_write = _IO_NO_WRITES;
>>      }
>>    else
>>      {
>> -      parent_end = pipe_fds[1];
>> -      child_end = pipe_fds[0];
>> +      op = 1;
>>        read_or_write = _IO_NO_READS;
>>      }
>>  
>> -  ((_IO_proc_file *) fp)->pid = child_pid = __fork ();
>> -  if (child_pid == 0)
>> -    {
>> -      int child_std_end = do_read ? 1 : 0;
>> -      struct _IO_proc_file *p;
>> -
>> -      if (child_end != child_std_end)
>> -	__dup2 (child_end, child_std_end);
>> -      else
>> -	/* The descriptor is already the one we will use.  But it must
>> -	   not be marked close-on-exec.  Undo the effects.  */
>> -	__fcntl (child_end, F_SETFD, 0);
>> -      /* POSIX.2:  "popen() shall ensure that any streams from previous
>> -         popen() calls that remain open in the parent process are closed
>> -	 in the new child process." */
>> -      for (p = proc_file_chain; p; p = p->next)
>> -	{
>> -	  int fd = _IO_fileno ((FILE *) p);
>> +  {
>> +    posix_spawn_file_actions_t fa;
>> +    /* posix_spawn_file_actions_init does not fail.  */
>> +    __posix_spawn_file_actions_init (&fa);
>>  
>> -	  /* If any stream from previous popen() calls has fileno
>> -	     child_std_end, it has been already closed by the dup2 syscall
>> -	     above.  */
>> -	  if (fd != child_std_end)
>> -	    __close_nocancel (fd);
>> -	}
>> +    /* The descriptor is already in the one the child will use.  In this case
>> +       it must be moved to another one, otherwise there is no safe way to
>> +       remove the close-on-exec flag in the child without creating a FD leak
>> +       race in the parent.  */
>> +    if (pipe_fds[1 - op] == 1 - op)
>> +      {
>> +	int tmp = __fcntl (1 - op, F_DUPFD_CLOEXEC, 0);
>> +	if (tmp < 0)
>> +	  goto spawn_failure;
>> +	__close_nocancel (pipe_fds[1 - op]);
>> +	pipe_fds[1 - op] = tmp;
>> +      }
>>  
>> -      execl ("/bin/sh", "sh", "-c", command, (char *) 0);
>> -      _exit (127);
>> -    }
>> -  __close_nocancel (child_end);
>> -  if (child_pid < 0)
>> +    if (__posix_spawn_file_actions_adddup2 (&fa, pipe_fds[1 - op], 1 - op)
>> +	!= 0)
>> +      goto spawn_failure;
>> +
>> +    /* POSIX.2: "popen() shall ensure that any streams from previous popen()
>> +       calls that remain open in the parent process are closed in the new
>> +       child process." */
>> +    for (struct _IO_proc_file *p = proc_file_chain; p; p = p->next)
>> +      {
>> +	int fd = _IO_fileno ((FILE *) p);
>> +
>> +	/* If any stream from previous popen() calls has fileno
>> +	   child_send, it has been already closed by the dup2 syscall
>> +	   above.  */
>> +	if (fd != 1 - op
>> +	    && __posix_spawn_file_actions_addclose (&fa, fd) != 0)
>> +	  goto spawn_failure;
>> +      }
>> +
>> +    if (__posix_spawn (&((_IO_proc_file *) fp)->pid, _PATH_BSHELL, &fa, 0,
>> +		     (char *const[]){ (char*) "sh", (char*) "-c",
>> +		     (char *) command, NULL }, __environ) != 0)
>> +      {
>> +      spawn_failure:
>> +	__posix_spawn_file_actions_destroy (&fa);
>> +	__close_nocancel (pipe_fds[1 - op]);
>> +	__set_errno (ENOMEM);
>> +	return NULL;
>> +      }
>> +
>> +    __posix_spawn_file_actions_destroy (&fa);
>> +  }
>> +  __close_nocancel (pipe_fds[1 - op]);
>> +  if (((_IO_proc_file *) fp)->pid < 0)
>>      {
>> -      __close_nocancel (parent_end);
>> +      __close_nocancel (pipe_fds[op]);
>>        return NULL;
>>      }
>>  
>>    if (!do_cloexec)
>>      /* Undo the effects of the pipe2 call which set the
>>         close-on-exec flag.  */
>> -    __fcntl (parent_end, F_SETFD, 0);
>> +    __fcntl (pipe_fds[op], F_SETFD, 0);
>>  
>> -  _IO_fileno (fp) = parent_end;
>> +  _IO_fileno (fp) = pipe_fds[op];
>>  
>>    /* Link into proc_file_chain. */
>>  #ifdef _IO_MTSAFE_IO
>>

  reply	other threads:[~2018-10-19 20:23 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2018-09-15 15:18 [PATCH 1/3] posix: Add internal symbols for posix_spawn interface Adhemerval Zanella
2018-09-15 15:16 ` [PATCH 2/3] posix: Use posix_spawn on popen Adhemerval Zanella
2018-09-16  5:13   ` David Newall
2018-09-17 14:50     ` Rich Felker
2018-09-17 17:32       ` Adhemerval Zanella
2018-09-18  1:31       ` David Newall
2018-09-18  3:12         ` Rich Felker
2018-09-18 18:01     ` Zack Weinberg
2018-09-19  5:18       ` Rich Felker
2018-09-19 15:53         ` Adhemerval Zanella
2018-10-17 17:20   ` Adhemerval Zanella
2018-10-19 22:08     ` Adhemerval Zanella [this message]
2018-09-15 15:18 ` [PATCH 3/3] posix: Use posix_spawn on system Adhemerval Zanella
2018-10-17 20:13   ` Adhemerval Zanella
2018-09-17 12:12 ` [PATCH 1/3] posix: Add internal symbols for posix_spawn interface Florian Weimer
2018-09-17 19:10   ` Adhemerval Zanella
2018-09-21 13:09     ` Florian Weimer
2018-10-17 17:11 ` Adhemerval Zanella

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=d1e48281-a850-3bb2-2515-10122782a8c8@linaro.org \
    --to=adhemerval.zanella@linaro.org \
    --cc=libc-alpha@sourceware.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).