git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v4] reflog-walk: don't segfault on non-commit sha1's in the reflog

From
Dennis Kaarsemaker <dennis@kaarsemaker.net>
Date
Jan 5, 2016, 21:12 UTC
Message-ID
<20160105211206.GA12057@spirit>
In-Reply-To
<1451552227.11138.6.camel@kaarsemaker.net>

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 <dennis@kaarsemaker.net>
Helped-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>
Helped-by: Junio C Hamano <gitster@pobox.com>
---
Changes since v3: tweaks to the second test.
 reflog-walk.c     | 16 +++++++++++-----
 t/t1410-reflog.sh | 13 +++++++++++++
 2 files changed, 24 insertions(+), 5 deletions(-)
diff --git a/reflog-walk.c b/reflog-walk.c
index 85b8a54..0ebd1da 100644
--- a/reflog-walk.c
+++ b/reflog-walk.c
@@ -221,6 +221,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;
@@ -232,15 +233,20 @@ void fake_reflog_parent(struct reflog_walk_info *info, struct commit *commit)
 		commit->parents = NULL;
 		return;
 	}
-
-	reflog = &commit_reflog->reflogs->items[commit_reflog->recno];
 	info->last_commit_reflog = commit_reflog;
-	commit_reflog->recno--;
-	commit_info->commit = (struct commit *)parse_object(reflog->osha1);
-	if (!commit_info->commit) {
+
+	do {
+		reflog = &commit_reflog->reflogs->items[commit_reflog->recno];
+		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;
 		return;
 	}
+	commit_info->commit = (struct commit *)logobj;
 
 	commit->parents = xcalloc(1, sizeof(struct commit_list));
 	commit->parents->item = commit_info->commit;
diff --git a/t/t1410-reflog.sh b/t/t1410-reflog.sh
index b79049f..17a194b 100755
--- a/t/t1410-reflog.sh
+++ b/t/t1410-reflog.sh
@@ -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
+'
+
 test_done
-- 
2.7.0-rc3-219-g24972d4


-- 
Dennis Kaarsemaker <dennis@kaarsemaker.net>
http://twitter.com/seveas
Previous: Dennis KaarsemakerNext: Eric Sunshine
Message 19 of 25 in “Segfault in git reflog”
  1. Dennis KaarsemakerDec 30, 2015
  2. Duy NguyenDec 30, 2015
  3. Dennis KaarsemakerDec 30, 2015
  4. Duy NguyenDec 30, 2015
  5. Duy NguyenDec 30, 2015
  6. Dennis KaarsemakerDec 30, 2015
  7. Duy NguyenDec 30, 2015
  8. reflog-walk: don't segfault on non-commit sha1's in the reflogDennis Kaarsemaker, Dec 30, 2015
  9. Junio C HamanoDec 30, 2015
  10. Dennis KaarsemakerDec 30, 2015
  11. Junio C HamanoDec 30, 2015
  12. Dennis KaarsemakerDec 30, 2015
  13. reflog-walk: don't segfault on non-commit sha1's in the reflogDennis Kaarsemaker, Dec 30, 2015
  14. Junio C HamanoDec 30, 2015
  15. reflog-walk: don't segfault on non-commit sha1's in the reflogDennis Kaarsemaker, Dec 30, 2015
  16. Junio C HamanoDec 31, 2015
  17. Dennis KaarsemakerDec 31, 2015
  18. Dennis KaarsemakerDec 31, 2015
  19. reflog-walk: don't segfault on non-commit sha1's in the reflogDennis Kaarsemaker, Jan 5, 2016
  20. Eric SunshineJan 6, 2016
  21. Dennis KaarsemakerJan 6, 2016
  22. Eric SunshineJan 6, 2016
  23. Eric SunshineJan 6, 2016
  24. Dennis KaarsemakerJan 6, 2016
  25. Duy NguyenJan 6, 2016

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.