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