On Wed, May 23, 2018 at 01:46:13PM -0700, Elijah Newren wrote:

> In commit 2122f8b963d4 ("rev-parse: Add support for the ^! and ^@ syntax",
> 2008-07-26), try_parent_shorthands() was introduced to parse the special
> ^! and ^@ syntax.  However, it did not check the commit returned from
> lookup_commit_reference() before proceeding to use it.  If it is NULL,
> bail early and notify the caller that this cannot be a valid revision
> range.

Yep, this is definitely the right track. But...

> diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c
> index 55c0b90441..4e9ba9641a 100644
> --- a/builtin/rev-parse.c
> +++ b/builtin/rev-parse.c
> @@ -334,6 +334,8 @@ static int try_parent_shorthands(const char *arg)
>       }
>  
>       commit = lookup_commit_reference(&oid);
> +     if (!commit)
> +             return 1;
>       if (exclude_parent &&
>           exclude_parent > commit_list_count(commit->parents)) {
>               *dotdot = '^';

...I don't think this is quite right. I see two issues:

  1. We need to restore "*dotdot" like the other exit code-paths do.

  2. I think a return of 1 means "yes, I handled this". We want to
     return 0 so that the bogus name eventually triggers an error.

I also wondered if we need to print an error message, but since we are
using the non-gentle form of lookup_commit_reference(), it will complain
for us (and then the caller will issue some errors as well).

It might make sense to just lump this into the get_oid check above.
E.g., something like:

  if (get_oid_committish(arg, &oid) ||
      !(commit = lookup_commit_reference(&oid))) {
          *dotdot = '^';
          return 0;
  }

though I am fine with it either way.

> diff --git a/t/t6101-rev-parse-parents.sh b/t/t6101-rev-parse-parents.sh
> index 7b1b2dbdf2..f91cc417bd 100755
> --- a/t/t6101-rev-parse-parents.sh
> +++ b/t/t6101-rev-parse-parents.sh
> @@ -214,7 +214,7 @@ test_expect_success 'rev-list merge^-1x (garbage after 
> ^-1)' '
>       test_must_fail git rev-list merge^-1x
>  '
>  
> -test_expect_failure 'rev-parse $garbage^@ should not segfault' '
> +test_expect_success 'rev-parse $garbage^@ should not segfault' '
>       git rev-parse ffffffffffffffffffffffffffffffffffffffff^@
>  '

Once we flip the return value as above, I think this needs to be
test_must_fail, which matches how I'd expect it to behave.

This code (sadly) duplicates the functionality in revision.c. I checked
there to see if it has the same problem, but it's fine.

Unfortunately I think rev-parse has one other instance, though:

  bogus=ffffffffffffffffffffffffffffffffffffffff

  # this is ok; we just normalize to "$bogus ^$bogus" without looking at
  # the object, which is OK
  git rev-parse $bogus..$bogus

  # this segfaults, because we try to feed NULL to get_merge_bases()
  git rev-parse $bogus...$bogus

We should probably fix that at the same time.

-Peff

Reply via email to