Git development
 help / color / mirror / Atom feed
* [Crash] git-push $remote $non_ref:$anything
@ 2008-06-15 19:38 Mike Hommey
  2008-06-15 19:55 ` Jeff King
  0 siblings, 1 reply; 5+ messages in thread
From: Mike Hommey @ 2008-06-15 19:38 UTC (permalink / raw)
  To: git

Hi,

I somehow managed to get a segfault by running this:

git push origin non-existant-branch-name:non-existant-branch-name

FWIW, the output looks like this:

error: src refspec patches/uri-handlers does not match any.
Segmentation fault
fatal: The remote end hung up unexpectedly

I don't have time to dig into this, unfortunately.

Mike

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [Crash] git-push $remote $non_ref:$anything
  2008-06-15 19:38 [Crash] git-push $remote $non_ref:$anything Mike Hommey
@ 2008-06-15 19:55 ` Jeff King
  2008-06-15 21:06   ` Daniel Barkalow
  0 siblings, 1 reply; 5+ messages in thread
From: Jeff King @ 2008-06-15 19:55 UTC (permalink / raw)
  To: Mike Hommey; +Cc: Daniel Barkalow, git

[cc'ing Daniel for remote.c advice]

On Sun, Jun 15, 2008 at 09:38:23PM +0200, Mike Hommey wrote:

> I somehow managed to get a segfault by running this:
> 
> git push origin non-existant-branch-name:non-existant-branch-name

Hmm. The problem is the ref-guessing code. Given "git push foo:bar",
when we try to figure out what "bar" means we first try to find
refs/heads/bar or refs/heads/bar on the remote. But if that fails, we
are pushing a new item, so we try to use the same prefix as what "foo"
resolved to (e.g., if "foo" is a branch, we make it "refs/heads/bar").

So if "foo" doesn't resolve, we end up dereferencing NULL as part of our
guess. And the fix is obvious and the patch is below.

But it kind of makes me wonder why we bother looking at the dst side of
the refspec at all, since the src has already failed. Is there a good
reason not to just bail from match_explicit when we can't resolve the
src?

---
diff --git a/remote.c b/remote.c
index 91e3b11..fd8c71a 100644
--- a/remote.c
+++ b/remote.c
@@ -920,7 +920,8 @@ static int match_explicit(struct ref *src, struct ref *dst,
 	case 0:
 		if (!memcmp(dst_value, "refs/", 5))
 			matched_dst = make_linked_ref(dst_value, dst_tail);
-		else if((dst_guess = guess_ref(dst_value, matched_src)))
+		else if(matched_src &&
+			(dst_guess = guess_ref(dst_value, matched_src)))
 			matched_dst = make_linked_ref(dst_guess, dst_tail);
 		else
 			error("unable to push to unqualified destination: %s\n"

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [Crash] git-push $remote $non_ref:$anything
  2008-06-15 19:55 ` Jeff King
@ 2008-06-15 21:06   ` Daniel Barkalow
  2008-06-16 16:15     ` Jeff King
  0 siblings, 1 reply; 5+ messages in thread
From: Daniel Barkalow @ 2008-06-15 21:06 UTC (permalink / raw)
  To: Jeff King; +Cc: Mike Hommey, git

On Sun, 15 Jun 2008, Jeff King wrote:

