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

[PATCH] pretty: handle broken commit headers gracefully

From
René Scharfe <rene.scharfe@lsrfire.ath.cx>
Date
Apr 17, 2013, 18:33 UTC
Message-ID
<516EEAFF.6000209@lsrfire.ath.cx>
In-Reply-To
<516EE300.7020200@lsrfire.ath.cx>

Centralize the parsing of the date and time zone strings in the new helper function show_ident_date() and make sure it checks the pointers provided by split_ident_line() for NULL before use.

Reported-by: Ivan Lyapunov <dront78@gmail.com>
Signed-off-by: Rene Scharfe <rene.scharfe@lsrfire.ath.cx>
---
The first test case passes on v1.8.1, i.e. it also showed the epoch.
The second one passes on v1.8.1 and on master because there already
is a NULL check in format_person_part().
 pretty.c               | 45 ++++++++++++++++++++++++---------------------
 t/t4211-log-corrupt.sh | 42 ++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 66 insertions(+), 21 deletions(-)
 create mode 100755 t/t4211-log-corrupt.sh
diff --git a/pretty.c b/pretty.c
index d3a82d2..c116248 100644
--- a/pretty.c
+++ b/pretty.c
@@ -393,6 +393,19 @@ static void add_rfc2047(struct strbuf *sb, const char *line, size_t len,
 	strbuf_addstr(sb, "?=");
 }
 
+static const char *show_ident_date(const struct ident_split *ident,
+				   enum date_mode mode)
+{
+	unsigned long date = 0;
+	int tz = 0;
+
+	if (ident->date_begin && ident->date_end)
+		date = strtoul(ident->date_begin, NULL, 10);
+	if (ident->tz_begin && ident->tz_end)
+		tz = strtol(ident->tz_begin, NULL, 10);
+	return show_date(date, tz, mode);
+}
+
 void pp_user_info(const struct pretty_print_context *pp,
 		  const char *what, struct strbuf *sb,
 		  const char *line, const char *encoding)
