Merge branch 'jk/chopped-ident'

A commit object whose author or committer ident are malformed
crashed some code that trusted that a name, an email and an
timestamp can always be found in it.

* jk/chopped-ident:
  blame: handle broken commit headers gracefully
  pretty: handle broken commit headers gracefully
  cat-file: print tags raw for "cat-file -p"
This commit is contained in:
Junio C Hamano 2013-04-22 11:11:36 -07:00
commit 703319313f
5 changed files with 75 additions and 99 deletions

View file

@ -1375,10 +1375,15 @@ static void get_ac_line(const char *inbuf, const char *what,
maillen = ident.mail_end - ident.mail_begin;
mailbuf = ident.mail_begin;
*time = strtoul(ident.date_begin, NULL, 10);
if (ident.date_begin && ident.date_end)
*time = strtoul(ident.date_begin, NULL, 10);
else
*time = 0;
len = ident.tz_end - ident.tz_begin;
strbuf_add(tz, ident.tz_begin, len);
if (ident.tz_begin && ident.tz_end)
strbuf_add(tz, ident.tz_begin, ident.tz_end - ident.tz_begin);
else
strbuf_addstr(tz, "(unknown)");
/*
* Now, convert both name and e-mail using mailmap

View file

@ -16,73 +16,6 @@
#define BATCH 1
#define BATCH_CHECK 2
static void pprint_tag(const unsigned char *sha1, const char *buf, unsigned long size)
{
/* the parser in tag.c is useless here. */
const char *endp = buf + size;
const char *cp = buf;
while (cp < endp) {
char c = *cp++;
if (c != '\n')
continue;
if (7 <= endp - cp && !memcmp("tagger ", cp, 7)) {
const char *tagger = cp;
/* Found the tagger line. Copy out the contents
* of the buffer so far.
*/
write_or_die(1, buf, cp - buf);
/*
* Do something intelligent, like pretty-printing
* the date.
*/
while (cp < endp) {
if (*cp++ == '\n') {
/* tagger to cp is a line
* that has ident and time.
*/
const char *sp = tagger;
char *ep;
unsigned long date;
long tz;
while (sp < cp && *sp != '>')
sp++;
if (sp == cp) {
/* give up */
write_or_die(1, tagger,
cp - tagger);
break;
}
while (sp < cp &&
!('0' <= *sp && *sp <= '9'))
sp++;
write_or_die(1, tagger, sp - tagger);
date = strtoul(sp, &ep, 10);
tz = strtol(ep, NULL, 10);
sp = show_date(date, tz, 0);
write_or_die(1, sp, strlen(sp));
xwrite(1, "\n", 1);
break;
}
}
break;
}
if (cp < endp && *cp == '\n')
/* end of header */
break;
}
/* At this point, we have copied out the header up to the end of
* the tagger line and cp points at one past \n. It could be the
* next header line after the tagger line, or it could be another
* \n that marks the end of the headers. We need to copy out the
* remainder as is.
*/
if (cp < endp)
write_or_die(1, cp, endp - cp);
}
static int cat_one_file(int opt, const char *exp_type, const char *obj_name)
{
unsigned char sha1[20];
@ -133,10 +66,6 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name)
buf = read_sha1_file(sha1, &type, &size);
if (!buf)
die("Cannot read object %s", obj_name);
if (type == OBJ_TAG) {
pprint_tag(sha1, buf, size);
return 0;
}
/* otherwise just spit out the data */
break;

View file

@ -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;
}

View file

@ -134,15 +134,12 @@ tagger $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>"
tag_description="This is a tag"
tag_content="$tag_header_without_timestamp 0000000000 +0000
$tag_description"
tag_pretty_content="$tag_header_without_timestamp Thu Jan 1 00:00:00 1970 +0000
$tag_description"
tag_sha1=$(echo_without_newline "$tag_content" | git mktag)
tag_size=$(strlen "$tag_content")
run_tests 'tag' $tag_sha1 $tag_size "$tag_content" "$tag_pretty_content" 1
run_tests 'tag' $tag_sha1 $tag_size "$tag_content" "$tag_content" 1
test_expect_success \
"Reach a blob from a tag pointing to it" \

42
t/t4212-log-corrupt.sh Executable file
View file

@ -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