From fe6eb7f2c506190c817407accf27834005a57f2b Mon Sep 17 00:00:00 2001 From: Jeff King Date: Wed, 27 Aug 2014 03:56:01 -0400 Subject: commit: provide a function to find a header in a buffer Usually when we parse a commit, we read it line by line and handle each individual line (e.g., parse_commit and parse_commit_header). Sometimes, however, we only care about extracting a single header. Code in this situation is stuck doing an ad-hoc parse of the commit buffer. Let's provide a reusable function to locate a header within the commit. The code is modeled after pretty.c's get_header, which is used to extract the encoding. Since some callers may not have the "struct commit" to go along with the buffer, we drop that parameter. The only thing lost is a warning for truncated commits, but that's OK. This shouldn't happen in practice, and even if it does, there's no particular reason that this function needs to complain about it. It either finds the header it was asked for, or it doesn't (and in the latter case, the caller will typically complain). Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- commit.c | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) (limited to 'commit.c') diff --git a/commit.c b/commit.c index ae7f2b10f4..b6ffd623c8 100644 --- a/commit.c +++ b/commit.c @@ -1660,3 +1660,25 @@ void print_commit_list(struct commit_list *list, printf(format, sha1_to_hex(list->item->object.sha1)); } } + +const char *find_commit_header(const char *msg, const char *key, size_t *out_len) +{ + int key_len = strlen(key); + const char *line = msg; + + while (line) { + const char *eol = strchrnul(line, '\n'); + + if (line == eol) + return NULL; + + if (eol - line > key_len && + !strncmp(line, key, key_len) && + line[key_len] == ' ') { + *out_len = eol - line - key_len - 1; + return line + key_len + 1; + } + line = *eol ? eol + 1 : NULL; + } + return NULL; +} -- cgit v1.2.3 From 6876618ceaafddba625ed823679d99de0e79d111 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Wed, 27 Aug 2014 03:56:31 -0400 Subject: record_author_date(): fix memory leak on malformed commit If we hit the end-of-header without finding an "author" line, we just return from the function. We should jump to the fail_exit path to clean up the buffer that we may have allocated. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- commit.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'commit.c') diff --git a/commit.c b/commit.c index b6ffd623c8..4ff8c66f96 100644 --- a/commit.c +++ b/commit.c @@ -594,7 +594,7 @@ static void record_author_date(struct author_date_slab *author_date, line_end = strchrnul(buf, '\n'); if (!skip_prefix(buf, "author ", &ident_line)) { if (!line_end[0] || line_end[1] == '\n') - return; /* end of header */ + goto fail_exit; /* end of header */ continue; } if (split_ident_line(&ident, -- cgit v1.2.3 From ea5517f04b08bdb40eca72888220bd6a90d3cf17 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Wed, 27 Aug 2014 03:56:55 -0400 Subject: record_author_date(): use find_commit_header() This saves us some manual parsing and makes the code more readable. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- commit.c | 22 ++++++++-------------- 1 file changed, 8 insertions(+), 14 deletions(-) (limited to 'commit.c') diff --git a/commit.c b/commit.c index 4ff8c66f96..9416d842c6 100644 --- a/commit.c +++ b/commit.c @@ -584,25 +584,19 @@ define_commit_slab(author_date_slab, unsigned long); static void record_author_date(struct author_date_slab *author_date, struct commit *commit) { - const char *buf, *line_end, *ident_line; const char *buffer = get_commit_buffer(commit, NULL); struct ident_split ident; + const char *ident_line; + size_t ident_len; char *date_end; unsigned long date; - for (buf = buffer; buf; buf = line_end + 1) { - line_end = strchrnul(buf, '\n'); - if (!skip_prefix(buf, "author ", &ident_line)) { - if (!line_end[0] || line_end[1] == '\n') - goto fail_exit; /* end of header */ - continue; - } - if (split_ident_line(&ident, - ident_line, line_end - ident_line) || - !ident.date_begin || !ident.date_end) - goto fail_exit; /* malformed "author" line */ - break; - } + ident_line = find_commit_header(buffer, "author", &ident_len); + if (!ident_line) + goto fail_exit; /* no author line */ + if (split_ident_line(&ident, ident_line, ident_len) || + !ident.date_begin || !ident.date_end) + goto fail_exit; /* malformed "author" line */ date = strtoul(ident.date_begin, &date_end, 10); if (date_end != ident.date_end) -- cgit v1.2.3