From: Jeff King <peff@peff.net>
To: Eric Sunshine <sunshine@sunshineco.com>
Cc: Git List <git@vger.kernel.org>
Subject: Re: [PATCH 02/12] remote.c: drop "remote" pointer from "struct branch"
Date: Thu, 7 May 2015 05:33:34 -0400 [thread overview]
Message-ID: <20150507093333.GA14524@peff.net> (raw)
In-Reply-To: <20150505193105.GE10463@peff.net>
On Tue, May 05, 2015 at 03:31:05PM -0400, Jeff King wrote:
> One thing I did notice while looking at this is that it seems like we
> may leak if you call branch_get multiple times. The make_branch()
> function may sometimes return a brand-new branch and sometimes return a
> cached version from the "branches" array. In the latter case, we
> continue to update the "remote" pointer (which is wasteful but at least
> does not leak because the remotes themselves are part of a cached list).
> But then we will repeatedly re-allocate the ret->merge array. We
> probably should make sure it is NULL before trying to fill it in.
>
> I'll see if I can insert a cleanup patch in this part of the series.
Here's what I came up with. I'm sending it separately in case you have
any early comments, but it will be part of the next re-roll (just before
the existing patch 2 we're discussing here).
-- >8 --
Subject: remote.c: refactor setup of branch->merge list
When we call branch_get() to lookup or create a "struct
branch", we make sure the "merge" field is filled in so that
callers can access it. But the conditions under which we do
so are a little confusing, and can lead to two funny
situations:
1. If there's no branch.*.remote config, we cannot provide
branch->merge (because it is really just an application
of branch.*.merge to our remote's refspecs). But
branch->merge_nr may be non-zero, leading callers to be
believe they can access branch->merge (e.g., in
branch_merge_matches and elsewhere).
It doesn't look like this can cause a segfault in
practice, as most code paths dealing with merge config
will bail early if there is no remote defined. But it's
a bit of a dangerous construct.
We can fix this by setting merge_nr to "0" explicitly
when we realize that we have no merge config. Note that
merge_nr also counts the "merge_name" fields (which we
_do_ have; that's how merge_nr got incremented), so we
will "lose" access to them, in the sense that we forget
how many we had. But no callers actually care; we use
merge_name only while iteratively reading the config,
and then convert it to the final "merge" form the first
time somebody calls branch_get().
2. We set up the "merge" field every time branch_get is
called, even if it has already been done. This leaks
memory.
It's not a big deal in practice, since most code paths
will access only one branch, or perhaps each branch
only one time. But if you want to be pathological, you
can leak arbitrary memory with:
yes @{upstream} | head -1000 | git rev-list --stdin
We can fix this by skipping setup when branch->merge is
already non-NULL.
In addition to those two fixes, this patch pushes the "do we
need to setup merge?" logic down into set_merge, where it is
a bit easier to follow.
Signed-off-by: Jeff King <peff@peff.net>
---
remote.c | 19 +++++++++++++++----
1 file changed, 15 insertions(+), 4 deletions(-)
diff --git a/remote.c b/remote.c
index bec8b31..ac17e66 100644
--- a/remote.c
+++ b/remote.c
@@ -1636,6 +1636,19 @@ static void set_merge(struct branch *ret)
unsigned char sha1[20];
int i;
+ if (!ret)
+ return; /* no branch */
+ if (ret->merge)
+ return; /* already run */
+ if (!ret->remote_name || !ret->merge_nr) {
+ /*
+ * no merge config; let's make sure we don't confuse callers
+ * with a non-zero merge_nr but a NULL merge
+ */
+ ret->merge_nr = 0;
+ return;
+ }
+
ret->merge = xcalloc(ret->merge_nr, sizeof(*ret->merge));
for (i = 0; i < ret->merge_nr; i++) {
ret->merge[i] = xcalloc(1, sizeof(**ret->merge));
@@ -1660,11 +1673,9 @@ struct branch *branch_get(const char *name)
ret = current_branch;
else
ret = make_branch(name, 0);
- if (ret && ret->remote_name) {
+ if (ret && ret->remote_name)
ret->remote = remote_get(ret->remote_name);
- if (ret->merge_nr)
- set_merge(ret);
- }
+ set_merge(ret);
return ret;
}
--
2.4.0.488.gf55b16a
next prev parent reply other threads:[~2015-05-07 9:33 UTC|newest]
Thread overview: 21+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-05-01 22:44 [PATCH v2 0/12] implement @{push} shorthand Jeff King
2015-05-01 22:44 ` [PATCH 01/12] remote.c: drop default_remote_name variable Jeff King
2015-05-01 22:45 ` [PATCH 02/12] remote.c: drop "remote" pointer from "struct branch" Jeff King
2015-05-03 3:34 ` Eric Sunshine
2015-05-05 19:31 ` Jeff King
2015-05-07 9:33 ` Jeff King [this message]
2015-05-01 22:45 ` [PATCH 03/12] remote.c: hoist branch.*.remote lookup out of remote_get_1 Jeff King
2015-05-01 22:46 ` [PATCH 04/12] remote.c: provide per-branch pushremote name Jeff King
2015-05-03 4:51 ` Eric Sunshine
2015-05-05 19:33 ` Jeff King
2015-05-05 19:48 ` Eric Sunshine
2015-05-07 9:38 ` Jeff King
2015-05-08 16:13 ` Eric Sunshine
2015-05-01 22:47 ` [PATCH 05/12] remote.c: introduce branch_get_upstream helper Jeff King
2015-05-01 22:52 ` [PATCH 06/12] remote.c: report specific errors from branch_get_upstream Jeff King
2015-05-01 22:53 ` [PATCH 07/12] remote.c: add branch_get_push Jeff King
2015-05-01 22:53 ` [PATCH 08/12] sha1_name: refactor upstream_mark Jeff King
2015-05-01 22:55 ` [PATCH 09/12] sha1_name: refactor interpret_upstream_mark Jeff King
2015-05-01 22:55 ` [PATCH 10/12] sha1_name: implement @{push} shorthand Jeff King
2015-05-01 22:55 ` [PATCH 11/12] for-each-ref: use skip_prefix instead of starts_with Jeff King
2015-05-01 22:56 ` [PATCH 12/12] for-each-ref: accept "%(push)" format Jeff King
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20150507093333.GA14524@peff.net \
--to=peff@peff.net \
--cc=git@vger.kernel.org \
--cc=sunshine@sunshineco.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).