remote: fix leaking config strings

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. This includes config strings for "branch" sections, "insteadOf", "pushInsteadOf", and "pushDefault". Plug those leaks. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Patrick Steinhardt committed Aug 22, 2024 at 11:17 UTC f5ccb535ccfbabd55c2c7ab0b8e36ca5f322d31f
1 file changed +38 -2
remote.c
+38 -2
@@ -243,6 +243,17 @@ static struct branch *make_branch(struct remote_state *remote_state,
243 return ret;
244 }
245
246 +static void branch_release(struct branch *branch)
247 +{
248 + free((char *)branch->name);
249 + free((char *)branch->refname);
250 + free(branch->remote_name);
251 + free(branch->pushremote_name);
252 + for (int i = 0; i < branch->merge_nr; i++)
253 + refspec_item_clear(branch->merge[i]);
254 + free(branch->merge);
255 +}
256 +
257 static struct rewrite *make_rewrite(struct rewrites *r,
258 const char *base, size_t len)
259 {
@@ -263,6 +274,14 @@ static struct rewrite *make_rewrite(struct rewrites *r,
274 return ret;
275 }
276
277 +static void rewrites_release(struct rewrites *r)
278 +{
279 + for (int i = 0; i < r->rewrite_nr; i++)
280 + free((char *)r->rewrite[i]->base);
281 + free(r->rewrite);
282 + memset(r, 0, sizeof(*r));
283 +}
284 +
285 static void add_instead_of(struct rewrite *rewrite, const char *instead_of)
286 {
287 ALLOC_GROW(rewrite->instead_of, rewrite->instead_of_nr + 1, rewrite->instead_of_alloc);
@@ -373,8 +392,10 @@ static int handle_config(const char *key, const char *value,
392 return -1;
393 branch = make_branch(remote_state, name, namelen);
394 if (!strcmp(subkey, "remote")) {
395 + FREE_AND_NULL(branch->remote_name);
396 return git_config_string(&branch->remote_name, key, value);
397 } else if (!strcmp(subkey, "pushremote")) {
398 + FREE_AND_NULL(branch->pushremote_name);
399 return git_config_string(&branch->pushremote_name, key, value);
400 } else if (!strcmp(subkey, "merge")) {
401 if (!value)
@@ -406,9 +427,11 @@ static int handle_config(const char *key, const char *value,
427 return 0;
428
429 /* Handle remote.* variables */
409 - if (!name && !strcmp(subkey, "pushdefault"))
430 + if (!name && !strcmp(subkey, "pushdefault")) {
431 + FREE_AND_NULL(remote_state->pushremote_name);
432 return git_config_string(&remote_state->pushremote_name, key,
433 value);
434 + }
435
436 if (!name)
437 return 0;
@@ -475,12 +498,15 @@ static int handle_config(const char *key, const char *value,
498 else if (!strcmp(value, "--tags"))
499 remote->fetch_tags = 2;
500 } else if (!strcmp(subkey, "proxy")) {
501 + FREE_AND_NULL(remote->http_proxy);
502 return git_config_string(&remote->http_proxy,
503 key, value);
504 } else if (!strcmp(subkey, "proxyauthmethod")) {
505 + FREE_AND_NULL(remote->http_proxy_authmethod);
506 return git_config_string(&remote->http_proxy_authmethod,
507 key, value);
508 } else if (!strcmp(subkey, "vcs")) {
509 + FREE_AND_NULL(remote->foreign_vcs);
510 return git_config_string(&remote->foreign_vcs, key, value);
511 }
512 return 0;
@@ -2797,16 +2823,26 @@ struct remote_state *remote_state_new(void)
2823
2824 void remote_state_clear(struct remote_state *remote_state)
2825 {
2826 + struct hashmap_iter iter;
2827 + struct branch *b;
2828 int i;
2829
2830 for (i = 0; i < remote_state->remotes_nr; i++)
2831 remote_clear(remote_state->remotes[i]);
2832 FREE_AND_NULL(remote_state->remotes);
2833 + FREE_AND_NULL(remote_state->pushremote_name);
2834 remote_state->remotes_alloc = 0;
2835 remote_state->remotes_nr = 0;
2836
2837 + rewrites_release(&remote_state->rewrites);
2838 + rewrites_release(&remote_state->rewrites_push);
2839 +
2840 hashmap_clear_and_free(&remote_state->remotes_hash, struct remote, ent);
2809 - hashmap_clear_and_free(&remote_state->branches_hash, struct remote, ent);
2841 + hashmap_for_each_entry(&remote_state->branches_hash, &iter, b, ent) {
2842 + branch_release(b);
2843 + free(b);
2844 + }
2845 + hashmap_clear(&remote_state->branches_hash);
2846 }
2847
2848 /*