All of lore.kernel.org
 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.