]> git.ipfire.org Git - thirdparty/git.git/commitdiff
commit-graph.c: remove path normalization, comparison
authorTaylor Blau <me@ttaylorr.com>
Mon, 3 Feb 2020 21:18:02 +0000 (13:18 -0800)
committerJunio C Hamano <gitster@pobox.com>
Tue, 4 Feb 2020 19:36:51 +0000 (11:36 -0800)
As of the previous patch, all calls to 'commit-graph.c' functions which
perform path normalization (for e.g., 'get_commit_graph_filename()') are
of the form 'ctx->odb->path', which is always in normalized form.

Now that there are no callers passing non-normalized paths to these
functions, ensure that future callers are bound by the same restrictions
by making these functions take a 'struct object_directory *' instead of
a 'const char *'. To match, replace all calls with arguments of the form
'ctx->odb->path' with 'ctx->odb' To recover the path, functions that
perform path manipulation simply use 'odb->path'.

Further, avoid string comparisons with arguments of the form
'odb->path', and instead prefer raw pointer comparisons, which
accomplish the same effect, but are far less brittle.

This has a pleasant side-effect of making these functions much more
robust to paths that cannot be normalized by 'normalize_path_copy()',
i.e., because they are outside of the current working directory.

For example, prior to this patch, Valgrind reports that the following
uninitialized memory read [1]:

  $ ( cd t && GIT_DIR=../.git valgrind git rev-parse HEAD^ )

because 'normalize_path_copy()' can't normalize '../.git' (since it's
relative to but above of the current working directory) [2].

By using a 'struct object_directory *' directly,
'get_commit_graph_filename()' does not need to normalize, because all
paths are relative to the current working directory since they are
always read from the '->path' of an object directory.

[1]: https://lore.kernel.org/git/20191027042116.GA5801@sigill.intra.peff.net.
[2]: The bug here is that 'get_commit_graph_filename()' returns the
     result of 'normalize_path_copy()' without checking the return
     value.

Signed-off-by: Taylor Blau <me@ttaylorr.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
builtin/commit-graph.c
commit-graph.c
commit-graph.h
t/helper/test-read-graph.c

index 5d8fa9dc2d1df443e9bb3f035c6398e779ba6c5e..e622ed90b89c3793604ad1567803b12526504012 100644 (file)
@@ -88,7 +88,7 @@ static int graph_verify(int argc, const char **argv)
                flags |= COMMIT_GRAPH_WRITE_PROGRESS;
 
        odb = find_odb(the_repository, opts.obj_dir);
-       graph_name = get_commit_graph_filename(odb->path);
+       graph_name = get_commit_graph_filename(odb);
        open_ok = open_commit_graph(graph_name, &fd, &st);
        if (!open_ok && errno != ENOENT)
                die_errno(_("Could not open commit-graph '%s'"), graph_name);
index 3af4a721ee6795f558ee173381da45a108bc0a3c..49541760b5deecf09e97edafeeddf6ecc56b2c05 100644 (file)
 /* Remember to update object flag allocation in object.h */
 #define REACHABLE       (1u<<15)
 
-char *get_commit_graph_filename(const char *obj_dir)
+char *get_commit_graph_filename(struct object_directory *odb)
 {
-       char *filename = xstrfmt("%s/info/commit-graph", obj_dir);
-       char *normalized = xmalloc(strlen(filename) + 1);
-       normalize_path_copy(normalized, filename);
-       free(filename);
-       return normalized;
+       return xstrfmt("%s/info/commit-graph", odb->path);
 }
 
