Skip to content

Commit aecad37

Browse files
seveasgitster
authored andcommitted
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 walker. 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 <[email protected]> Helped-by: Nguyễn Thái Ngọc Duy <[email protected]> Helped-by: Junio C Hamano <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 1ff8856 commit aecad37

File tree

2 files changed

+24
-5
lines changed

2 files changed

+24
-5
lines changed

reflog-walk.c

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -222,6 +222,7 @@ void fake_reflog_parent(struct reflog_walk_info *info, struct commit *commit)
222222
struct commit_info *commit_info =
223223
get_commit_info(commit, &info->reflogs, 0);
224224
struct commit_reflog *commit_reflog;
225+
struct object *logobj;
225226
struct reflog_info *reflog;
226227

227228
info->last_commit_reflog = NULL;
@@ -233,15 +234,20 @@ void fake_reflog_parent(struct reflog_walk_info *info, struct commit *commit)
233234
commit->parents = NULL;
234235
return;
235236
}
236-
237-
reflog = &commit_reflog->reflogs->items[commit_reflog->recno];
238237
info->last_commit_reflog = commit_reflog;
239-
commit_reflog->recno--;
240-
commit_info->commit = (struct commit *)parse_object(reflog->osha1);
241-
if (!commit_info->commit) {
238+
239+
do {
240+
reflog = &commit_reflog->reflogs->items[commit_reflog->recno];
241+
commit_reflog->recno--;
242+
logobj = parse_object(reflog->osha1);
243+
} while (commit_reflog->recno && (logobj && logobj->type != OBJ_COMMIT));
244+
245+
if (!logobj || logobj->type != OBJ_COMMIT) {
246+
commit_info->commit = NULL;
242247
commit->parents = NULL;
243248
return;
244249
}
250+
commit_info->commit = (struct commit *)logobj;
245251

246252
commit->parents = xcalloc(1, sizeof(struct commit_list));
247253
commit->parents->item = commit_info->commit;

t/t1410-reflog.sh

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -325,4 +325,17 @@ test_expect_success 'parsing reverse reflogs at BUFSIZ boundaries' '
325325
test_cmp expect actual
326326
'
327327

328+
test_expect_success 'no segfaults for reflog containing non-commit sha1s' '
329+
git update-ref --create-reflog -m "Creating ref" \
330+
refs/tests/tree-in-reflog HEAD &&
331+
git update-ref -m "Forcing tree" refs/tests/tree-in-reflog HEAD^{tree} &&
332+
git update-ref -m "Restoring to commit" refs/tests/tree-in-reflog HEAD &&
333+
git reflog refs/tests/tree-in-reflog
334+
'
335+
336+
test_expect_failure 'reflog with non-commit entries displays all entries' '
337+
git reflog refs/tests/tree-in-reflog >actual &&
338+
test_line_count = 3 actual
339+
'
340+
328341
test_done

0 commit comments

Comments
 (0)