From: "Derrick Stolee via GitGitGadget" <gitgitgadget@gmail.com>
To: git@vger.kernel.org
Cc: gitster@pobox.com, ps@pks.im, Jeff King <peff@peff.net>,
Derrick Stolee <stolee@gmail.com>,
Derrick Stolee <stolee@gmail.com>
Subject: [PATCH v2 1/3] line-log: protect inner strbuf from free
Date: Thu, 03 Oct 2024 11:58:42 +0000 [thread overview]
Message-ID: <05c21616c350b5141c17fde1aa5d3aea881c6031.1727956724.git.gitgitgadget@gmail.com> (raw)
In-Reply-To: <pull.1806.v2.git.1727956724.gitgitgadget@gmail.com>
From: Derrick Stolee <stolee@gmail.com>
The output_prefix() method in line-log.c may call a function pointer via
the diff_options struct. This function pointer returns a strbuf struct
and then its buffer is passed back. However, that implies that the
consumer is responsible to free the string. This is especially true
because the default behavior is to duplicate the empty string.
The existing functions used in the output_prefix pointer include:
1. idiff_prefix_cb() in diff-lib.c. This returns the data pointer, so
the value exists across multiple calls.
2. diff_output_prefix_callback() in graph.c. This uses a static strbuf
struct, so it reuses buffers across calls. These should not be
freed.
3. output_prefix_cb() in range-diff.c. This is similar to the
diff-lib.c case.
In each case, we should not be freeing this buffer. We can convert the
output_prefix() function to return a const char pointer and stop freeing
the result.
This choice is essentially the opposite of what was done in 394affd46d
(line-log: always allocate the output prefix, 2024-06-07).
This was discovered via 'valgrind' while investigating a public report
of a bug in 'git log --graph -L' [1].
[1] https://github.com/git-for-windows/git/issues/5185
This issue would have been caught by the new test, when Git is compiled
with ASan to catch these double frees.
Co-authored-by: Jeff King <peff@peff.net>
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Derrick Stolee <stolee@gmail.com>
---
line-log.c | 10 ++++------
t/t4211-line-log.sh | 28 ++++++++++++++++++++++++++++
2 files changed, 32 insertions(+), 6 deletions(-)
diff --git a/line-log.c b/line-log.c
index 67c80b39a0d..29cf66bdd10 100644
--- a/line-log.c
+++ b/line-log.c
@@ -897,13 +897,13 @@ static void print_line(const char *prefix, char first,
fputs("\\ No newline at end of file\n", file);
}
-static char *output_prefix(struct diff_options *opt)
+static const char *output_prefix(struct diff_options *opt)
{
if (opt->output_prefix) {
struct strbuf *sb = opt->output_prefix(opt, opt->output_prefix_data);
return sb->buf;
} else {
- return xstrdup("");
+ return "";
}
}
@@ -916,7 +916,7 @@ static void dump_diff_hacky_one(struct rev_info *rev, struct line_log_data *rang
struct diff_ranges *diff = &range->diff;
struct diff_options *opt = &rev->diffopt;
- char *prefix = output_prefix(opt);
+ const char *prefix = output_prefix(opt);
const char *c_reset = diff_get_color(opt->use_color, DIFF_RESET);
const char *c_frag = diff_get_color(opt->use_color, DIFF_FRAGINFO);
const char *c_meta = diff_get_color(opt->use_color, DIFF_METAINFO);
@@ -1003,7 +1003,6 @@ static void dump_diff_hacky_one(struct rev_info *rev, struct line_log_data *rang
out:
free(p_ends);
free(t_ends);
- free(prefix);
}
/*
@@ -1012,10 +1011,9 @@ out:
*/
static void dump_diff_hacky(struct rev_info *rev, struct line_log_data *range)
{
- char *prefix = output_prefix(&rev->diffopt);
+ const char *prefix = output_prefix(&rev->diffopt);
fprintf(rev->diffopt.file, "%s\n", prefix);
- free(prefix);
while (range) {
dump_diff_hacky_one(rev, range);
diff --git a/t/t4211-line-log.sh b/t/t4211-line-log.sh
index 02d76dca284..950451cf6a6 100755
--- a/t/t4211-line-log.sh
+++ b/t/t4211-line-log.sh
@@ -337,4 +337,32 @@ test_expect_success 'zero-width regex .* matches any function name' '
test_cmp expect actual
'
+test_expect_success 'show line-log with graph' '
+ qz_to_tab_space >expect <<-EOF &&
+ * $head_oid Modify func2() in file.c
+ |Z
+ | diff --git a/file.c b/file.c
+ | --- a/file.c
+ | +++ b/file.c
+ | @@ -6,4 +6,4 @@
+ | int func2()
+ | {
+ | - return F2;
+ | + return F2 + 2;
+ | }
+ * $root_oid Add func1() and func2() in file.c
+ ZZ
+ diff --git a/file.c b/file.c
+ --- /dev/null
+ +++ b/file.c
+ @@ -0,0 +6,4 @@
+ +int func2()
+ +{
+ + return F2;
+ +}
+ EOF
+ git log --graph --oneline -L:func2:file.c >actual &&
+ test_cmp expect actual
+'
+
test_done
--
gitgitgadget
next prev parent reply other threads:[~2024-10-03 11:58 UTC|newest]
Thread overview: 24+ messages / expand[flat|nested] mbox.gz Atom feed top
2024-10-02 16:07 [PATCH] line-log: protect inner strbuf from free Derrick Stolee via GitGitGadget
2024-10-02 23:56 ` Jeff King
2024-10-03 0:19 ` Jeff King
2024-10-03 2:36 ` Derrick Stolee
2024-10-03 6:11 ` Jeff King
2024-10-03 12:23 ` Derrick Stolee
2024-10-03 21:02 ` Jeff King
2024-10-03 11:58 ` [PATCH v2 0/3] " Derrick Stolee via GitGitGadget
2024-10-03 11:58 ` Derrick Stolee via GitGitGadget [this message]
2024-10-04 4:32 ` [PATCH v2 1/3] " Patrick Steinhardt
2024-10-03 11:58 ` [PATCH v2 2/3] line-log: remove output_prefix() Jeff King via GitGitGadget
2024-10-03 11:58 ` [PATCH v2 3/3] diff: modify output_prefix function pointer Jeff King via GitGitGadget
2024-10-03 16:26 ` Junio C Hamano
2024-10-03 21:05 ` [PATCH 0/5] diff output_prefix cleanups Jeff King
2024-10-03 21:06 ` [PATCH 1/5] line-log: use diff_line_prefix() instead of custom helper Jeff King
2024-10-03 21:06 ` [PATCH 2/5] diff: drop line_prefix_length field Jeff King
2024-10-03 21:09 ` [PATCH 3/5] diff: return const char from output_prefix callback Jeff King
2024-10-03 21:11 ` [PATCH 4/5] diff: return line_prefix directly when possible Jeff King
2024-10-03 21:13 ` [PATCH 5/5] diff: store graph prefix buf in git_graph struct Jeff King
2024-10-03 23:43 ` Junio C Hamano
2024-10-04 4:32 ` Patrick Steinhardt
2024-10-04 19:27 ` [PATCH 0/5] diff output_prefix cleanups Derrick Stolee
2024-10-04 19:31 ` Junio C Hamano
2024-10-04 19:33 ` Derrick Stolee
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=05c21616c350b5141c17fde1aa5d3aea881c6031.1727956724.git.gitgitgadget@gmail.com \
--to=gitgitgadget@gmail.com \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=peff@peff.net \
--cc=ps@pks.im \
--cc=stolee@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.
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).