fix segfault with git log -c --follow

In diff_tree_combined we make a copy of diffopts. In try_to_follow_renames, called via diff_tree_sha1, we free and re-initialize diffopts->pathspec->items. Since we did not make a deep copy of diffopts in diff_tree_combined, the original diffopts does not get the update. By the time we return from diff_tree_combined, rev->diffopt->pathspec->items points to an invalid memory address. We get a segfault next time we try to access that pathspec. Instead, along with the copy of diffopts, make a copy pathspec->items as well. We would also have to make a copy of pathspec->raw to keep it consistent with pathspec->items, but nobody seems to rely on that. Signed-off-by: Clemens Buchacher <drizzd@aon.at> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Clemens Buchacher committed May 28, 2013 at 00:49 UTC 46ec510ac088ac2669e617a4c8c35e6218dabecc
2 files changed +17
combine-diff.c
+3
@@ -1120,6 +1120,7 @@ void diff_tree_combined(const unsigned char *sha1,
1120 int i, num_paths, needsep, show_log_first, num_parent = parents->nr;
1121
1122 diffopts = *opt;
1123 + diff_tree_setup_paths(diffopts.pathspec.raw, &diffopts);
1124 diffopts.output_format = DIFF_FORMAT_NO_OUTPUT;
1125 DIFF_OPT_SET(&diffopts, RECURSIVE);
1126 DIFF_OPT_CLR(&diffopts, ALLOW_EXTERNAL);
@@ -1187,6 +1188,8 @@ void diff_tree_combined(const unsigned char *sha1,
1188 paths = paths->next;
1189 free(tmp);
1190 }
1191 +
1192 + diff_tree_release_paths(&diffopts);
1193 }
1194
1195 void diff_tree_combined_merge(const struct commit *commit, int dense,
t/t4202-log.sh
+14
@@ -542,6 +542,20 @@ test_expect_success 'show added path under "--follow -M"' '
542 )
543 '
544
545 +test_expect_success 'git log -c --follow' '
546 + test_create_repo follow-c &&
547 + (
548 + cd follow-c &&
549 + test_commit initial file original &&
550 + git rm file &&
551 + test_commit rename file2 original &&
552 + git reset --hard initial &&
553 + test_commit modify file foo &&
554 + git merge -m merge rename &&
555 + git log -c --follow file2
556 + )
557 +'
558 +
559 cat >expect <<\EOF
560 * commit COMMIT_OBJECT_NAME
561 |\ Merge: MERGE_PARENTS