Skip to content

Commit

Permalink
remote: make match_refs() copy src ref before assigning to peer_ref
Browse files Browse the repository at this point in the history
In some instances, match_refs() sets the peer_ref field of refs in the
dst list such that it points to a ref in the src list. This prevents
callers from freeing both the src and dst lists, as doing so would cause
a double-free since free_refs() frees the peer_ref.

As well, the following configuration causes two refs in the dst list to
have the same peer_ref, which can also lead to a double-free:

  push = refs/heads/master:refs/heads/backup
  push = refs/heads/master:refs/heads/master

Existing callers of match_heads() call it only once and then terminate,
w/o ever bothering to free the src or dst lists, so this is not
currently a problem.

This patch modifies match_refs() to first copy any refs it plucks from
the src list before assigning them as a peer_ref. This allows
builtin-remote, a future caller, to free the src and dst lists.

Signed-off-by: Jay Soffian <jaysoffian@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
  • Loading branch information
Jay Soffian authored and Junio C Hamano committed Feb 27, 2009
1 parent 4229f1f commit cdf690e
Showing 1 changed file with 5 additions and 2 deletions.
7 changes: 5 additions & 2 deletions remote.c
Original file line number Diff line number Diff line change
Expand Up @@ -936,6 +936,7 @@ static int match_explicit(struct ref *src, struct ref *dst,
struct refspec *rs)
{
struct ref *matched_src, *matched_dst;
int copy_src;

const char *dst_value = rs->dst;
char *dst_guess;
Expand All @@ -946,6 +947,7 @@ static int match_explicit(struct ref *src, struct ref *dst,
matched_src = matched_dst = NULL;
switch (count_refspec_match(rs->src, src, &matched_src)) {
case 1:
copy_src = 1;
break;
case 0:
/* The source could be in the get_sha1() format
Expand All @@ -955,6 +957,7 @@ static int match_explicit(struct ref *src, struct ref *dst,
matched_src = try_explicit_object_name(rs->src);
if (!matched_src)
return error("src refspec %s does not match any.", rs->src);
copy_src = 0;
break;
default:
return error("src refspec %s matches more than one.", rs->src);
Expand Down Expand Up @@ -1000,7 +1003,7 @@ static int match_explicit(struct ref *src, struct ref *dst,
return error("dst ref %s receives from more than one src.",
matched_dst->name);
else {
matched_dst->peer_ref = matched_src;
matched_dst->peer_ref = copy_src ? copy_ref(matched_src) : matched_src;
matched_dst->force = rs->force;
}
return 0;
Expand Down Expand Up @@ -1108,7 +1111,7 @@ int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,
dst_peer = make_linked_ref(dst_name, dst_tail);
hashcpy(dst_peer->new_sha1, src->new_sha1);
}
dst_peer->peer_ref = src;
dst_peer->peer_ref = copy_ref(src);
dst_peer->force = pat->force;
free_name:
free(dst_name);
Expand Down

0 comments on commit cdf690e

Please sign in to comment.