git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: "D. Ben Knoble" <ben.knoble+github@gmail.com>
To: git@vger.kernel.org
Cc: "D. Ben Knoble" <ben.knoble+github@gmail.com>,
	"Johannes Schindelin" <johannes.schindelin@gmx.de>,
	"Johannes Schindelin" <Johannes.Schindelin@gmx.de>,
	"Junio C Hamano" <gitster@pobox.com>,
	"Ævar Arnfjörð Bjarmason" <avarab@gmail.com>
Subject: [PATCH 4/4] drop git_exec_path() from non-Git commands' PATH
Date: Tue, 20 May 2025 15:34:58 -0400	[thread overview]
Message-ID: <20250520193506.95199-5-ben.knoble+github@gmail.com> (raw)
In-Reply-To: <20250520193506.95199-1-ben.knoble+github@gmail.com>

We setup_path() with git_exec_path() unconditionally (8e3462837b (Modify
setup_path() to only add git_exec_path() to PATH, 2009-01-18)) when Git
starts; as a result, all child processes see Git's exec-path when run,
including editors and other programs that don't need it [1]. This can
cause confusion for such programs or shells, especially when they rely
on finding "git" in PATH to locate other nearby directories, in a
similar vein as a0b4507ef7 (stop putting argv[0] dirname at front of
PATH, 2015-04-22) solved.

Since we only need this for finding git-* subprocesses, drop it from
child processes that aren't Git commands.

[1]: https://public-inbox.org/git/CALnO6CDtGRRav8zK2GKi1oHTZWrHFTxZNmnOWu64-ab+oY3_Lw@mail.gmail.com/

Signed-off-by: D. Ben Knoble <ben.knoble+github@gmail.com>
Suggested-by: Johannes Schindelin <johannes.schindelin@gmx.de>
---

