Skip to content

Commit

Permalink
commit-graph: return with errors during write
Browse files Browse the repository at this point in the history
The write_commit_graph() method uses die() to report failure and
exit when confronted with an unexpected condition. This use of
die() in a library function is incorrect and is now replaced by
error() statements and an int return type.

Now that we use 'goto cleanup' to jump to the terminal condition
on an error, we have new paths that could lead to uninitialized
values. New initializers are added to correct for this.

The builtins 'commit-graph', 'gc', and 'commit' call these methods,
so update them to check the return value.

Signed-off-by: Derrick Stolee <dstolee@microsoft.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
  • Loading branch information
derrickstolee authored and gitster committed Jan 24, 2019
1 parent 723bfba commit 8e7e6c0
Show file tree
Hide file tree
Showing 5 changed files with 62 additions and 39 deletions.
19 changes: 9 additions & 10 deletions builtin/commit-graph.c
Expand Up @@ -126,6 +126,7 @@ static int graph_write(int argc, const char **argv)
struct string_list *pack_indexes = NULL;
struct string_list *commit_hex = NULL;
struct string_list lines;
int result;

static struct option builtin_commit_graph_write_options[] = {
OPT_STRING(0, "object-dir", &opts.obj_dir,
Expand Down Expand Up @@ -153,10 +154,8 @@ static int graph_write(int argc, const char **argv)

read_replace_refs = 0;

if (opts.reachable) {
write_commit_graph_reachable(opts.obj_dir, opts.append, 1);
return 0;
}
if (opts.reachable)
return write_commit_graph_reachable(opts.obj_dir, opts.append, 1);

string_list_init(&lines, 0);
if (opts.stdin_packs || opts.stdin_commits) {
Expand All @@ -173,14 +172,14 @@ static int graph_write(int argc, const char **argv)
UNLEAK(buf);
}

write_commit_graph(opts.obj_dir,
pack_indexes,
commit_hex,
opts.append,
1);
result = write_commit_graph(opts.obj_dir,
pack_indexes,
commit_hex,
opts.append,
1);

UNLEAK(lines);
return 0;
return result;
}

int cmd_commit_graph(int argc, const char **argv, const char *prefix)
Expand Down
5 changes: 3 additions & 2 deletions builtin/commit.c
Expand Up @@ -1667,8 +1667,9 @@ int cmd_commit(int argc, const char **argv, const char *prefix)
"new_index file. Check that disk is not full and quota is\n"
"not exceeded, and then \"git reset HEAD\" to recover."));

if (git_env_bool(GIT_TEST_COMMIT_GRAPH, 0))
write_commit_graph_reachable(get_object_directory(), 0, 0);
if (git_env_bool(GIT_TEST_COMMIT_GRAPH, 0) &&
write_commit_graph_reachable(get_object_directory(), 0, 0))
return 1;

repo_rerere(the_repository, 0);
run_command_v_opt(argv_gc_auto, RUN_GIT_CMD);
Expand Down
7 changes: 4 additions & 3 deletions builtin/gc.c
Expand Up @@ -662,9 +662,10 @@ int cmd_gc(int argc, const char **argv, const char *prefix)
if (pack_garbage.nr > 0)
clean_pack_garbage();

if (gc_write_commit_graph)
write_commit_graph_reachable(get_object_directory(), 0,
!quiet && !daemonized);
if (gc_write_commit_graph &&
write_commit_graph_reachable(get_object_directory(), 0,
!quiet && !daemonized))
return 1;