-static char *get_split_graph_filename(const char *obj_dir,
+static char *get_split_graph_filename(struct object_directory *odb,
                                      const char *oid_hex)
 {
-       char *filename = xstrfmt("%s/info/commit-graphs/graph-%s.graph",
-                                obj_dir,
-                                oid_hex);
-       char *normalized = xmalloc(strlen(filename) + 1);
-       normalize_path_copy(normalized, filename);
-       free(filename);
-       return normalized;
+       return xstrfmt("%s/info/commit-graphs/graph-%s.graph", odb->path,
+                      oid_hex);
 }
 
-static char *get_chain_filename(const char *obj_dir)
+static char *get_chain_filename(struct object_directory *odb)
 {
-       return xstrfmt("%s/info/commit-graphs/commit-graph-chain", obj_dir);
+       return xstrfmt("%s/info/commit-graphs/commit-graph-chain", odb->path);
 }
 
 static uint8_t oid_version(void)
@@ -330,7 +321,7 @@ static struct commit_graph *load_commit_graph_one(const char *graph_file)
 static struct commit_graph *load_commit_graph_v1(struct repository *r,
                                                 struct object_directory *odb)
 {
-       char *graph_name = get_commit_graph_filename(odb->path);
+       char *graph_name = get_commit_graph_filename(odb);
        struct commit_graph *g = load_commit_graph_one(graph_name);
        free(graph_name);
 
@@ -381,7 +372,7 @@ static struct commit_graph *load_commit_graph_chain(struct repository *r,
        struct stat st;
        struct object_id *oids;
        int i = 0, valid = 1, count;
-       char *chain_name = get_chain_filename(odb->path);
+       char *chain_name = get_chain_filename(odb);
        FILE *fp;
        int stat_res;
 
@@ -414,7 +405,7 @@ static struct commit_graph *load_commit_graph_chain(struct repository *r,
 
                valid = 0;
                for (odb = r->objects->odb; odb; odb = odb->next) {
-                       char *graph_name = get_split_graph_filename(odb->path, line.buf);
+                       char *graph_name = get_split_graph_filename(odb, line.buf);
                        struct commit_graph *g = load_commit_graph_one(graph_name);
 
                        free(graph_name);
@@ -1375,7 +1366,7 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)
                            ctx->odb->path);
                ctx->graph_name = strbuf_detach(&tmp_file, NULL);
        } else {
-               ctx->graph_name = get_commit_graph_filename(ctx->odb->path);
+               ctx->graph_name = get_commit_graph_filename(ctx->odb);
        }
 
        if (safe_create_leading_directories(ctx->graph_name)) {
@@ -1386,7 +1377,7 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)
        }
 
        if (ctx->split) {
-               char *lock_name = get_chain_filename(ctx->odb->path);
+               char *lock_name = get_chain_filename(ctx->odb);
 
                hold_lock_file_for_update(&lk, lock_name, LOCK_DIE_ON_ERROR);
 
@@ -1474,7 +1465,7 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)
 
        if (ctx->split && ctx->base_graph_name && ctx->num_commit_graphs_after > 1) {
                char *new_base_hash = xstrdup(oid_to_hex(&ctx->new_base_graph->oid));
-               char *new_base_name = get_split_graph_filename(ctx->new_base_graph->odb->path, new_base_hash);
+               char *new_base_name = get_split_graph_filename(ctx->new_base_graph->odb, new_base_hash);
 
                free(ctx->commit_graph_filenames_after[ctx->num_commit_graphs_after - 2]);
                free(ctx->commit_graph_hash_after[ctx->num_commit_graphs_after - 2]);
@@ -1510,12 +1501,12 @@ static int write_commit_graph_file(struct write_commit_graph_context *ctx)
                                }
                        }
                } else {
-                       char *graph_name = get_commit_graph_filename(ctx->odb->path);
+                       char *graph_name = get_commit_graph_filename(ctx->odb);
                        unlink(graph_name);
                }
 
                ctx->commit_graph_hash_after[ctx->num_commit_graphs_after - 1] = xstrdup(oid_to_hex(&file_hash));
-               final_graph_name = get_split_graph_filename(ctx->odb->path,
+               final_graph_name = get_split_graph_filename(ctx->odb,
                                        ctx->commit_graph_hash_after[ctx->num_commit_graphs_after - 1]);
                ctx->commit_graph_filenames_after[ctx->num_commit_graphs_after - 1] = final_graph_name;
 
@@ -1557,7 +1548,7 @@ static void split_graph_merge_strategy(struct write_commit_graph_context *ctx)
 
        while (g && (g->num_commits <= size_mult * num_commits ||
                    (max_commits && num_commits > max_commits))) {
-               if (strcmp(g->odb->path, ctx->odb->path))
+               if (g->odb != ctx->odb)
                        break;
 
                num_commits += g->num_commits;
@@ -1569,10 +1560,10 @@ static void split_graph_merge_strategy(struct write_commit_graph_context *ctx)
        ctx->new_base_graph = g;
 
        if (ctx->num_commit_graphs_after == 2) {
-               char *old_graph_name = get_commit_graph_filename(g->odb->path);
+               char *old_graph_name = get_commit_graph_filename(g->odb);
 
                if (!strcmp(g->filename, old_graph_name) &&
-                   strcmp(g->odb->path, ctx->odb->path)) {
+                   g->odb != ctx->odb) {
                        ctx->num_commit_graphs_after = 1;
                        ctx->new_base_graph = NULL;
                }
@@ -1723,7 +1714,7 @@ static void expire_commit_graphs(struct write_commit_graph_context *ctx)
        if (ctx->split_opts && ctx->split_opts->expire_time)
                expire_time -= ctx->split_opts->expire_time;
        if (!ctx->split) {
-               char *chain_file_name = get_chain_filename(ctx->odb->path);
+               char *chain_file_name = get_chain_filename(ctx->odb);
                unlink(chain_file_name);
                free(chain_file_name);
                ctx->num_commit_graphs_after = 0;
index 244813437866b4fb6de52b25822638a6cd168e07..5a690723b00a2739d7cc4c36916478fac155f1ee 100644 (file)
@@ -12,7 +12,7 @@
 
 struct commit;
 
-char *get_commit_graph_filename(const char *obj_dir);
+char *get_commit_graph_filename(struct object_directory *odb);
 int open_commit_graph(const char *graph_file, int *fd, struct stat *st);
 
 /*
index d2884efe0a13b8e49d347c02c0c55a692f646957..2c2f65f06c460031e4a3ec9e9b8d2ff651924f36 100644 (file)
@@ -11,12 +11,12 @@ int cmd__read_graph(int argc, const char **argv)
        int open_ok;
        int fd;
        struct stat st;
-       const char *object_dir;
+       struct object_directory *odb;
 
        setup_git_directory();
-       object_dir = get_object_directory();
+       odb = the_repository->objects->odb;
 
-       graph_name = get_commit_graph_filename(object_dir);
+       graph_name = get_commit_graph_filename(odb);
 
        open_ok = open_commit_graph(graph_name, &fd, &st);
        if (!open_ok)