Skip to content

Commit f36d4f8

Browse files
avargitster
authored andcommitted
ls-remote & transport API: release "struct transport_ls_refs_options"
Fix a memory leak in codepaths that use the "struct transport_ls_refs_options" API. Since the introduction of the struct in 3983540 (connect, transport: encapsulate arg in struct, 2021-02-05) the caller has been responsible for freeing it. That commit in turn migrated code originally added in 402c47d (clone: send ref-prefixes when using protocol v2, 2018-07-20) and b4be741 (ls-remote: pass ref prefixes when requesting a remote's refs, 2018-03-15). Only some of those codepaths were releasing the allocated resources of the struct, now all of them will. Mark the "t/t5511-refspec.sh" test as passing when git is compiled with SANITIZE=leak. They'll now be listed as running under the "GIT_TEST_PASSING_SANITIZE_LEAK=true" test mode (the "linux-leaks" CI target). Previously 24/47 tests would fail. Signed-off-by: Ævar Arnfjörð Bjarmason <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 38062e7 commit f36d4f8

File tree

7 files changed

+26
-15
lines changed

7 files changed

+26
-15
lines changed

builtin/clone.c

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1233,7 +1233,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
12331233
}
12341234
else {
12351235
const char *branch;
1236-
char *ref;
1236+
const char *ref;
1237+
char *ref_free = NULL;
12371238

12381239
if (option_branch)
12391240
die(_("Remote branch %s not found in upstream %s"),
@@ -1250,17 +1251,16 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
12501251
skip_prefix(transport_ls_refs_options.unborn_head_target,
12511252
"refs/heads/", &branch)) {
12521253
ref = transport_ls_refs_options.unborn_head_target;
1253-
transport_ls_refs_options.unborn_head_target = NULL;
12541254
create_symref("HEAD", ref, reflog_msg.buf);
12551255
} else {
12561256
branch = git_default_branch_name(0);
1257-
ref = xstrfmt("refs/heads/%s", branch);
1257+
ref_free = xstrfmt("refs/heads/%s", branch);
1258+
ref = ref_free;
12581259
}
12591260

12601261
if (!option_bare)
12611262
install_branch_config(0, branch, remote_name, ref);
1262-
1263-
free(ref);
1263+
free(ref_free);
12641264
}
12651265

12661266
write_refspec_config(src_ref_prefix, our_head_points_at,
@@ -1312,7 +1312,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
13121312
UNLEAK(repo);
13131313
junk_mode = JUNK_LEAVE_ALL;
13141314

1315-
strvec_clear(&transport_ls_refs_options.ref_prefixes);
1316-
free(transport_ls_refs_options.unborn_head_target);
1315+
transport_ls_refs_options_release(&transport_ls_refs_options);
13171316
return err;
13181317
}

builtin/fetch.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1593,7 +1593,7 @@ static int do_fetch(struct transport *transport,
15931593
} else
15941594
remote_refs = NULL;
15951595

1596-
strvec_clear(&transport_ls_refs_options.ref_prefixes);
1596+
transport_ls_refs_options_release(&transport_ls_refs_options);
15971597

15981598
ref_map = get_ref_map(transport->remote, remote_refs, rs,
15991599
tags, &autotags);

builtin/ls-remote.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ int cmd_ls_remote(int argc, const char **argv, const char *prefix)
155155

156156
ref_array_clear(&ref_array);
157157
if (transport_disconnect(transport))
158-
return 1;
158+
status = 1;
159+
transport_ls_refs_options_release(&transport_options);
159160
return status;
160161
}

connect.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -379,7 +379,7 @@ struct ref **get_remote_heads(struct packet_reader *reader,
379379

380380
/* Returns 1 when a valid ref has been added to `list`, 0 otherwise */
381381
static int process_ref_v2(struct packet_reader *reader, struct ref ***list,
382-
char **unborn_head_target)
382+
const char **unborn_head_target)
383383
{
384384
int ret = 1;
385385
int i = 0;
@@ -483,7 +483,7 @@ struct ref **get_remote_refs(int fd_out, struct packet_reader *reader,
483483
const char *hash_name;
484484
struct strvec *ref_prefixes = transport_options ?
485485
&transport_options->ref_prefixes : NULL;
486-
char **unborn_head_target = transport_options ?
486+
const char **unborn_head_target = transport_options ?
487487
&transport_options->unborn_head_target : NULL;
488488
*list = NULL;
489489

t/t5511-refspec.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
test_description='refspec parsing'
44

5+
TEST_PASSES_SANITIZE_LEAK=true
56
. ./test-lib.sh
67

78
test_refspec () {

transport.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1292,7 +1292,7 @@ int transport_push(struct repository *r,
12921292
&transport_options);
12931293
trace2_region_leave("transport_push", "get_refs_list", r);
12941294

1295-
strvec_clear(&transport_options.ref_prefixes);
1295+
transport_ls_refs_options_release(&transport_options);
12961296

12971297
if (flags & TRANSPORT_PUSH_ALL)
12981298
match_flags |= MATCH_REFS_ALL;
@@ -1420,6 +1420,12 @@ const struct ref *transport_get_remote_refs(struct transport *transport,
14201420
return transport->remote_refs;
14211421
}
14221422

1423+
void transport_ls_refs_options_release(struct transport_ls_refs_options *opts)
1424+
{
1425+
strvec_clear(&opts->ref_prefixes);
1426+
free((char *)opts->unborn_head_target);
1427+
}
1428+
14231429
int transport_fetch_refs(struct transport *transport, struct ref *refs)
14241430
{
14251431
int rc;

transport.h

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -257,15 +257,19 @@ struct transport_ls_refs_options {
257257
/*
258258
* If unborn_head_target is not NULL, and the remote reports HEAD as
259259
* pointing to an unborn branch, transport_get_remote_refs() stores the
260-
* unborn branch in unborn_head_target. It should be freed by the
261-
* caller.
260+
* unborn branch in unborn_head_target.
262261
*/
263-
char *unborn_head_target;
262+
const char *unborn_head_target;
264263
};
265264
#define TRANSPORT_LS_REFS_OPTIONS_INIT { \
266265
.ref_prefixes = STRVEC_INIT, \
267266
}
268267

268+
/**
269+
* Release the "struct transport_ls_refs_options".
270+
*/
271+
void transport_ls_refs_options_release(struct transport_ls_refs_options *opts);
272+
269273
/*
270274
* Retrieve refs from a remote.
271275
*/

0 commit comments

Comments
 (0)