if (auto_gc && too_many_loose_objects())
warning(_("There are too many unreachable loose objects; "
Expand Down
60 changes: 41 additions & 19 deletions commit-graph.c
Expand Up @@ -755,27 +755,30 @@ static int add_ref_to_list(const char *refname,
return 0;
}

void write_commit_graph_reachable(const char *obj_dir, int append,
int report_progress)
int write_commit_graph_reachable(const char *obj_dir, int append,
int report_progress)
{
struct string_list list = STRING_LIST_INIT_DUP;
int result;

for_each_ref(add_ref_to_list, &list);
write_commit_graph(obj_dir, NULL, &list, append, report_progress);
result = write_commit_graph(obj_dir, NULL, &list,
append, report_progress);

string_list_clear(&list, 0);
return result;
}

void write_commit_graph(const char *obj_dir,
struct string_list *pack_indexes,
struct string_list *commit_hex,
int append, int report_progress)
int write_commit_graph(const char *obj_dir,
struct string_list *pack_indexes,
struct string_list *commit_hex,
int append, int report_progress)
{
struct packed_oid_list oids;
struct packed_commit_list commits;
struct hashfile *f;
uint32_t i, count_distinct = 0;
char *graph_name;
char *graph_name = NULL;
struct lock_file lk = LOCK_INIT;
uint32_t chunk_ids[5];
uint64_t chunk_offsets[5];
Expand All @@ -787,15 +790,17 @@ void write_commit_graph(const char *obj_dir,
struct strbuf progress_title = STRBUF_INIT;
unsigned long approx_nr_objects;
const unsigned hashsz = the_hash_algo->rawsz;
int res = 0;

if (!commit_graph_compatible(the_repository))
return;
return 0;

oids.nr = 0;
approx_nr_objects = approximate_object_count();
oids.alloc = approx_nr_objects / 32;
oids.progress = NULL;
oids.progress_done = 0;
commits.list = NULL;

if (append) {
prepare_commit_graph_one(the_repository, obj_dir);
Expand Down Expand Up @@ -836,10 +841,16 @@ void write_commit_graph(const char *obj_dir,
strbuf_setlen(&packname, dirlen);
strbuf_addstr(&packname, pack_indexes->items[i].string);
p = add_packed_git(packname.buf, packname.len, 1);
if (!p)
die(_("error adding pack %s"), packname.buf);
if (open_pack_index(p))
die(_("error opening index for %s"), packname.buf);
if (!p) {
error(_("error adding pack %s"), packname.buf);
res = 1;
goto cleanup;
}
if (open_pack_index(p)) {
error(_("error opening index for %s"), packname.buf);
res = 1;
goto cleanup;
}
for_each_object_in_pack(p, add_packed_commits, &oids,
FOR_EACH_OBJECT_PACK_ORDER);
close_pack(p);
Expand Down Expand Up @@ -910,8 +921,11 @@ void write_commit_graph(const char *obj_dir,
}
stop_progress(&progress);

if (count_distinct >= GRAPH_PARENT_MISSING)
die(_("the commit graph format cannot write %d commits"), count_distinct);
if (count_distinct >= GRAPH_PARENT_MISSING) {
error(_("the commit graph format cannot write %d commits"), count_distinct);
res = 1;
goto cleanup;
}

commits.nr = 0;
commits.alloc = count_distinct;
Expand Down Expand Up @@ -943,16 +957,21 @@ void write_commit_graph(const char *obj_dir,
num_chunks = num_extra_edges ? 4 : 3;
stop_progress(&progress);

if (commits.nr >= GRAPH_PARENT_MISSING)
die(_("too many commits to write graph"));
if (commits.nr >= GRAPH_PARENT_MISSING) {
error(_("too many commits to write graph"));
res = 1;
goto cleanup;
}

compute_generation_numbers(&commits, report_progress);

graph_name = get_commit_graph_filename(obj_dir);
if (safe_create_leading_directories(graph_name)) {
UNLEAK(graph_name);
die_errno(_("unable to create leading directories of %s"),
graph_name);
error(_("unable to create leading directories of %s"),
graph_name);
res = errno;
goto cleanup;
}

hold_lock_file_for_update(&lk, graph_name, LOCK_DIE_ON_ERROR);
Expand Down Expand Up @@ -1011,9 +1030,12 @@ void write_commit_graph(const char *obj_dir,
finalize_hashfile(f, NULL, CSUM_HASH_IN_STREAM | CSUM_FSYNC);
commit_lock_file(&lk);

cleanup:
free(graph_name);
free(commits.list);
free(oids.list);

return res;
}

#define VERIFY_COMMIT_GRAPH_ERROR_HASH 2
Expand Down
10 changes: 5 additions & 5 deletions commit-graph.h
Expand Up @@ -60,12 +60,12 @@ struct commit_graph *load_commit_graph_one(const char *graph_file);
*/
int generation_numbers_enabled(struct repository *r);

void write_commit_graph_reachable(const char *obj_dir, int append,
int write_commit_graph_reachable(const char *obj_dir, int append,
int report_progress);
void write_commit_graph(const char *obj_dir,
struct string_list *pack_indexes,
struct string_list *commit_hex,
int append, int report_progress);
int write_commit_graph(const char *obj_dir,
struct string_list *pack_indexes,
struct string_list *commit_hex,
int append, int report_progress);

int verify_commit_graph(struct repository *r, struct commit_graph *g);

Expand Down

0 comments on commit 8e7e6c0

Please sign in to comment.