]> git.ipfire.org Git - thirdparty/git.git/commitdiff
Always check `parse_tree*()`'s return value
authorJohannes Schindelin <johannes.schindelin@gmx.de>
Fri, 23 Feb 2024 08:34:23 +0000 (08:34 +0000)
committerJunio C Hamano <gitster@pobox.com>
Fri, 23 Feb 2024 18:19:40 +0000 (10:19 -0800)
Otherwise we may easily run into serious crashes: For example, if we run
`init_tree_desc()` directly after a failed `parse_tree()`, we are
accessing uninitialized data or trying to dereference `NULL`.

Note that the `parse_tree()` function already takes care of showing an
error message. The `parse_tree_indirectly()` and
`repo_get_commit_tree()` functions do not, therefore those latter call
sites need to show a useful error message while the former do not.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
12 files changed:
builtin/checkout.c
builtin/clone.c
builtin/commit.c
builtin/merge-tree.c
builtin/read-tree.c
builtin/reset.c
cache-tree.c
merge-ort.c
merge-recursive.c
merge.c
reset.c
sequencer.c

index f02434bc155ba1769a248350afa686322e6110bb..9ab0901d6291f49a34bdb0c071a2c1c049fc4bf8 100644 (file)
@@ -707,7 +707,8 @@ static int reset_tree(struct tree *tree, const struct checkout_opts *o,
        init_checkout_metadata(&opts.meta, info->refname,
                               info->commit ? &info->commit->object.oid : null_oid(),
                               NULL);
-       parse_tree(tree);
+       if (parse_tree(tree) < 0)
+               return 128;
        init_tree_desc(&tree_desc, tree->buffer, tree->size);
        switch (unpack_trees(1, &tree_desc, &opts)) {
        case -2:
@@ -786,9 +787,15 @@ static int merge_working_tree(const struct checkout_opts *opts,
                if (new_branch_info->commit)
                        BUG("'switch --orphan' should never accept a commit as starting point");
                new_tree = parse_tree_indirect(the_hash_algo->empty_tree);
-       } else
+               if (!new_tree)
+                       BUG("unable to read empty tree");
+       } else {
                new_tree = repo_get_commit_tree(the_repository,
                                                new_branch_info->commit);
+               if (!new_tree)
+                       return error(_("unable to read tree (%s)"),
+                                    oid_to_hex(&new_branch_info->commit->object.oid));
+       }
        if (opts->discard_changes) {
                ret = reset_tree(new_tree, opts, 1, writeout_error, new_branch_info);
                if (ret)
@@ -823,7 +830,8 @@ static int merge_working_tree(const struct checkout_opts *opts,
                                oid_to_hex(old_commit_oid));
 
                init_tree_desc(&trees[0], tree->buffer, tree->size);
-               parse_tree(new_tree);
+               if (parse_tree(new_tree) < 0)
+                       exit(128);
                tree = new_tree;
                init_tree_desc(&trees[1], tree->buffer, tree->size);
 
@@ -1239,10 +1247,15 @@ static void setup_new_branch_info_and_source_tree(
        if (!new_branch_info->commit) {
                /* not a commit */
                *source_tree = parse_tree_indirect(rev);
+               if (!*source_tree)
+                       die(_("unable to read tree (%s)"), oid_to_hex(rev));
        } else {
                parse_commit_or_die(new_branch_info->commit);
                *source_tree = repo_get_commit_tree(the_repository,
                                                    new_branch_info->commit);
+               if (!*source_tree)
+                       die(_("unable to read tree (%s)"),
+                           oid_to_hex(&new_branch_info->commit->object.oid));
        }
 }
 
index c6357af949895a688639c83984598931906b2690..4410b55be98da921c3bf556fec6e58b06cf06c4a 100644 (file)
@@ -736,7 +736,8 @@ static int checkout(int submodule_progress, int filter_submodules)
        tree = parse_tree_indirect(&oid);
        if (!tree)
                die(_("unable to parse commit %s"), oid_to_hex(&oid));
-       parse_tree(tree);
+       if (parse_tree(tree) < 0)
+               exit(128);
        init_tree_desc(&t, tree->buffer, tree->size);
        if (unpack_trees(1, &t, &opts) < 0)
                die(_("unable to checkout working tree"));
index 781af2e206c1060213f16dd7cacb5ca68884f6b8..0723f06de7af183a7d0c4f247dc8ee12ed099667 100644 (file)
@@ -339,7 +339,8 @@ static void create_base_index(const struct commit *current_head)
        tree = parse_tree_indirect(&current_head->object.oid);
        if (!tree)
                die(_("failed to unpack HEAD tree object"));
-       parse_tree(tree);
+       if (parse_tree(tree) < 0)
+               exit(128);
        init_tree_desc(&t, tree->buffer, tree->size);
        if (unpack_trees(1, &t, &opts))
                exit(128); /* We've already reported the error, finish dying */
index 2d4ce5b388699ec8ec4aa658d04de0abaa6f1557..3492a575a6c784e01a21a4bf5f458124f636c4cb 100644 (file)
@@ -447,12 +447,18 @@ static int real_merge(struct merge_tree_options *o,
                if (repo_get_oid_treeish(the_repository, merge_base, &base_oid))
                        die(_("could not parse as tree '%s'"), merge_base);
                base_tree = parse_tree_indirect(&base_oid);
+               if (!base_tree)
+                       die(_("unable to read tree (%s)"), oid_to_hex(&base_oid));
                if (repo_get_oid_treeish(the_repository, branch1, &head_oid))
                        die(_("could not parse as tree '%s'"), branch1);
                parent1_tree = parse_tree_indirect(&head_oid);
+               if (!parent1_tree)
+                       die(_("unable to read tree (%s)"), oid_to_hex(&head_oid));
                if (repo_get_oid_treeish(the_repository, branch2, &merge_oid))
                        die(_("could not parse as tree '%s'"), branch2);
                parent2_tree = parse_tree_indirect(&merge_oid);
+               if (!parent2_tree)
+                       die(_("unable to read tree (%s)"), oid_to_hex(&merge_oid));
 
                opt.ancestor = merge_base;
                merge_incore_nonrecursive(&opt, base_tree, parent1_tree, parent2_tree, &result);
index 8196ca9dd85828890cf5e7088d19e51990a00c66..5923ed36893b0ecae1615c0cd274c7d1dc2b7182 100644 (file)
@@ -263,7 +263,8 @@ int cmd_read_tree(int argc, const char **argv, const char *cmd_prefix)
        cache_tree_free(&the_index.cache_tree);
        for (i = 0; i < nr_trees; i++) {
                struct tree *tree = trees[i];
-               parse_tree(tree);
+               if (parse_tree(tree) < 0)
+                       return 128;
                init_tree_desc(t+i, tree->buffer, tree->size);
        }
        if (unpack_trees(nr_trees, t, &opts))
index 4b018d20e3b2200e44a04f1f759837a571e4bc4f..fd36fc5bd959121a959e22a2ba1c88ee41fbde7b 100644 (file)
@@ -119,6 +119,10 @@ static int reset_index(const char *ref, const struct object_id *oid, int reset_t
 
        if (reset_type == MIXED || reset_type == HARD) {
                tree = parse_tree_indirect(oid);
+               if (!tree) {
+                       error(_("unable to read tree (%s)"), oid_to_hex(oid));
+                       goto out;
+               }
                prime_cache_tree(the_repository, the_repository->index, tree);
        }
 
index 641427ed410af39be80be22460a103dbad2d3d35..c6508b64a5c81083e263e323b78a3aa60ac48af2 100644 (file)
@@ -779,8 +779,8 @@ static void prime_cache_tree_rec(struct repository *r,
                        struct cache_tree_sub *sub;
                        struct tree *subtree = lookup_tree(r, &entry.oid);
 
-                       if (!subtree->object.parsed)
-                               parse_tree(subtree);
+                       if (!subtree->object.parsed && parse_tree(subtree) < 0)
+                               exit(128);
                        sub = cache_tree_sub(it, entry.path);
                        sub->cache_tree = cache_tree();
 
index 79d9e18f63dca282bd72cddcc9fe22a350f1af6d..910ba38ff055d8cda85688ebc4a62afc81108308 100644 (file)
@@ -4983,6 +4983,9 @@ redo:
 
        if (result->clean >= 0) {
                result->tree = parse_tree_indirect(&working_tree_oid);
+               if (!result->tree)
+                       die(_("unable to read tree (%s)"),
+                           oid_to_hex(&working_tree_oid));
                /* existence of conflicted entries implies unclean */
                result->clean &= strmap_empty(&opt->priv->conflicted);
        }
index e3beb0801b115691d84b5da3403bc52abcb97336..10d41bfd48702a5523ebaa4b567f9ecea7ede700 100644 (file)
@@ -410,7 +410,8 @@ static inline int merge_detect_rename(struct merge_options *opt)
 
 static void init_tree_desc_from_tree(struct tree_desc *desc, struct tree *tree)
 {
-       parse_tree(tree);
+       if (parse_tree(tree) < 0)
+               exit(128);
        init_tree_desc(desc, tree->buffer, tree->size);
 }
 
diff --git a/merge.c b/merge.c
index b60925459c292bbb4a9daae46534edfbb3eca756..14a7325859d72cbae11bb3be8d6462cf85b845ba 100644 (file)
--- a/merge.c
+++ b/merge.c
@@ -80,7 +80,10 @@ int checkout_fast_forward(struct repository *r,
                return -1;
        }
        for (i = 0; i < nr_trees; i++) {
-               parse_tree(trees[i]);
+               if (parse_tree(trees[i]) < 0) {
+                       rollback_lock_file(&lock_file);
+                       return -1;
+               }
                init_tree_desc(t+i, trees[i]->buffer, trees[i]->size);
        }
 
diff --git a/reset.c b/reset.c
index 48da0adf851e1b09edfc22ffbbc0b1128cbbc5ab..080bcb6d656c2c8960ffef59f2298870871cc2cb 100644 (file)
--- a/reset.c
+++ b/reset.c
@@ -158,6 +158,11 @@ int reset_head(struct repository *r, const struct reset_head_opts *opts)
        }
 
        tree = parse_tree_indirect(oid);
+       if (!tree) {
+               ret = error(_("unable to read tree (%s)"), oid_to_hex(oid));
+               goto leave_reset_head;
+       }
+
        prime_cache_tree(r, r->index, tree);
 
        if (write_locked_index(r->index, &lock, COMMIT_LOCK) < 0) {
index d584cac8ed9307caad0f8a9ede98d1f57ceab874..33d12b2ffd16b89c8d4c589680d1dd4706a4f73c 100644 (file)
@@ -715,6 +715,8 @@ static int do_recursive_merge(struct repository *r,
        o.show_rename_progress = 1;
 
        head_tree = parse_tree_indirect(head);
+       if (!head_tree)
+               return error(_("unable to read tree (%s)"), oid_to_hex(head));
        next_tree = next ? repo_get_commit_tree(r, next) : empty_tree(r);
        base_tree = base ? repo_get_commit_tree(r, base) : empty_tree(r);
 
@@ -3887,6 +3889,8 @@ static int do_reset(struct repository *r,
        }
 
        tree = parse_tree_indirect(&oid);
+       if (!tree)
+               return error(_("unable to read tree (%s)"), oid_to_hex(&oid));
        prime_cache_tree(r, r->index, tree);
 
        if (write_locked_index(r->index, &lock, COMMIT_LOCK) < 0)