diff mbox series

[v2,1/2] builtin/checkout: simplify metadata initialization

Message ID 20200521020712.1620993-2-sandals@crustytoothpaste.net (mailing list archive)
State New, archived
Headers show
Series Improve Fix code coverage for checkout | expand

Commit Message

brian m. carlson May 21, 2020, 2:07 a.m. UTC
When we call init_checkout_metadata in reset_tree, we want to pass the
object ID of the commit in question so that it can be passed to filters,
or if there is no commit, the tree.  We anticipated this latter case,
which can occur elsewhere in the checkout code, but it cannot occur
here.  The only case in which we do not have a commit object is when
invoking git switch with --orphan.  Moreover, we can only hit this code
path without a commit object additionally with either --force or
--discard-changes.

In such a case, there is no point initializing the checkout metadata
with a commit or tree because (a) there is no commit, only the empty
tree, and (b) we will never use the data, since no files will be smudged
when checking out a branch with no files.  Pass the all-zeros object ID
in this case, since we just need some value which is a valid pointer.

Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
---
 builtin/checkout.c | 4 +---
 1 file changed, 1 insertion(+), 3 deletions(-)

Comments

Junio C Hamano May 21, 2020, 5:35 p.m. UTC | #1
"brian m. carlson" <sandals@crustytoothpaste.net> writes:

> ...  The only case in which we do not have a commit object is when
> invoking git switch with --orphan.  Moreover, we can only hit this code
> path without a commit object additionally with either --force or
> --discard-changes.

It was easy for me to trace the codepath to see when these options
are used we end up with no commit object, but I ran out of time
trying to see if the "forced orphan" is the only way to end up with
a NULL in new_branch_info->commit.  Assuming that is true, of course
the following perfectly makes sense.

> In such a case, there is no point initializing the checkout metadata
> with a commit or tree because (a) there is no commit, only the empty
> tree, and (b) we will never use the data, since no files will be smudged
> when checking out a branch with no files.  Pass the all-zeros object ID
> in this case, since we just need some value which is a valid pointer.
>
> Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
> ---
>  builtin/checkout.c | 4 +---
>  1 file changed, 1 insertion(+), 3 deletions(-)

Thanks.

> diff --git a/builtin/checkout.c b/builtin/checkout.c
> index e9d111bb83..62b5e371bc 100644
> --- a/builtin/checkout.c
> +++ b/builtin/checkout.c
> @@ -621,9 +621,7 @@ static int reset_tree(struct tree *tree, const struct checkout_opts *o,
>  	opts.src_index = &the_index;
>  	opts.dst_index = &the_index;
>  	init_checkout_metadata(&opts.meta, info->refname,
> -			       info->commit ? &info->commit->object.oid :
> -			       is_null_oid(&info->oid) ? &tree->object.oid :
> -			       &info->oid,
> +			       info->commit ? &info->commit->object.oid : &null_oid,
>  			       NULL);
>  	parse_tree(tree);
>  	init_tree_desc(&tree_desc, tree->buffer, tree->size);
brian m. carlson May 23, 2020, 12:22 p.m. UTC | #2
On 2020-05-21 at 17:35:22, Junio C Hamano wrote:
> "brian m. carlson" <sandals@crustytoothpaste.net> writes:
> 
> > ...  The only case in which we do not have a commit object is when
> > invoking git switch with --orphan.  Moreover, we can only hit this code
> > path without a commit object additionally with either --force or
> > --discard-changes.
> 
> It was easy for me to trace the codepath to see when these options
> are used we end up with no commit object, but I ran out of time
> trying to see if the "forced orphan" is the only way to end up with
> a NULL in new_branch_info->commit.  Assuming that is true, of course
> the following perfectly makes sense.

I believe it is.  The only case in which we have a NULL commit as far as
I can tell is with switch and an orphan, and in merge_working_tree we
call reset_tree either if the changes are discarded or unpack_trees
couldn't do a trivial merge.  Since I'm pretty sure unpack_trees can
indeed merge with the empty tree, we would only call reset_trees with
--discard-changes or --force.  And reset_tree is only called from
merge_working_tree.

In addition, I did try other situations plus the entire testsuite with
my erroneous first patch and was unable to cause a segfault anywhere
(which would have been a trivial NULL dereference) in case I missed
something, which leads me to believe that this is in fact the only
situation in which this occurs.
diff mbox series

Patch

diff --git a/builtin/checkout.c b/builtin/checkout.c
index e9d111bb83..62b5e371bc 100644
--- a/builtin/checkout.c
+++ b/builtin/checkout.c
@@ -621,9 +621,7 @@  static int reset_tree(struct tree *tree, const struct checkout_opts *o,
 	opts.src_index = &the_index;
 	opts.dst_index = &the_index;
 	init_checkout_metadata(&opts.meta, info->refname,
-			       info->commit ? &info->commit->object.oid :
-			       is_null_oid(&info->oid) ? &tree->object.oid :
-			       &info->oid,
+			       info->commit ? &info->commit->object.oid : &null_oid,
 			       NULL);
 	parse_tree(tree);
 	init_tree_desc(&tree_desc, tree->buffer, tree->size);