]> git.ipfire.org Git - thirdparty/git.git/commitdiff
reflog-walk: duplicate strings in complete_reflogs list
authorJeff King <peff@peff.net>
Fri, 7 Jul 2017 08:39:50 +0000 (04:39 -0400)
committerJunio C Hamano <gitster@pobox.com>
Fri, 7 Jul 2017 15:58:17 +0000 (08:58 -0700)
As part of the add_reflog_to_walk() function, we keep a
string_list mapping refnames to their reflog contents. This
serves as a cache so that accessing the same reflog twice
requires only a single copy of the log in memory.

The string_list is initialized via xcalloc, meaning its
strdup_strings field is set to 0. But after inserting a
string into the list, we unconditionally call free() on the
string, leaving the list pointing to freed memory. If
another reflog is added (e.g., "git log -g HEAD HEAD"), then
the second one may have unpredictable results.

The extra free was added by 5026b47175 (add_reflog_for_walk:
avoid memory leak, 2017-05-04). Though if you look
carefully, you can see that the code was buggy even before
then. If we tried to read the reflogs by time but came up
with no entries, we exited with an error, freeing the string
in that code path. So the bug was harder to trigger, but
still there.

We can fix it by just asking the string list to make a copy
of the string. Technically we could fix the problem by not
calling free() on our string (and just handing over
ownership to the string list), but there are enough
conditionals that it's quite hard to figure out which code
paths need the free and which do not. Simpler is better
here.

The new test reliably shows the problem when run with
--valgrind or ASAN.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
reflog-walk.c
t/t1411-reflog-show.sh

index f7ffd1caa3ced247a3da271f478a942ff59b4bd8..aec718beba8ae58860759f311a5f8b41c2b78010 100644 (file)
@@ -136,6 +136,7 @@ struct reflog_walk_info {
 void init_reflog_walk(struct reflog_walk_info **info)
 {
        *info = xcalloc(1, sizeof(struct reflog_walk_info));
+       (*info)->complete_reflogs.strdup_strings = 1;
 }
 
 int add_reflog_for_walk(struct reflog_walk_info *info,
index 6ac7734d79be21a82feeadff10064bb4ca7ad47b..ae96eeb66a0fd9d73a5805cd01f32dac857bd483 100755 (executable)
@@ -171,4 +171,10 @@ test_expect_success 'reflog exists works' '
        ! git reflog exists refs/heads/nonexistent
 '
 
+# The behavior with two reflogs is buggy and the output is in flux; for now
+# we're just checking that the program works at all without segfaulting.
+test_expect_success 'showing multiple reflogs works' '
+       git log -g HEAD HEAD >actual
+'
+
 test_done