git@vger.kernel.org mailing list mirror (one of many)
 help / color / mirror / code / Atom feed
From: Jeff King <peff@peff.net>
To: Junio C Hamano <gitster@pobox.com>
Cc: git@vger.kernel.org, "Rubén Justo" <rjusto@gmail.com>
Subject: [PATCH 01/11] config: make sequencer.c's git_config_string_dup() public
Date: Sat, 6 Apr 2024 20:58:31 -0400	[thread overview]
Message-ID: <20240407005831.GA868358@coredump.intra.peff.net> (raw)
In-Reply-To: <20240407005656.GA436890@coredump.intra.peff.net>

Just about every caller of git_config_string() has a possible leak in
it: if we parse a config variable twice, it will overwrite the pointer
that was allocated the first time, leaving the memory unreferenced.

Unfortunately we can't just fix this directly in git_config_string().
Some callers do something like:

   const char *foo = "default_value";
   ...
   git_config_string(&foo, var, value);

And we must _not_ free that initial value, as it's a string literal. We
can't help those cases easily, as there's no way to distinguish a
heap-allocated variable from the default one. But let's start by at
least providing a helper that avoids the leak. That will let us convert
some cases right away, and give us one potential path forward for the
more complex ones.

It turns out we already have such a helper, courtesy of 03a4e260e2
(sequencer: plug memory leaks for the option values, 2016-10-21). The
problem is more acute in sequencer.c, which may load config multiple
times. Hence the solution was limited to that file back then. But this
really is a more general problem within our config callbacks.

Note that the new helper takes a "char *" rather than a const pointer.
This is more appropriate, since we tend to use "const" as a signal for
a lack of memory ownership (and this function is most certainly
asserting ownership over the pointed-to memory).

Signed-off-by: Jeff King <peff@peff.net>
---
 config.c    |  9 +++++++++
 config.h    | 12 ++++++++++++
 sequencer.c | 10 ----------
 3 files changed, 21 insertions(+), 10 deletions(-)

diff --git a/config.c b/config.c
index eebce8c7e0..2194fb078a 100644
--- a/config.c
+++ b/config.c
@@ -1345,6 +1345,15 @@ int git_config_string(const char **dest, const char *var, const char *value)
 	return 0;
 }
 
+int git_config_string_dup(char **dest, const char *var, const char *value)
+{
+	if (!value)
+		return config_error_nonbool(var);
+	free(*dest);
+	*dest = xstrdup(value);
+	return 0;
+}
+
 int git_config_pathname(const char **dest, const char *var, const char *value)
 {
 	if (!value)
diff --git a/config.h b/config.h
index f4966e3749..cdffc14ccf 100644
--- a/config.h
+++ b/config.h
@@ -279,9 +279,21 @@ int git_config_bool(const char *, const char *);
 /**
  * Allocates and copies the value string into the `dest` parameter; if no
  * string is given, prints an error message and returns -1.
+ *
+ * Note that this function does _not_ free the memory referenced by the
+ * destination pointer. This makes it safe to use on a variable that initially
+ * points to a string literal, but it also means that it leaks if the config
+ * option is seen multiple times.
  */
 int git_config_string(const char **, const char *, const char *);
 
+/**
+ * Like git_config_string(), but frees any previously-allocated
+ * string at the destination pointer, avoiding a leak when a
+ * config variable is seen multiple times.
+ */
+int git_config_string_dup(char **, const char *, const char *);
+
 /**
  * Similar to `git_config_string`, but expands `~` or `~user` into the
  * user's home directory when found at the beginning of the path.
diff --git a/sequencer.c b/sequencer.c
index 2c19846385..3e5d82e0e5 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -2920,16 +2920,6 @@ static int read_populate_todo(struct repository *r,
 	return 0;
 }
 
-static int git_config_string_dup(char **dest,
-				 const char *var, const char *value)
-{
-	if (!value)
-		return config_error_nonbool(var);
-	free(*dest);
-	*dest = xstrdup(value);
-	return 0;
-}
-
 static int populate_opts_cb(const char *key, const char *value,
 			    const struct config_context *ctx,
 			    void *data)
-- 
2.44.0.872.g288abe5b5b



  reply	other threads:[~2024-04-07  0:58 UTC|newest]

Thread overview: 23+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-04-06 18:11 [PATCH] config: do not leak excludes_file Junio C Hamano
2024-04-06 19:17 ` [WIP] git_config_pathname() leakfix Junio C Hamano
2024-04-07  0:56 ` [PATCH 0/12] git_config_string() considered harmful Jeff King
2024-04-07  0:58   ` Jeff King [this message]
2024-04-07  1:00   ` [PATCH 02/11] config: add git_config_pathname_dup() Jeff King
2024-04-07  1:00   ` [PATCH 03/11] config: prefer git_config_string_dup() for temp variables Jeff King
2024-04-07  1:50     ` Eric Sunshine
2024-04-07  2:45       ` Jeff King
2024-04-07  1:01   ` [PATCH 04/11] config: use git_config_string_dup() for open-coded equivalents Jeff King
2024-04-07  1:01   ` [PATCH 05/11] config: use git_config_string_dup() to fix leaky open coding Jeff King
2024-04-07  1:02   ` [PATCH 06/11] config: use git_config_string() in easy cases Jeff King
2024-04-07  2:05     ` Eric Sunshine
2024-04-07  2:47       ` Jeff King
2024-04-07  1:03   ` [PATCH 07/11] config: use git_config_pathname_dup() " Jeff King
2024-04-07  1:03   ` [PATCH 08/11] http: use git_config_string_dup() Jeff King
2024-04-07  1:04   ` [PATCH 09/11] merge: use git_config_string_dup() for pull strategies Jeff King
2024-04-07  1:04   ` [PATCH 10/11] userdiff: use git_config_string_dup() when we can Jeff King
2024-04-07  1:07   ` [PATCH 11/11] blame: use "dup" string_list for ignore-revs files Jeff King
2024-04-07  2:42     ` Eric Sunshine
2024-04-07  1:08   ` [PATCH 0/12] git_config_string() considered harmful Jeff King
2024-04-07 17:58   ` Rubén Justo
2024-04-08 20:55     ` Jeff King
2024-04-11 23:36       ` Rubén Justo

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=20240407005831.GA868358@coredump.intra.peff.net \
    --to=peff@peff.net \
    --cc=git@vger.kernel.org \
    --cc=gitster@pobox.com \
    --cc=rjusto@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).