git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
From: Eric Wong <e@80x24.org>
To: Brandon Williams <bmwill@google.com>
Cc: git@vger.kernel.org, jrnieder@gmail.com, Karsten Blees <blees@dcon.de>
Subject: Re: [PATCH v4 05/10] run-command: prepare child environment before forking
Date: Tue, 18 Apr 2017 00:26:52 +0000	[thread overview]
Message-ID: <20170418002651.GA14303@dcvr.yhbt.net> (raw)
In-Reply-To: <20170417220818.44917-6-bmwill@google.com>

+Cc Karsten for comments below...

Brandon Williams <bmwill@google.com> wrote:
> In order to avoid allocation between 'fork()' and 'exec()' prepare the
> environment to be used in the child process prior to forking.
> 
> Switch to using 'execve()' so that the construct child environment can
> used in the exec'd process.
> 
> Signed-off-by: Brandon Williams <bmwill@google.com>
> ---
>  run-command.c | 87 ++++++++++++++++++++++++++++++++++++++++++++++++++++-------
>  1 file changed, 77 insertions(+), 10 deletions(-)
> 
> diff --git a/run-command.c b/run-command.c
> index 1c7a3b611..2fff60a04 100644
> --- a/run-command.c
> +++ b/run-command.c
> @@ -267,6 +267,76 @@ static void prepare_cmd(struct argv_array *out, const struct child_process *cmd)
>  		}
>  	}
>  }
> +
> +static int env_isequal(const char *e1, const char *e2)
> +{
> +	for (;;) {
> +		char c1 = *e1++;
> +		char c2 = *e2++;
> +		c1 = (c1 == '=') ? '\0' : tolower(c1);
> +		c2 = (c2 == '=') ? '\0' : tolower(c2);

Dealing with C strings scares me so maybe I'm misreading;
but: why is this comparison case-insensitive?

Reading on...

> +
> +		if (c1 != c2)
> +			return 0;
> +		if (c1 == '\0')
> +			return 1;
> +	}
> +}
> +
> +static int searchenv(char **env, const char *name)
> +{
> +	int pos = 0;
> +
> +	for (; env[pos]; pos++)
> +		if (env_isequal(env[pos], name))
> +			break;
> +
> +	return pos;
> +}

So this scans through every string in env looking for something
that matches 'name' followed by a '=', and return the position
of that in env so do_putenv below can use it:

> +
> +static int do_putenv(char **env, int env_nr, const char *name)
> +{
> +	int pos = searchenv(env, name);
> +
> +	if (strchr(name, '=')) {
> +		/* ('key=value'), insert of replace entry */

		"insert or replace"

> +		if (pos >= env_nr)
> +			env_nr++;
> +		env[pos] = (char *) name;

OK, this sets an entry...

> +	} else if (pos < env_nr) {
> +		/* otherwise ('key') remove existing entry */
> +		env_nr--;
> +		memmove(&env[pos], &env[pos + 1],
> +			(env_nr - pos) * sizeof(char *));
> +		env[env_nr] = NULL;

And this clobbers it, freeing up a slot for future sets and
tells the caller by returning env_nr below:

> +	}
> +
> +	return env_nr;
> +}

So now the caller below will know where there's a free slot
to place the next environment variable:

> +static char **prep_childenv(const char *const *deltaenv)
> +{
> +	extern char **environ;
> +	char **childenv;
> +	int childenv_nr = 0, childenv_alloc = 0;
> +	int i;
> +
> +	for (i = 0; environ[i]; i++)
> +		childenv_nr++;
> +	for (i = 0; deltaenv && deltaenv[i]; i++)
> +		childenv_alloc++;
> +	/* Add one for the NULL termination */
> +	childenv_alloc += childenv_nr + 1;
> +
> +	childenv = xcalloc(childenv_alloc, sizeof(char *));
> +	memcpy(childenv, environ, childenv_nr * sizeof(char *));
> +
> +	/* merge in deltaenv */
> +	for (i = 0; deltaenv && deltaenv[i]; i++)
> +		childenv_nr = do_putenv(childenv, childenv_nr, deltaenv[i]);
> +
> +	return childenv;
> +}

OK, the above seems to make sense; copy parent environment and
then make changes from deltaenv on top of it...

