From 26b974b3a9608adee6f964e9effbac86d0220bc3 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Thu, 5 Mar 2026 18:08:54 -0500 Subject: check_connected(): delay opening new_pack In check_connected(), if the transport tells us we got a single packfile that has already been verified as self-contained and connected, then we can skip checking connectivity for any tips that are mentioned in that pack. This goes back to c6807a40dc (clone: open a shortcut for connectivity check, 2013-05-26). We don't need to open that pack until we are about to start sending oids to our child rev-list process, since that's when we check whether they are in the self-contained pack. Let's push the opening of that pack further down in the function. That saves us from having to clean it up when we leave the function early (and by the time have opened the rev-list process, we never leave the function early, since we have to clean up the child process). Signed-off-by: Jeff King Reviewed-by: Jacob Keller Signed-off-by: Junio C Hamano --- connected.c | 33 +++++++++++++++------------------ 1 file changed, 15 insertions(+), 18 deletions(-) (limited to 'connected.c') diff --git a/connected.c b/connected.c index 79403108dd..530357de54 100644 --- a/connected.c +++ b/connected.c @@ -45,20 +45,6 @@ int check_connected(oid_iterate_fn fn, void *cb_data, return err; } - if (transport && transport->smart_options && - transport->smart_options->self_contained_and_connected && - transport->pack_lockfiles.nr == 1 && - strip_suffix(transport->pack_lockfiles.items[0].string, - ".keep", &base_len)) { - struct strbuf idx_file = STRBUF_INIT; - strbuf_add(&idx_file, transport->pack_lockfiles.items[0].string, - base_len); - strbuf_addstr(&idx_file, ".idx"); - new_pack = add_packed_git(the_repository, idx_file.buf, - idx_file.len, 1); - strbuf_release(&idx_file); - } - if (repo_has_promisor_remote(the_repository)) { /* * For partial clones, we don't want to have to do a regular @@ -90,7 +76,6 @@ int check_connected(oid_iterate_fn fn, void *cb_data, promisor_pack_found: ; } while ((oid = fn(cb_data)) != NULL); - free(new_pack); return 0; } @@ -127,15 +112,27 @@ no_promisor_pack_found: else rev_list.no_stderr = opt->quiet; - if (start_command(&rev_list)) { - free(new_pack); + if (start_command(&rev_list)) return error(_("Could not run 'git rev-list'")); - } sigchain_push(SIGPIPE, SIG_IGN); rev_list_in = xfdopen(rev_list.in, "w"); + if (transport && transport->smart_options && + transport->smart_options->self_contained_and_connected && + transport->pack_lockfiles.nr == 1 && + strip_suffix(transport->pack_lockfiles.items[0].string, + ".keep", &base_len)) { + struct strbuf idx_file = STRBUF_INIT; + strbuf_add(&idx_file, transport->pack_lockfiles.items[0].string, + base_len); + strbuf_addstr(&idx_file, ".idx"); + new_pack = add_packed_git(the_repository, idx_file.buf, + idx_file.len, 1); + strbuf_release(&idx_file); + } + do { /* * If index-pack already checked that: -- cgit v1.3-5-g9baa From 0921da1724dab83ea1d266b996544674d0e318e4 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Thu, 5 Mar 2026 18:09:56 -0500 Subject: check_connected(): fix leak of pack-index mmap Since c6807a40dc (clone: open a shortcut for connectivity check, 2013-05-26), we may open a one-off packed_git struct to check what's in the pack we just received. At the end of the function we throw away the struct (rather than linking it into the repository struct as usual). We used to leak the struct until dd4143e7bf (connected.c: free the "struct packed_git", 2022-11-08), which calls free(). But that's not sufficient; inside the struct we'll have mmap'd the pack idx data from disk, which needs an munmap() call. Building with SANITIZE=leak doesn't detect this, because we are leaking our own mmap(), and it only finds heap allocations from malloc(). But if we use our compat mmap implementation like this: make NO_MMAP=MapsBecomeMallocs SANITIZE=leak then LSan will notice the leak, because now it's a regular heap buffer allocated by malloc(). We can fix it by calling close_pack(), which will free any associated memory. Note that we need to check for NULL ourselves; unlike free(), it is not safe to pass a NULL pointer to close_pack(). Signed-off-by: Jeff King Reviewed-by: Jacob Keller Signed-off-by: Junio C Hamano --- connected.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'connected.c') diff --git a/connected.c b/connected.c index 530357de54..6718503649 100644 --- a/connected.c +++ b/connected.c @@ -159,6 +159,9 @@ no_promisor_pack_found: err = error_errno(_("failed to close rev-list's stdin")); sigchain_pop(SIGPIPE); - free(new_pack); + if (new_pack) { + close_pack(new_pack); + free(new_pack); + } return finish_command(&rev_list) || err; } -- cgit v1.3-5-g9baa