> [cc'ing Daniel for remote.c advice]
> 
> On Sun, Jun 15, 2008 at 09:38:23PM +0200, Mike Hommey wrote:
> 
> > I somehow managed to get a segfault by running this:
> > 
> > git push origin non-existant-branch-name:non-existant-branch-name
> 
> Hmm. The problem is the ref-guessing code. Given "git push foo:bar",
> when we try to figure out what "bar" means we first try to find
> refs/heads/bar or refs/heads/bar on the remote. But if that fails, we
> are pushing a new item, so we try to use the same prefix as what "foo"
> resolved to (e.g., if "foo" is a branch, we make it "refs/heads/bar").
> 
> So if "foo" doesn't resolve, we end up dereferencing NULL as part of our
> guess. And the fix is obvious and the patch is below.
> 
> But it kind of makes me wonder why we bother looking at the dst side of
> the refspec at all, since the src has already failed. Is there a good
> reason not to just bail from match_explicit when we can't resolve the
> src?

The only thing I can think of is that a user might have made some mistake 
that would be more obvious with the error messages about both sides. Aside 
from that, it doesn't seem to have any possible effects anyway.

	-Daniel
*This .sig left intentionally blank*

^ permalink raw reply	[flat|nested] 5+ messages in thread

* Re: [Crash] git-push $remote $non_ref:$anything
  2008-06-15 21:06   ` Daniel Barkalow
@ 2008-06-16 16:15     ` Jeff King
  2008-06-16 16:17       ` Jeff King
  0 siblings, 1 reply; 5+ messages in thread
From: Jeff King @ 2008-06-16 16:15 UTC (permalink / raw)
  To: Daniel Barkalow; +Cc: Junio C Hamano, Mike Hommey, git

On Sun, Jun 15, 2008 at 05:06:52PM -0400, Daniel Barkalow wrote:

> The only thing I can think of is that a user might have made some mistake 
> that would be more obvious with the error messages about both sides. Aside 
> from that, it doesn't seem to have any possible effects anyway.

Hmm. Yes, looking at it more closely, I think the intent was to show
as many errors as possible. We report all errors for the source and
dest sides of every refspec before aborting.

I think the patch below is an improvement. Apologies for the long-winded
commit message, but it took me a while to figure out what was going on,
so I thought it worth explaining.

-- >8 --
clean up error conventions of remote.c:match_explicit

match_explicit is called for each push refspec to try to
fully resolve the source and destination sides of the
refspec.  Currently, we look at each refspec and report
errors on both the source and the dest side before aborting.

It makes sense to report errors for each refspec, since an
error in one is independent of an error in the other.
However, reporting errors on the 'dst' side of a refspec if
there has been an error on the 'src' side does not
necessarily make sense, since the interpretation of the
'dst' side depends on the 'src' side (for example, when
creating a new unqualified remote ref, we use the same type
as the src ref).

This patch lets match_explicit return early when the src
side of the refspec is bogus. We still look at all of the
refspecs before aborting the push, though.

At the same time, we clean up the call signature, which
previously took an extra "errs" flag. This was pointless, as
we didn't act on that flag, but rather just passed it back
to the caller. Instead, we now use the more traditional
"return -1" to signal an error, and the caller aggregates
the error count.

This change fixes two bugs, as well:

  - the early return avoids a segfault when passing a NULL
    matched_src to guess_ref()

  - the check for multiple sources pointing to a single dest
    aborted if the "err" flag was set. Presumably the intent
    was not to bother with the check if we had no
    matched_src. However, since the err flag was passed in
    from the caller, we might abort the check just because a
    previous refspec had a problem, which doesn't make
    sense.

    In practice, this didn't matter, since due to the error
    flag we end up aborting the push anyway.

Signed-off-by: Jeff King <peff@peff.net>
---
 remote.c |   25 ++++++++++---------------
 1 files changed, 10 insertions(+), 15 deletions(-)

diff --git a/remote.c b/remote.c
index 91e3b11..55a8f9c 100644
--- a/remote.c
+++ b/remote.c
@@ -867,8 +867,7 @@ static char *guess_ref(const char *name, struct ref *peer)
 
 static int match_explicit(struct ref *src, struct ref *dst,
 			  struct ref ***dst_tail,
-			  struct refspec *rs,
-			  int errs)
+			  struct refspec *rs)
 {
 	struct ref *matched_src, *matched_dst;
 
@@ -876,7 +875,7 @@ static int match_explicit(struct ref *src, struct ref *dst,
 	char *dst_guess;
 
 	if (rs->pattern || rs->matching)
-		return errs;
+		return 0;
 
 	matched_src = matched_dst = NULL;
 	switch (count_refspec_match(rs->src, src, &matched_src)) {
@@ -898,14 +897,12 @@ static int match_explicit(struct ref *src, struct ref *dst,
 	}
 
 	if (!matched_src)
-		errs = 1;
+		return -1;
 
 	if (!dst_value) {
 		unsigned char sha1[20];
 		int flag;
 
-		if (!matched_src)
-			return errs;
 		dst_value = resolve_ref(matched_src->name, sha1, 1, &flag);
 		if (!dst_value ||
 		    ((flag & REF_ISSYMREF) &&
@@ -936,18 +933,16 @@ static int match_explicit(struct ref *src, struct ref *dst,
 		      dst_value);
 		break;
 	}
-	if (errs || !matched_dst)
-		return 1;
-	if (matched_dst->peer_ref) {
-		errs = 1;
-		error("dst ref %s receives from more than one src.",
+	if (!matched_dst)
+		return -1;
+	if (matched_dst->peer_ref)
+		return error("dst ref %s receives from more than one src.",
 		      matched_dst->name);
-	}
 	else {
 		matched_dst->peer_ref = matched_src;
 		matched_dst->force = rs->force;
 	}
-	return errs;
+	return 0;
 }
 
 static int match_explicit_refs(struct ref *src, struct ref *dst,
@@ -956,8 +951,8 @@ static int match_explicit_refs(struct ref *src, struct ref *dst,
 {
 	int i, errs;
 	for (i = errs = 0; i < rs_nr; i++)
-		errs |= match_explicit(src, dst, dst_tail, &rs[i], errs);
-	return -errs;
+		errs += match_explicit(src, dst, dst_tail, &rs[i]);
+	return errs;
 }
 
 static const struct refspec *check_pattern_match(const struct refspec *rs,
-- 
1.5.6.rc3.8.gabbfb

^ permalink raw reply related	[flat|nested] 5+ messages in thread

* Re: [Crash] git-push $remote $non_ref:$anything
  2008-06-16 16:15     ` Jeff King
@ 2008-06-16 16:17       ` Jeff King
  0 siblings, 0 replies; 5+ messages in thread
From: Jeff King @ 2008-06-16 16:17 UTC (permalink / raw)
  To: Daniel Barkalow; +Cc: Junio C Hamano, Mike Hommey, git

On Mon, Jun 16, 2008 at 12:15:02PM -0400, Jeff King wrote:

>  	if (!matched_src)
> -		errs = 1;
> +		return -1;

This could maybe be cleaned up even more by just returning -1 at each
point where matched_src becomes NULL (in the switch statement above).

-Peff

^ permalink raw reply	[flat|nested] 5+ messages in thread

end of thread, other threads:[~2008-06-16 16:18 UTC | newest]

Thread overview: 5+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2008-06-15 19:38 [Crash] git-push $remote $non_ref:$anything Mike Hommey
2008-06-15 19:55 ` Jeff King
2008-06-15 21:06   ` Daniel Barkalow
2008-06-16 16:15     ` Jeff King
2008-06-16 16:17       ` Jeff King

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox