The function parse_commit() is not safe regarding replaced commits because it uses the buffer of the replacement commit but the object part of the commit struct stay the same. Especially the sha1 is not changed so it doesn't match the content of the commit. To fix that, this patch adds a new function that takes a "struct commit **" instead of a "struct commit *" so we can change the commit pointer that is passed to us. Signed-off-by: Christian Couder <chriscool@xxxxxxxxxxxxx> --- commit.c | 43 +++++++++++++++++++++++++++++++++++++++++++ commit.h | 6 ++++++ 2 files changed, 49 insertions(+), 0 deletions(-) diff --git a/commit.c b/commit.c index 652c1ba..f170179 100644 --- a/commit.c +++ b/commit.c @@ -316,6 +316,49 @@ int parse_commit(struct commit *item) return ret; } +int parse_commit_repl(struct commit **commit) +{ + enum object_type type; + void *buffer; + unsigned long size; + int ret; + const unsigned char *repl; + struct commit *item = *commit; + + if (!item) + return -1; + if (item->object.parsed) + return 0; + buffer = read_sha1_file_repl(item->object.sha1, &type, &size, &repl); + if (!buffer) + return error("Could not read %s", + sha1_to_hex(item->object.sha1)); + + if (item->object.sha1 != repl) { + struct commit *repl_item = lookup_commit(repl); + if (!repl_item) { + free(buffer); + return error("Bad replacement %s for commit %s", + sha1_to_hex(repl), + sha1_to_hex(item->object.sha1)); + } + repl_item->object.flags = item->object.flags; + *commit = item = repl_item; + } else if (type != OBJ_COMMIT) { + free(buffer); + return error("Object %s not a commit", + sha1_to_hex(item->object.sha1)); + } + + ret = parse_commit_buffer(item, buffer, size); + if (save_commit_buffer && !ret) { + item->buffer = buffer; + return 0; + } + free(buffer); + return ret; +} + int find_commit_subject(const char *commit_buffer, const char **subject) { const char *eol; diff --git a/commit.h b/commit.h index a3618f8..d3dfebb 100644 --- a/commit.h +++ b/commit.h @@ -39,6 +39,12 @@ struct commit *lookup_commit_reference_gently(const unsigned char *sha1, int parse_commit_buffer(struct commit *item, void *buffer, unsigned long size); +int parse_commit_repl(struct commit **item); + +/* + * parse_commit() is deprecated, because it's buggy regarding replacements. + * Use parse_commit_repl() instead. + */ int parse_commit(struct commit *item); /* Find beginning and length of commit subject. */ -- 1.7.2.1.351.g275bf -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html