diff --git a/builtin/fsck.c b/builtin/fsck.c index fc150c8821..8aadca160e 100644 --- a/builtin/fsck.c +++ b/builtin/fsck.c @@ -310,8 +310,7 @@ static int fsck_obj(struct object *obj) if (obj->type == OBJ_COMMIT) { struct commit *commit = (struct commit *) obj; - free(commit->buffer); - commit->buffer = NULL; + free_commit_buffer(commit); if (!commit->parents && show_root) printf("root %s\n", sha1_to_hex(commit->object.sha1)); diff --git a/builtin/index-pack.c b/builtin/index-pack.c index b9f6e12c0e..42551ce4ff 100644 --- a/builtin/index-pack.c +++ b/builtin/index-pack.c @@ -774,7 +774,8 @@ static void sha1_object(const void *data, struct object_entry *obj_entry, } if (obj->type == OBJ_COMMIT) { struct commit *commit = (struct commit *) obj; - commit->buffer = NULL; + if (detach_commit_buffer(commit) != data) + die("BUG: parse_object_buffer transmogrified our buffer"); } obj->flags |= FLAG_CHECKED; } diff --git a/builtin/log.c b/builtin/log.c index 39e8836352..226f8f2980 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -349,8 +349,7 @@ static int cmd_log_walk(struct rev_info *rev) rev->max_count++; if (!rev->reflog_info) { /* we allow cycles in reflog ancestry */ - free(commit->buffer); - commit->buffer = NULL; + free_commit_buffer(commit); } free_commit_list(commit->parents); commit->parents = NULL; @@ -1508,8 +1507,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix) reopen_stdout(rev.numbered_files ? NULL : commit, NULL, &rev, quiet)) die(_("Failed to create output files")); shown = log_tree_commit(&rev, commit); - free(commit->buffer); - commit->buffer = NULL; + free_commit_buffer(commit); /* We put one extra blank line between formatted * patches and this flag is used by log-tree code diff --git a/builtin/rev-list.c b/builtin/rev-list.c index 9f92905379..e012ebe502 100644 --- a/builtin/rev-list.c +++ b/builtin/rev-list.c @@ -173,8 +173,7 @@ static void finish_commit(struct commit *commit, void *data) free_commit_list(commit->parents); commit->parents = NULL; } - free(commit->buffer); - commit->buffer = NULL; + free_commit_buffer(commit); } static void finish_object(struct object *obj, diff --git a/commit.c b/commit.c index fbdc480ccf..11a05c1f24 100644 --- a/commit.c +++ b/commit.c @@ -245,6 +245,19 @@ int unregister_shallow(const unsigned char *sha1) return 0; } +void free_commit_buffer(struct commit *commit) +{ + free(commit->buffer); + commit->buffer = NULL; +} + +const void *detach_commit_buffer(struct commit *commit) +{ + void *ret = commit->buffer; + commit->buffer = NULL; + return ret; +} + int parse_commit_buffer(struct commit *item, const void *buffer, unsigned long size) { const char *tail = buffer; diff --git a/commit.h b/commit.h index 4df48cb688..d72ed43340 100644 --- a/commit.h +++ b/commit.h @@ -51,6 +51,17 @@ int parse_commit_buffer(struct commit *item, const void *buffer, unsigned long s int parse_commit(struct commit *item); void parse_commit_or_die(struct commit *item); +/* + * Free any cached object buffer associated with the commit. + */ +void free_commit_buffer(struct commit *); + +/* + * Disassociate any cached object buffer from the commit, but do not free it. + * The buffer (or NULL, if none) is returned. + */ +const void *detach_commit_buffer(struct commit *); + /* Find beginning and length of commit subject. */ int find_commit_subject(const char *commit_buffer, const char **subject);