>  #endif
>  
>  static inline void set_cloexec(int fd)
> @@ -395,12 +465,14 @@ int start_command(struct child_process *cmd)
>  #ifndef GIT_WINDOWS_NATIVE
>  {
>  	int notify_pipe[2];
> +	char **childenv;
>  	struct argv_array argv = ARGV_ARRAY_INIT;
>  
>  	if (pipe(notify_pipe))
>  		notify_pipe[0] = notify_pipe[1] = -1;
>  
>  	prepare_cmd(&argv, cmd);
> +	childenv = prep_childenv(cmd->env);
>  
>  	cmd->pid = fork();
>  	failed_errno = errno;
> @@ -456,14 +528,6 @@ int start_command(struct child_process *cmd)
>  		if (cmd->dir && chdir(cmd->dir))
>  			die_errno("exec '%s': cd to '%s' failed", cmd->argv[0],
>  			    cmd->dir);
> -		if (cmd->env) {
> -			for (; *cmd->env; cmd->env++) {
> -				if (strchr(*cmd->env, '='))
> -					putenv((char *)*cmd->env);
> -				else
> -					unsetenv(*cmd->env);
> -			}
> -		}

... which was what the original code did inside the forked child.

So, everything above made sense to me except the use of tolower.

So it looks like Brandon is reusing some of Karsten's
compat/mingw.c changes in
commit 343ff06da7d83f40892b10a3b653c7d0e6cb526c,
("Win32: keep the environment sorted")

But, since these changes to run-command are *nix only,
the sorting the env makes no sense, and neither
does case-insensitivity.

However, reading Karsten's commit; it only seems the use
of case-insensitive qsort is correct.  I'm not sure
if mingw is case-insensitive for actual env modifications,
but I know *nix env names are case-sensitive.

So, there _may_ be a bug in compat/mingw.c with the use
of bsearchenv and compareenv.  It does not seem bsearch
is correct to use there, nor can a case-insensitive
compareenv be used for searching, only sorting...

  reply	other threads:[~2017-04-18  0:26 UTC|newest]

Thread overview: 140+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2017-04-10 23:49 [PATCH 0/5] forking and threading Brandon Williams
2017-04-10 23:49 ` [PATCH 1/5] run-command: convert sane_execvp to sane_execvpe Brandon Williams
2017-04-12 19:22   ` Brandon Williams
2017-04-10 23:49 ` [PATCH 2/5] run-command: prepare argv before forking Brandon Williams
2017-04-10 23:49 ` [PATCH 3/5] run-command: allocate child_err " Brandon Williams
2017-04-10 23:49 ` [PATCH 4/5] run-command: prepare child environment " Brandon Williams
2017-04-11  0:58   ` Jonathan Nieder
2017-04-11 17:27     ` Brandon Williams
2017-04-11 17:30       ` Jonathan Nieder
2017-04-10 23:49 ` [PATCH 5/5] run-command: add note about forking and threading Brandon Williams
2017-04-11  0:26   ` Jonathan Nieder
2017-04-11  0:53     ` Eric Wong
2017-04-11 17:33       ` Jonathan Nieder
2017-04-11 17:34       ` Brandon Williams
2017-04-11 17:40         ` Eric Wong
2017-04-11  7:05 ` [PATCH 6/5] run-command: avoid potential dangers in forked child Eric Wong
2017-04-11 16:29   ` Brandon Williams
2017-04-11 16:59     ` Eric Wong
2017-04-11 17:17       ` Brandon Williams
2017-04-11 17:37 ` [PATCH 0/5] forking and threading Jonathan Nieder
2017-04-11 17:54   ` Brandon Williams
2017-04-13 18:32 ` [PATCH v2 0/6] " Brandon Williams
2017-04-13 18:32   ` [PATCH v2 1/6] t5550: use write_script to generate post-update hook Brandon Williams
2017-04-13 20:43     ` Jonathan Nieder
2017-04-13 20:59       ` Eric Wong
2017-04-13 21:35         ` Brandon Williams
2017-04-13 21:39           ` Eric Wong
2017-04-13 18:32   ` [PATCH v2 2/6] run-command: prepare command before forking Brandon Williams
2017-04-13 21:14     ` Jonathan Nieder
2017-04-13 22:41       ` Brandon Williams
2017-04-13 18:32   ` [PATCH v2 3/6] run-command: prepare child environment " Brandon Williams
2017-04-13 18:32   ` [PATCH v2 4/6] run-command: don't die in child when duping /dev/null Brandon Williams
2017-04-13 19:29     ` Eric Wong
2017-04-13 19:43       ` Brandon Williams
2017-04-13 18:32   ` [PATCH v2 5/6] run-command: eliminate calls to error handling functions in child Brandon Williams
2017-04-13 18:32   ` [PATCH v2 6/6] run-command: add note about forking and threading Brandon Williams
2017-04-13 20:50   ` [PATCH v2 0/6] " Jonathan Nieder
2017-04-13 23:44     ` Brandon Williams
2017-04-13 21:14   ` [PATCH 7/6] run-command: block signals between fork and execve Eric Wong
2017-04-13 23:37     ` Brandon Williams
2017-04-14  2:42     ` Brandon Williams
2017-04-14  5:26       ` Eric Wong
2017-04-14  5:35         ` Eric Wong
2017-04-14 16:58   ` [PATCH v3 00/10] forking and threading Brandon Williams
2017-04-14 16:58     ` [PATCH v3 01/10] t5550: use write_script to generate post-update hook Brandon Williams
2017-04-14 16:58     ` [PATCH v3 02/10] t0061: run_command executes scripts without a #! line Brandon Williams
2017-04-14 16:58     ` [PATCH v3 03/10] run-command: prepare command before forking Brandon Williams
2017-04-14 16:58     ` [PATCH v3 04/10] run-command: use the async-signal-safe execv instead of execvp Brandon Williams
2017-04-14 16:58     ` [PATCH v3 05/10] run-command: prepare child environment before forking Brandon Williams
2017-04-14 16:58     ` [PATCH v3 06/10] run-command: don't die in child when duping /dev/null Brandon Williams
2017-04-14 19:38       ` Eric Wong
2017-04-14 20:19         ` Brandon Williams
2017-04-14 16:58     ` [PATCH v3 07/10] run-command: eliminate calls to error handling functions in child Brandon Williams
2017-04-14 18:50       ` Eric Wong
2017-04-14 20:22         ` Brandon Williams
2017-04-14 16:59     ` [PATCH v3 08/10] run-command: handle dup2 and close errors " Brandon Williams
2017-04-14 16:59     ` [PATCH v3 09/10] run-command: add note about forking and threading Brandon Williams
2017-04-14 16:59     ` [PATCH v3 10/10] run-command: block signals between fork and execve Brandon Williams
2017-04-14 20:24       ` Brandon Williams
2017-04-14 21:35         ` Eric Wong
2017-04-17 22:08     ` [PATCH v4 00/10] forking and threading Brandon Williams
2017-04-17 22:08       ` [PATCH v4 01/10] t5550: use write_script to generate post-update hook Brandon Williams
2017-04-17 22:08       ` [PATCH v4 02/10] t0061: run_command executes scripts without a #! line Brandon Williams
2017-04-17 22:08       ` [PATCH v4 03/10] run-command: prepare command before forking Brandon Williams
2017-04-17 22:08       ` [PATCH v4 04/10] run-command: use the async-signal-safe execv instead of execvp Brandon Williams
2017-04-17 22:08       ` [PATCH v4 05/10] run-command: prepare child environment before forking Brandon Williams
2017-04-18  0:26         ` Eric Wong [this message]
2017-04-18 21:02           ` Brandon Williams
2017-04-17 22:08       ` [PATCH v4 06/10] run-command: don't die in child when duping /dev/null Brandon Williams
2017-04-17 22:08       ` [PATCH v4 07/10] run-command: eliminate calls to error handling functions in child Brandon Williams
2017-04-17 22:08       ` [PATCH v4 08/10] run-command: handle dup2 and close errors " Brandon Williams
2017-04-17 22:08       ` [PATCH v4 09/10] run-command: add note about forking and threading Brandon Williams
2017-04-17 22:08       ` [PATCH v4 10/10] run-command: block signals between fork and execve Brandon Williams
2017-04-18 23:17       ` [PATCH v5 00/11] forking and threading Brandon Williams
2017-04-18 23:17         ` [PATCH v5 01/11] t5550: use write_script to generate post-update hook Brandon Williams
2017-04-18 23:17         ` [PATCH v5 02/11] t0061: run_command executes scripts without a #! line Brandon Williams
2017-04-19  5:43           ` Johannes Sixt
2017-04-19  6:21             ` Johannes Sixt
2017-04-19 15:56               ` Brandon Williams
2017-04-19 18:18                 ` Johannes Sixt
2017-04-20 10:47                 ` Johannes Schindelin
2017-04-20 17:02                   ` Brandon Williams
2017-04-20 20:24                     ` Johannes Schindelin
2017-04-20 20:49                       ` Brandon Williams
2017-04-18 23:17         ` [PATCH v5 03/11] run-command: prepare command before forking Brandon Williams
2017-04-18 23:17         ` [PATCH v5 04/11] run-command: use the async-signal-safe execv instead of execvp Brandon Williams
2017-04-18 23:17         ` [PATCH v5 05/11] string-list: add string_list_remove function Brandon Williams
2017-04-18 23:31           ` Stefan Beller
2017-04-18 23:36             ` Brandon Williams
2017-04-18 23:40               ` Stefan Beller
2017-04-18 23:18         ` [PATCH v5 06/11] run-command: prepare child environment before forking Brandon Williams
2017-04-18 23:18         ` [PATCH v5 07/11] run-command: don't die in child when duping /dev/null Brandon Williams
2017-04-18 23:18         ` [PATCH v5 08/11] run-command: eliminate calls to error handling functions in child Brandon Williams
2017-04-18 23:18         ` [PATCH v5 09/11] run-command: handle dup2 and close errors " Brandon Williams
2017-04-18 23:18         ` [PATCH v5 10/11] run-command: add note about forking and threading Brandon Williams
2017-04-18 23:18         ` [PATCH v5 11/11] run-command: block signals between fork and execve Brandon Williams
2017-04-19  6:00           ` Johannes Sixt
2017-04-19  7:48             ` Eric Wong
2017-04-19 16:10               ` Brandon Williams
2017-04-19 23:13         ` [PATCH v6 00/11] forking and threading Brandon Williams
2017-04-19 23:13           ` [PATCH v6 01/11] t5550: use write_script to generate post-update hook Brandon Williams
2017-04-19 23:13           ` [PATCH v6 02/11] t0061: run_command executes scripts without a #! line Brandon Williams
2017-04-20 10:49             ` Johannes Schindelin
2017-04-20 16:58               ` Brandon Williams
2017-04-19 23:13           ` [PATCH v6 03/11] run-command: prepare command before forking Brandon Williams
2017-04-19 23:13           ` [PATCH v6 04/11] run-command: use the async-signal-safe execv instead of execvp Brandon Williams
2017-05-17  2:15             ` Junio C Hamano
2017-05-17  2:26               ` Jeff King
2017-05-17  2:28                 ` Jeff King
2017-05-17  3:41                 ` Junio C Hamano
2017-05-17 14:52                 ` Brandon Williams
2017-04-19 23:13           ` [PATCH v6 05/11] string-list: add string_list_remove function Brandon Williams
2017-04-19 23:13           ` [PATCH v6 06/11] run-command: prepare child environment before forking Brandon Williams
2017-04-19 23:13           ` [PATCH v6 07/11] run-command: don't die in child when duping /dev/null Brandon Williams
2017-04-19 23:13           ` [PATCH v6 08/11] run-command: eliminate calls to error handling functions in child Brandon Williams
2017-04-19 23:13           ` [PATCH v6 09/11] run-command: handle dup2 and close errors " Brandon Williams
2017-04-19 23:13           ` [PATCH v6 10/11] run-command: add note about forking and threading Brandon Williams
2017-04-19 23:13           ` [PATCH v6 11/11] run-command: block signals between fork and execve Brandon Williams
2017-04-24 22:37           ` [PATCH v6 00/11] forking and threading Brandon Williams
2017-04-24 23:50             ` [PATCH v6 12/11] run-command: don't try to execute directories Brandon Williams
2017-04-25  0:17               ` Jonathan Nieder
2017-04-25  1:58                 ` Junio C Hamano
2017-04-25  2:51                   ` Jonathan Nieder
2017-04-25  2:56                 ` Jeff King
2017-04-25  1:47               ` Junio C Hamano
2017-04-25  2:57               ` Jonathan Nieder
2017-04-25 17:54               ` [PATCH v7 1/2] exec_cmd: expose is_executable function Brandon Williams
2017-04-25 17:54                 ` [PATCH v7 2/2] run-command: don't try to execute directories Brandon Williams
2017-04-25 18:51                   ` Jonathan Nieder
2017-04-25 19:32                     ` Brandon Williams
2017-04-25 18:04                 ` [PATCH v7 1/2] exec_cmd: expose is_executable function Jonathan Nieder
2017-04-25 18:18                 ` Johannes Sixt
2017-04-25 18:38                   ` Brandon Williams
2017-04-25 23:46                 ` [PATCH v8 1/2] run-command: " Brandon Williams
2017-04-25 23:47                   ` [PATCH v8 2/2] run-command: restrict PATH search to executable files Brandon Williams
2017-04-25 23:50                     ` Jonathan Nieder
2017-04-26  1:44                     ` Junio C Hamano
2017-04-26 17:10                       ` [PATCH v9 " Brandon Williams
2017-04-27  0:33                         ` Junio C Hamano
2017-04-25 23:48                   ` [PATCH v8 1/2] run-command: expose is_executable function Jonathan Nieder

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

  List information: http://vger.kernel.org/majordomo-info.html

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

  git send-email \
    --in-reply-to=20170418002651.GA14303@dcvr.yhbt.net \
    --to=e@80x24.org \
    --cc=blees@dcon.de \
    --cc=bmwill@google.com \
    --cc=git@vger.kernel.org \
    --cc=jrnieder@gmail.com \
    /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.
Code repositories for project(s) associated with this public inbox

	https://80x24.org/mirrors/git.git

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).