Notes:
    A few interesting points:
    
    - I'm not sure how best to deal with the memory leak here.
    - Dscho suggested the essence of the patch in
      https://github.com/git-for-windows/build-extra/pull/616#pullrequestreview-2839055049,
      for the curious. My only major tweaks were this diff to skip past
      "PATH=" when searching for the matching path (but still modify the
      original buffer; b always points into buf.buf, so the later operations
      with p and buf.buf are valid).
    
    --->8---
    diff --git i/run-command.c w/run-command.c
    index b567e4fdd5..8a8b5c8455 100644
    --- i/run-command.c
    +++ w/run-command.c
    @@ -452,17 +452,24 @@ static void remove_git_exec_path(struct string_list_item *path_item) {
    	struct strbuf buf = STRBUF_INIT;
    	const char *exec_path = git_exec_path();
    	size_t exec_len = strlen(exec_path);
    -	char *p;
    +	char *b, *p;
    
    	/* Value comes from environ; we should not modify it directly. But
    	 * strbuf copies data, so we now have our own playground. */
    	strbuf_addstr(&buf, (const char *)path_item->util);
    -	for (p = strstr(buf.buf, exec_path); p; p = strstr(p, exec_path)) {
    -		if ((p[exec_len] && p[exec_len] != PATH_SEP) || (p != buf.buf && p[-1] != PATH_SEP))
    +
    +	/* skip past "PATH=" to start search */
    +	p = strchr(buf.buf, '=');
    +	if (!p || !*(p + 1))
    +		return;
    +	b = p + 1;
    +
    +	for (p = strstr(b, exec_path); p; p = strstr(p, exec_path)) {
    +		if ((p[exec_len] && p[exec_len] != PATH_SEP) || (p != b && p[-1] != PATH_SEP))
    			p += exec_len; /* false positive, skip */
    		else {
    			size_t offset = p - buf.buf, delete_len = exec_len;
    -			if (p != buf.buf) {
    +			if (p != b) {
    				/* include the preceding path separator */
    				offset--;
    				delete_len++;
    --->8---
    
    - I /think/ this resolves the issues in my earlier mail beyond just Git
      builtins; for example, git-jump also doesn't get exec-path because
      it's not invoked with git_cmd set during execv_dashed_external.

 run-command.c     | 47 +++++++++++++++++++++++++++++++++++++++++++++--
 t/t7005-editor.sh | 13 +++++++++++++
 2 files changed, 58 insertions(+), 2 deletions(-)

diff --git a/run-command.c b/run-command.c
index dee6ae3e62..8a8b5c8455 100644
--- a/run-command.c
+++ b/run-command.c
@@ -448,11 +448,51 @@ static int prepare_cmd(struct strvec *out, const struct child_process *cmd)
 	return 0;
 }
 
-static char **prep_childenv(const char *const *deltaenv)
+static void remove_git_exec_path(struct string_list_item *path_item) {
+	struct strbuf buf = STRBUF_INIT;
+	const char *exec_path = git_exec_path();
+	size_t exec_len = strlen(exec_path);
+	char *b, *p;
+
+	/* Value comes from environ; we should not modify it directly. But
+	 * strbuf copies data, so we now have our own playground. */
+	strbuf_addstr(&buf, (const char *)path_item->util);
+
+	/* skip past "PATH=" to start search */
+	p = strchr(buf.buf, '=');
+	if (!p || !*(p + 1))
+		return;
+	b = p + 1;
+
+	for (p = strstr(b, exec_path); p; p = strstr(p, exec_path)) {
+		if ((p[exec_len] && p[exec_len] != PATH_SEP) || (p != b && p[-1] != PATH_SEP))
+			p += exec_len; /* false positive, skip */
+		else {
+			size_t offset = p - buf.buf, delete_len = exec_len;
+			if (p != b) {
+				/* include the preceding path separator */
+				offset--;
+				delete_len++;
+			} else if (p[exec_len] == PATH_SEP) {
+				/* include the path separator following GIT_EXEC_PATH */
+				delete_len++;
+			}
+			strbuf_splice(&buf, offset, delete_len, "", 0);
+		}
+	}
+
+	/* Overwrite PATH value with new (owned) data. This leaks memory because
+	 * the only future owner is a char** childenv, which is freed, but whose
+	 * contents are not (because most of them come from environ). */
+	path_item->util = (void *)strbuf_detach(&buf, NULL);
+}
+
+static char **prep_childenv(const char *const *deltaenv, unsigned git_cmd)
 {
 	extern char **environ;
 	char **childenv;
 	struct string_list env = STRING_LIST_INIT_DUP;
+	struct string_list_item *path_item;
 	struct strbuf key = STRBUF_INIT;
 	const char *const *p;
 	int i;
@@ -486,6 +526,9 @@ static char **prep_childenv(const char *const *deltaenv)
 		}
 	}
 
+	if (!git_cmd && (path_item = string_list_lookup(&env, "PATH")))
+		remove_git_exec_path(path_item);
+
 	/* Create an array of 'char *' to be used as the childenv */
 	ALLOC_ARRAY(childenv, env.nr + 1);
 	for (i = 0; i < env.nr; i++)
@@ -746,7 +789,7 @@ int start_command(struct child_process *cmd)
 	if (cmd->close_object_store)
 		close_object_store(the_repository->objects);
 
-	childenv = prep_childenv(cmd->env.v);
+	childenv = prep_childenv(cmd->env.v, cmd->git_cmd);
 
 #ifndef GIT_WINDOWS_NATIVE
 {
diff --git a/t/t7005-editor.sh b/t/t7005-editor.sh
index 06fa1ecd91..560e500b53 100755
--- a/t/t7005-editor.sh
+++ b/t/t7005-editor.sh
@@ -127,4 +127,17 @@
 	test space = "$(git show -s --pretty=format:%s)"
 '
 
+test_expect_success 'editor does not see GIT_EXEC_PATH on PATH' '
+	cat >e-path <<-EOF &&
+	#!$SHELL_PATH
+	echo "\$PATH" | tr : "\\n" >actual
+	EOF
+	chmod +x e-path &&
+	(
+		test_set_editor ./e-path &&
+		git commit --amend
+	) &&
+	test_grep ! ^"$(git --exec-path)"\$ actual
+'
+
 test_done
-- 
2.48.1


  parent reply	other threads:[~2025-05-20 19:36 UTC|newest]

Thread overview: 73+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-05-20 19:34 [PATCH 0/4] Drop git-exec-path from non-Git child programs D. Ben Knoble
2025-05-20 19:34 ` [PATCH 1/4] t7005: sanitize test environment for subsequent tests D. Ben Knoble
2025-05-21  7:56   ` Patrick Steinhardt
2025-05-21 13:23     ` D. Ben Knoble
2025-05-20 19:34 ` [PATCH 2/4] editor: use standard strvec API to receive environment for external editors D. Ben Knoble
2025-05-21  7:56   ` Patrick Steinhardt
2025-05-21 13:26     ` D. Ben Knoble
2025-05-21 13:34       ` Patrick Steinhardt
2025-05-21 15:20       ` Junio C Hamano
2025-05-21 15:10     ` Junio C Hamano
2025-05-20 19:34 ` [PATCH 3/4] run-command: prep_childenv on all platforms D. Ben Knoble
2025-05-21  7:56   ` Patrick Steinhardt
2025-05-21 13:07     ` Phillip Wood
2025-05-21 13:33       ` D. Ben Knoble
2025-05-20 19:34 ` D. Ben Knoble [this message]
2025-05-20 20:33   ` [PATCH 4/4] drop git_exec_path() from non-Git commands' PATH Junio C Hamano
2025-05-21 13:44     ` D. Ben Knoble
2025-05-21  8:27   ` Patrick Steinhardt
2025-05-21 13:07     ` Phillip Wood
2025-05-21 13:17       ` Patrick Steinhardt
2025-05-21 15:27         ` Phillip Wood
2025-05-26  6:34           ` Patrick Steinhardt
2025-05-21 15:50         ` Justin Tobler
2025-05-26  6:31           ` Patrick Steinhardt
2025-05-21 13:48     ` D. Ben Knoble
2025-05-21 14:47     ` Junio C Hamano
2025-05-22 13:21 ` [PATCH 0/4] Drop git-exec-path from non-Git child programs Phillip Wood
2025-08-05  1:41   ` D. Ben Knoble
2025-08-05  2:40 ` [PATCH 0/2] clean up some code around editors D. Ben Knoble
2025-08-06 10:07   ` Phillip Wood
2025-08-05  2:40 ` [PATCH 1/2] t7005: sanitize test environment for subsequent tests D. Ben Knoble
2025-08-05  2:40 ` [PATCH 2/2] editor: use standard strvec API to receive environment for external editors D. Ben Knoble
2025-08-10 16:03 ` [PATCH 0/3] clean up some code around editors D. Ben Knoble
2025-08-10 16:06   ` D. Ben Knoble
2025-08-10 16:34     ` Ben Knoble
2025-08-11 22:16   ` [PATCH v3 0/4] " D. Ben Knoble
2025-08-11 22:59     ` Ben Knoble
2025-08-12  0:16       ` Eric Sunshine
2025-08-12 16:42         ` D. Ben Knoble
2025-08-12 17:35         ` Junio C Hamano
2025-08-12 18:13           ` Eric Sunshine
2025-08-12 18:22             ` Junio C Hamano
2025-08-12 18:30               ` Eric Sunshine
2025-08-12 17:02     ` [PATCH v4 0/3] " D. Ben Knoble
2025-08-13 10:14       ` Phillip Wood
2025-08-13 15:41         ` Junio C Hamano
2025-08-13 17:36           ` D. Ben Knoble
2025-08-13 17:50       ` [PATCH v5 " D. Ben Knoble
2025-08-15 16:00         ` Phillip Wood
2025-08-13 17:50       ` [PATCH v5 1/3] t7005: use modern test style D. Ben Knoble
2025-08-13 17:50       ` [PATCH v5 2/3] t7005: stop abusing --exec-path D. Ben Knoble
2025-08-13 17:50       ` [PATCH v5 3/3] t7005: sanitize test environment for subsequent tests D. Ben Knoble
2025-08-12 17:02     ` [PATCH v4 1/3] t7005: use modern test style D. Ben Knoble
2025-08-12 17:02     ` [PATCH v4 2/3] t7005: stop abusing --exec-path D. Ben Knoble
2025-08-12 17:02     ` [PATCH v4 3/3] t7005: sanitize test environment for subsequent tests D. Ben Knoble
2025-08-11 22:16   ` [PATCH v3 1/4] t7005: use modern test style D. Ben Knoble
2025-08-11 22:16   ` [PATCH v3 2/4] t7005: stop abusing --exec-path D. Ben Knoble
2025-08-11 22:16   ` [PATCH v3 3/4] t7005: sanitize test environment for subsequent tests D. Ben Knoble
2025-08-11 22:34     ` Eric Sunshine
2025-08-12 16:40       ` D. Ben Knoble
2025-08-12 17:13         ` Eric Sunshine
2025-08-11 22:16   ` [PATCH v3 4/4] editor: use standard strvec API to receive environment for external editors D. Ben Knoble
2025-08-11 22:46     ` Eric Sunshine
2025-08-11 23:58       ` Junio C Hamano
2025-08-10 16:03 ` [PATCH 1/3] t7005: use modern test style D. Ben Knoble
2025-08-10 19:42   ` Phillip Wood
2025-08-11 10:04   ` Phillip Wood
2025-08-10 16:03 ` [PATCH 2/3] t7005: sanitize test environment for subsequent tests D. Ben Knoble
2025-08-10 19:44   ` Phillip Wood
2025-08-10 19:53     ` Ben Knoble
2025-08-10 20:58       ` Eric Sunshine
2025-08-11  9:59     ` Phillip Wood
2025-08-10 16:03 ` [PATCH 3/3] editor: use standard strvec API to receive environment for external editors D. Ben Knoble

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=20250520193506.95199-5-ben.knoble+github@gmail.com \
    --to=ben.knoble+github@gmail.com \
    --cc=avarab@gmail.com \
    --cc=git@vger.kernel.org \
    --cc=gitster@pobox.com \
    --cc=johannes.schindelin@gmx.de \
    /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 NNTP newsgroup(s).