]> git.ipfire.org Git - thirdparty/git.git/commitdiff
list-objects: handle NULL function pointers
authorÆvar Arnfjörð Bjarmason <avarab@gmail.com>
Wed, 9 Mar 2022 16:01:38 +0000 (16:01 +0000)
committerJunio C Hamano <gitster@pobox.com>
Wed, 9 Mar 2022 18:25:27 +0000 (10:25 -0800)
If a caller to traverse_commit_list() specifies the options for the
--objects flag but does not specify a show_object function pointer, the
result is a segfault. This is currently visible by running 'git bundle
create --objects HEAD'.

We could fix this problem by supplying a no-op callback in
builtin/bundle.c, but that only solves the problem for one builtin,
leaving this segfault open for other callers.

Replace all callers of the show_commit and show_object function pointers
in list-objects.c to call helper functions show_commit() and
show_object() which check that the given context has non-NULL functions
before passing the necessary data. One extra benefit is that it reduces
duplication due to passing ctx->show_data to every caller.

Test that this segfault no longer occurs for 'git bundle'.

Co-authored-by: Derrick Stolee <derrickstolee@github.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
Signed-off-by: Derrick Stolee <derrickstolee@github.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
bundle.c
list-objects.c
t/t6020-bundle-misc.sh

index a0bb687b0f4ea30d44883dcb9d4de5bf1e5963ea..7ba60a573d73c92a02ab609bc67203d6032b6658 100644 (file)
--- a/bundle.c
+++ b/bundle.c
@@ -544,6 +544,8 @@ int create_bundle(struct repository *r, const char *path,
                die("revision walk setup failed");
        bpi.fd = bundle_fd;
        bpi.pending = &revs_copy.pending;
+
+       revs.blob_objects = revs.tree_objects = 0;
        traverse_commit_list(&revs, write_bundle_prerequisites, NULL, &bpi);
        object_array_remove_duplicates(&revs_copy.pending);
 
index 117f734398ca5f385ae586e31131ddebb9523a3b..250d9de41cb56072e95420530b203ce417191a2b 100644 (file)
@@ -21,6 +21,23 @@ struct traversal_context {
        struct filter *filter;
 };
 
+static void show_commit(struct traversal_context *ctx,
+                       struct commit *commit)
+{
+       if (!ctx->show_commit)
+               return;
+       ctx->show_commit(commit, ctx->show_data);
+}
+
+static void show_object(struct traversal_context *ctx,
+                       struct object *object,
+                       const char *name)
+{
+       if (!ctx->show_object)
+               return;
+       ctx->show_object(object, name, ctx->show_data);
+}
+
 static void process_blob(struct traversal_context *ctx,
                         struct blob *blob,
                         struct strbuf *path,
@@ -60,7 +77,7 @@ static void process_blob(struct traversal_context *ctx,
        if (r & LOFR_MARK_SEEN)
                obj->flags |= SEEN;
        if (r & LOFR_DO_SHOW)
-               ctx->show_object(obj, path->buf, ctx->show_data);
+               show_object(ctx, obj, path->buf);
        strbuf_setlen(path, pathlen);
 }
 
@@ -194,7 +211,7 @@ static void process_tree(struct traversal_context *ctx,
        if (r & LOFR_MARK_SEEN)
                obj->flags |= SEEN;
        if (r & LOFR_DO_SHOW)
-               ctx->show_object(obj, base->buf, ctx->show_data);
+               show_object(ctx, obj, base->buf);
        if (base->len)
                strbuf_addch(base, '/');
 
@@ -210,7 +227,7 @@ static void process_tree(struct traversal_context *ctx,
        if (r & LOFR_MARK_SEEN)
                obj->flags |= SEEN;
        if (r & LOFR_DO_SHOW)
-               ctx->show_object(obj, base->buf, ctx->show_data);
+               show_object(ctx, obj, base->buf);
 
        strbuf_setlen(base, baselen);
        free_tree_buffer(tree);
@@ -228,7 +245,7 @@ static void process_tag(struct traversal_context *ctx,
        if (r & LOFR_MARK_SEEN)
                tag->object.flags |= SEEN;
        if (r & LOFR_DO_SHOW)
-               ctx->show_object(&tag->object, name, ctx->show_data);
+               show_object(ctx, &tag->object, name);
 }
 
 static void mark_edge_parents_uninteresting(struct commit *commit,
@@ -402,7 +419,7 @@ static void do_traverse(struct traversal_context *ctx)
                if (r & LOFR_MARK_SEEN)
                        commit->object.flags |= SEEN;
                if (r & LOFR_DO_SHOW)
-                       ctx->show_commit(commit, ctx->show_data);
+                       show_commit(ctx, commit);
 
                if (ctx->revs->tree_blobs_in_commit_order)
                        /*
index b13e8a52a93a4e96cde54c5076c19960a4d41a2c..df5ff561fa5c1b837d2db0222af7631677c17169 100755 (executable)
@@ -475,4 +475,16 @@ test_expect_success 'clone from bundle' '
        test_cmp expect actual
 '
 
+test_expect_success 'unfiltered bundle with --objects' '
+       git bundle create all-objects.bdl \
+               --all --objects &&
+       git bundle create all.bdl \
+               --all &&
+
+       # Compare the headers of these files.
+       sed -n -e "/^$/q" -e "p" all.bdl >expect &&
+       sed -n -e "/^$/q" -e "p" all-objects.bdl >actual &&
+       test_cmp expect actual
+'
+
 test_done