transport-helper: fix leaking helper name

When initializing the transport helper in `transport_get()`, we allocate the name of the helper. We neither end up transferring ownership of the name, nor do we free it. The associated memory thus leaks. Fix this memory leak by freeing the string at the calling side in `transport_get()`. `transport_helper_init()` now creates its own copy of the string and thus can free it as required. An alterantive way to fix this would be to transfer ownership of the string passed into `transport_helper_init()`, which would avoid the call to xstrdup(1). But it does make for a more surprising calling convention as we do not typically transfer ownership of strings like this. Mark now-passing tests as leak free. Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Patrick Steinhardt committed May 27, 2024 at 13:45 UTC 97613b9cb91eb97b8a4df547396465f3184ccdef
6 files changed +9 -2
t/t0611-reftable-httpd.sh
+1
@@ -2,6 +2,7 @@
2
3 test_description='reftable HTTPD tests'
4
5 +TEST_PASSES_SANITIZE_LEAK=true
6 . ./test-lib.sh
7 . "$TEST_DIRECTORY"/lib-httpd.sh
8
t/t5563-simple-http-auth.sh
+1
@@ -2,6 +2,7 @@
2
3 test_description='test http auth header and credential helper interop'
4
5 +TEST_PASSES_SANITIZE_LEAK=true
6 . ./test-lib.sh
7 . "$TEST_DIRECTORY"/lib-httpd.sh
8
t/t5564-http-proxy.sh
+1
@@ -2,6 +2,7 @@
2
3 test_description="test fetching through http proxy"
4
5 +TEST_PASSES_SANITIZE_LEAK=true
6 . ./test-lib.sh
7 . "$TEST_DIRECTORY"/lib-httpd.sh
8
t/t5581-http-curl-verbose.sh
+1
@@ -4,6 +4,7 @@ test_description='test GIT_CURL_VERBOSE'
4 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
5 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
6
7 +TEST_PASSES_SANITIZE_LEAK=true
8 . ./test-lib.sh
9 . "$TEST_DIRECTORY"/lib-httpd.sh
10 start_httpd
transport-helper.c
+4 -2
@@ -22,7 +22,7 @@
22 static int debug;
23
24 struct helper_data {
25 - const char *name;
25 + char *name;
26 struct child_process *helper;
27 FILE *out;
28 unsigned fetch : 1,
@@ -111,6 +111,7 @@ static void do_take_over(struct transport *transport)
111 data = (struct helper_data *)transport->data;
112 transport_take_over(transport, data->helper);
113 fclose(data->out);
114 + free(data->name);
115 free(data);
116 }
117
@@ -253,6 +254,7 @@ static int disconnect_helper(struct transport *transport)
254 close(data->helper->out);
255 fclose(data->out);
256 res = finish_command(data->helper);
257 + FREE_AND_NULL(data->name);
258 FREE_AND_NULL(data->helper);
259 }
260 return res;
@@ -1297,7 +1299,7 @@ static struct transport_vtable vtable = {
1299 int transport_helper_init(struct transport *transport, const char *name)
1300 {
1301 struct helper_data *data = xcalloc(1, sizeof(*data));
1300 - data->name = name;
1302 + data->name = xstrdup(name);
1303
1304 transport_check_allowed(name);
1305
transport.c
+1
@@ -1176,6 +1176,7 @@ struct transport *transport_get(struct remote *remote, const char *url)
1176 int len = external_specification_len(url);
1177 char *handler = xmemdupz(url, len);
1178 transport_helper_init(ret, handler);
1179 + free(handler);
1180 }
1181
1182 if (ret->smart_options) {