@@ -401,12 +414,10 @@ void pp_user_info(const struct pretty_print_context *pp,
 	struct strbuf mail;
 	struct ident_split ident;
 	int linelen;
-	char *line_end, *date;
+	char *line_end;
 	const char *mailbuf, *namebuf;
 	size_t namelen, maillen;
 	int max_length = 78; /* per rfc2822 */
-	unsigned long time;
-	int tz;
 
 	if (pp->fmt == CMIT_FMT_ONELINE)
 		return;
@@ -438,8 +449,6 @@ void pp_user_info(const struct pretty_print_context *pp,
 	strbuf_add(&name, namebuf, namelen);
 
 	namelen = name.len + mail.len + 3; /* ' ' + '<' + '>' */
-	time = strtoul(ident.date_begin, &date, 10);
-	tz = strtol(date, NULL, 10);
 
 	if (pp->fmt == CMIT_FMT_EMAIL) {
 		strbuf_addstr(sb, "From: ");
@@ -472,13 +481,16 @@ void pp_user_info(const struct pretty_print_context *pp,
 
 	switch (pp->fmt) {
 	case CMIT_FMT_MEDIUM:
-		strbuf_addf(sb, "Date:   %s\n", show_date(time, tz, pp->date_mode));
+		strbuf_addf(sb, "Date:   %s\n",
+			    show_ident_date(&ident, pp->date_mode));
 		break;
 	case CMIT_FMT_EMAIL:
-		strbuf_addf(sb, "Date: %s\n", show_date(time, tz, DATE_RFC2822));
+		strbuf_addf(sb, "Date: %s\n",
+			    show_ident_date(&ident, DATE_RFC2822));
 		break;
 	case CMIT_FMT_FULLER:
-		strbuf_addf(sb, "%sDate: %s\n", what, show_date(time, tz, pp->date_mode));
+		strbuf_addf(sb, "%sDate: %s\n", what,
+			    show_ident_date(&ident, pp->date_mode));
 		break;
 	default:
 		/* notin' */
@@ -688,8 +700,6 @@ static size_t format_person_part(struct strbuf *sb, char part,
 {
 	/* currently all placeholders have same length */
 	const int placeholder_len = 2;
-	int tz;
-	unsigned long date = 0;
 	struct ident_split s;
 	const char *name, *mail;
 	size_t maillen, namelen;
@@ -716,30 +726,23 @@ static size_t format_person_part(struct strbuf *sb, char part,
 	if (!s.date_begin)
 		goto skip;
 
-	date = strtoul(s.date_begin, NULL, 10);
-
 	if (part == 't') {	/* date, UNIX timestamp */
 		strbuf_add(sb, s.date_begin, s.date_end - s.date_begin);
 		return placeholder_len;
 	}
 
-	/* parse tz */
-	tz = strtoul(s.tz_begin + 1, NULL, 10);
-	if (*s.tz_begin == '-')
-		tz = -tz;
-
 	switch (part) {
 	case 'd':	/* date */
-		strbuf_addstr(sb, show_date(date, tz, dmode));
+		strbuf_addstr(sb, show_ident_date(&s, dmode));
 		return placeholder_len;
 	case 'D':	/* date, RFC2822 style */
-		strbuf_addstr(sb, show_date(date, tz, DATE_RFC2822));
+		strbuf_addstr(sb, show_ident_date(&s, DATE_RFC2822));
 		return placeholder_len;
 	case 'r':	/* date, relative */
-		strbuf_addstr(sb, show_date(date, tz, DATE_RELATIVE));
+		strbuf_addstr(sb, show_ident_date(&s, DATE_RELATIVE));
 		return placeholder_len;
 	case 'i':	/* date, ISO 8601 */
-		strbuf_addstr(sb, show_date(date, tz, DATE_ISO8601));
+		strbuf_addstr(sb, show_ident_date(&s, DATE_ISO8601));
 		return placeholder_len;
 	}
 
diff --git a/t/t4211-log-corrupt.sh b/t/t4211-log-corrupt.sh
new file mode 100755
index 0000000..ec5099b
--- /dev/null
+++ b/t/t4211-log-corrupt.sh
@@ -0,0 +1,42 @@
+#!/bin/sh
+
+test_description='git log with invalid commit headers'
+
+. ./test-lib.sh
+
+test_expect_success 'setup' '
+	test_commit foo &&
+
+	git cat-file commit HEAD |
+	sed "/^author /s/>/>-<>/" >broken_email.commit &&
+	git hash-object -w -t commit broken_email.commit >broken_email.hash &&
+	git update-ref refs/heads/broken_email $(cat broken_email.hash)
+'
+
+test_expect_success 'git log with broken author email' '
+	{
+		echo commit $(cat broken_email.hash)
+		echo "Author: A U Thor <author@example.com>"
+		echo "Date:   Thu Jan 1 00:00:00 1970 +0000"
+		echo
+		echo "    foo"
+	} >expect.out &&
+	: >expect.err &&
+
+	git log broken_email >actual.out 2>actual.err &&
+
+	test_cmp expect.out actual.out &&
+	test_cmp expect.err actual.err
+'
+
+test_expect_success 'git log --format with broken author email' '
+	echo "A U Thor+author@example.com+" >expect.out &&
+	: >expect.err &&
+
+	git log --format="%an+%ae+%ad" broken_email >actual.out 2>actual.err &&
+
+	test_cmp expect.out actual.out &&
+	test_cmp expect.err actual.err
+'
+
+test_done
-- 
1.8.2.1
Previous: Eric SunshineNext: René Scharfe
Message 20 of 28 in “git log - crash and core dump”
  1. Ivan LyapunovApr 16, 2013
  2. Antoine PelisseApr 16, 2013
  3. René ScharfeApr 16, 2013
  4. Junio C HamanoApr 16, 2013
  5. René ScharfeApr 16, 2013
  6. Junio C HamanoApr 16, 2013
  7. Ivan LyapunovApr 17, 2013
  8. Ivan LyapunovApr 17, 2013
  9. John KeepingApr 17, 2013
  10. Ivan LyapunovApr 17, 2013
  11. Konstantin KhomoutovApr 17, 2013
  12. Junio C HamanoApr 17, 2013
  13. Jeff KingApr 17, 2013
  14. Junio C HamanoApr 17, 2013
  15. René ScharfeApr 17, 2013
  16. Jeff KingApr 17, 2013
  17. René ScharfeApr 17, 2013
  18. cat-file: print tags raw for "cat-file -p"Jeff King, Apr 17, 2013
  19. Eric SunshineApr 19, 2013
  20. pretty: handle broken commit headers gracefullyRené Scharfe, Apr 17, 2013
  21. blame: handle broken commit headers gracefullyRené Scharfe, Apr 17, 2013
  22. Jeff KingApr 17, 2013
  23. René ScharfeApr 17, 2013
  24. Junio C HamanoApr 17, 2013
  25. Jeff KingApr 18, 2013
  26. Antoine PelisseApr 16, 2013
  27. Jeff KingApr 16, 2013
  28. Ivan LyapunovApr 17, 2013

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.