Commit aecad374 authored by Dennis Kaarsemaker's avatar Dennis Kaarsemaker Committed by Junio C Hamano

reflog-walk: don't segfault on non-commit sha1's in the reflog

git reflog (ab)uses the log machinery to display its list of log
entries. To do so it must fake commit parent information for the log

For refs in refs/heads this is no problem, as they should only ever
point to commits. Tags and other refs however can point to anything,
thus their reflog may contain non-commit objects.

To avoid segfaulting, we check whether reflog entries are commits before
feeding them to the log walker and skip any non-commits. This means that
git reflog output will be incomplete for such refs, but that's one step
up from segfaulting. A more complete solution would be to decouple git
reflog from the log walker machinery.
Signed-off-by: Dennis Kaarsemaker's avatarDennis Kaarsemaker <[email protected]>
Helped-by: Duy Nguyen's avatarNguyễn Thái Ngọc Duy <[email protected]>
Helped-by: default avatarJunio C Hamano <[email protected]>
Signed-off-by: default avatarJunio C Hamano <[email protected]>
parent 1ff88560
......@@ -222,6 +222,7 @@ void fake_reflog_parent(struct reflog_walk_info *info, struct commit *commit)
struct commit_info *commit_info =
get_commit_info(commit, &info->reflogs, 0);
struct commit_reflog *commit_reflog;
struct object *logobj;
struct reflog_info *reflog;
info->last_commit_reflog = NULL;
......@@ -233,15 +234,20 @@ void fake_reflog_parent(struct reflog_walk_info *info, struct commit *commit)
commit->parents = NULL;
reflog = &commit_reflog->reflogs->items[commit_reflog->recno];
info->last_commit_reflog = commit_reflog;
commit_info->commit = (struct commit *)parse_object(reflog->osha1);
if (!commit_info->commit) {
do {
reflog = &commit_reflog->reflogs->items[commit_reflog->recno];
logobj = parse_object(reflog->osha1);
} while (commit_reflog->recno && (logobj && logobj->type != OBJ_COMMIT));
if (!logobj || logobj->type != OBJ_COMMIT) {
commit_info->commit = NULL;
commit->parents = NULL;
commit_info->commit = (struct commit *)logobj;
commit->parents = xcalloc(1, sizeof(struct commit_list));
commit->parents->item = commit_info->commit;
......@@ -325,4 +325,17 @@ test_expect_success 'parsing reverse reflogs at BUFSIZ boundaries' '
test_cmp expect actual
test_expect_success 'no segfaults for reflog containing non-commit sha1s' '
git update-ref --create-reflog -m "Creating ref" \
refs/tests/tree-in-reflog HEAD &&
git update-ref -m "Forcing tree" refs/tests/tree-in-reflog HEAD^{tree} &&
git update-ref -m "Restoring to commit" refs/tests/tree-in-reflog HEAD &&
git reflog refs/tests/tree-in-reflog
test_expect_failure 'reflog with non-commit entries displays all entries' '
git reflog refs/tests/tree-in-reflog >actual &&
test_line_count = 3 actual
Markdown is supported
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment