diff mbox series

[15/20] remote: fix leaking config strings

Message ID 97346d6f944e3587a08d96a5e1b4ead8df8a0bc0.1724159575.git.ps@pks.im (mailing list archive)
State Superseded
Headers show
Series Memory leak fixes (pt.5) | expand

Commit Message

Patrick Steinhardt Aug. 20, 2024, 2:05 p.m. UTC
We're leaking several config strings when assembling remotes, either
because we do not free preceding values in case a config was set
multiple times, or because we do not free them when releasing the remote
state. Plug those leaks.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 remote.c | 10 +++++++++-
 1 file changed, 9 insertions(+), 1 deletion(-)

Comments

Junio C Hamano Aug. 21, 2024, 5:58 p.m. UTC | #1
Patrick Steinhardt <ps@pks.im> writes:

> @@ -2802,6 +2809,7 @@ void remote_state_clear(struct remote_state *remote_state)
>  	for (i = 0; i < remote_state->remotes_nr; i++)
>  		remote_clear(remote_state->remotes[i]);
>  	FREE_AND_NULL(remote_state->remotes);
> +	FREE_AND_NULL(remote_state->pushremote_name);
>  	remote_state->remotes_alloc = 0;
>  	remote_state->remotes_nr = 0;

As remote_state has two extra structures embedded in it, I wonder if
we should be clearing them in this function, but possibly it is
cleared elsewhere or perhaps in a later series?

As the focus of this step is about strings that we obtained from the
config API, it is totally outside the scope of this topic, even if
it turns out to be needed to clear them.

Looking good.  Thanks.
Patrick Steinhardt Aug. 22, 2024, 8:19 a.m. UTC | #2
On Wed, Aug 21, 2024 at 10:58:55AM -0700, Junio C Hamano wrote:
> Patrick Steinhardt <ps@pks.im> writes:
> 
> > @@ -2802,6 +2809,7 @@ void remote_state_clear(struct remote_state *remote_state)
> >  	for (i = 0; i < remote_state->remotes_nr; i++)
> >  		remote_clear(remote_state->remotes[i]);
> >  	FREE_AND_NULL(remote_state->remotes);
> > +	FREE_AND_NULL(remote_state->pushremote_name);
> >  	remote_state->remotes_alloc = 0;
> >  	remote_state->remotes_nr = 0;
> 
> As remote_state has two extra structures embedded in it, I wonder if
> we should be clearing them in this function, but possibly it is
> cleared elsewhere or perhaps in a later series?

It is not yet part of any subsequent patch series, mostly because I
didn't happen to stumble over such leaks yet. Both of the rewrites very
much are leaky though, and would be hit when we use "insteadOf" or
"pushInsteadOf" configs.

The `struct branch` also needs handling and is being populated via
"branch" configs.

> As the focus of this step is about strings that we obtained from the
> config API, it is totally outside the scope of this topic, even if
> it turns out to be needed to clear them.

Well, these are being populated via config strings. So I'd rather fix
them in this commit, as well.

Patrick
Junio C Hamano Aug. 22, 2024, 4:04 p.m. UTC | #3
Patrick Steinhardt <ps@pks.im> writes:

> On Wed, Aug 21, 2024 at 10:58:55AM -0700, Junio C Hamano wrote:
>> Patrick Steinhardt <ps@pks.im> writes:
>> 
>> > @@ -2802,6 +2809,7 @@ void remote_state_clear(struct remote_state *remote_state)
>> >  	for (i = 0; i < remote_state->remotes_nr; i++)
>> >  		remote_clear(remote_state->remotes[i]);
>> >  	FREE_AND_NULL(remote_state->remotes);
>> > +	FREE_AND_NULL(remote_state->pushremote_name);
>> >  	remote_state->remotes_alloc = 0;
>> >  	remote_state->remotes_nr = 0;
>> 
>> As remote_state has two extra structures embedded in it, I wonder if
>> we should be clearing them in this function, but possibly it is
>> cleared elsewhere or perhaps in a later series?
>
> It is not yet part of any subsequent patch series, mostly because I
> didn't happen to stumble over such leaks yet. Both of the rewrites very
> much are leaky though, and would be hit when we use "insteadOf" or
> "pushInsteadOf" configs.

Yes, I was wondering if our test coverage for the feature is
lacking.  In a sense, leaks from these insteadOf configuration
variables are tiny and uninteresting, compared to how much it
bothers me to find us not testing these often used features.
diff mbox series

Patch

diff --git a/remote.c b/remote.c
index 7d5b8f750d8..3087437bc61 100644
--- a/remote.c
+++ b/remote.c
@@ -373,8 +373,10 @@  static int handle_config(const char *key, const char *value,
 			return -1;
 		branch = make_branch(remote_state, name, namelen);
 		if (!strcmp(subkey, "remote")) {
+			FREE_AND_NULL(branch->remote_name);
 			return git_config_string(&branch->remote_name, key, value);
 		} else if (!strcmp(subkey, "pushremote")) {
+			FREE_AND_NULL(branch->pushremote_name);
 			return git_config_string(&branch->pushremote_name, key, value);
 		} else if (!strcmp(subkey, "merge")) {
 			if (!value)
@@ -406,9 +408,11 @@  static int handle_config(const char *key, const char *value,
 		return 0;
 
 	/* Handle remote.* variables */
-	if (!name && !strcmp(subkey, "pushdefault"))
+	if (!name && !strcmp(subkey, "pushdefault")) {
+		FREE_AND_NULL(remote_state->pushremote_name);
 		return git_config_string(&remote_state->pushremote_name, key,
 					 value);
+	}
 
 	if (!name)
 		return 0;
@@ -475,12 +479,15 @@  static int handle_config(const char *key, const char *value,
 		else if (!strcmp(value, "--tags"))
 			remote->fetch_tags = 2;
 	} else if (!strcmp(subkey, "proxy")) {
+		FREE_AND_NULL(remote->http_proxy);
 		return git_config_string(&remote->http_proxy,
 					 key, value);
 	} else if (!strcmp(subkey, "proxyauthmethod")) {
+		FREE_AND_NULL(remote->http_proxy_authmethod);
 		return git_config_string(&remote->http_proxy_authmethod,
 					 key, value);
 	} else if (!strcmp(subkey, "vcs")) {
+		FREE_AND_NULL(remote->foreign_vcs);
 		return git_config_string(&remote->foreign_vcs, key, value);
 	}
 	return 0;
@@ -2802,6 +2809,7 @@  void remote_state_clear(struct remote_state *remote_state)
 	for (i = 0; i < remote_state->remotes_nr; i++)
 		remote_clear(remote_state->remotes[i]);
 	FREE_AND_NULL(remote_state->remotes);
+	FREE_AND_NULL(remote_state->pushremote_name);
 	remote_state->remotes_alloc = 0;
 	remote_state->remotes_nr = 0;