From: Karthik Nayak <karthik.188@gmail.com>
To: Jeff King <peff@peff.net>
Cc: git@vger.kernel.org, toon@iotcl.com, ps@pks.im, gitster@pobox.com
Subject: Re: [PATCH v2 4/4] receive-pack: use batched reference updates
Date: Fri, 16 May 2025 12:49:35 -0700 [thread overview]
Message-ID: <CAOLa=ZSwzWm=43daWfu7aAb7q9gnseT=bifh0DUS3Cr02taCRQ@mail.gmail.com> (raw)
In-Reply-To: <20250515190909.GA3320028@coredump.intra.peff.net>
[-- Attachment #1: Type: text/plain, Size: 5563 bytes --]
Jeff King <peff@peff.net> writes:
> On Thu, May 15, 2025 at 02:55:36PM -0400, Jeff King wrote:
>
>> On Thu, May 15, 2025 at 04:07:28PM +0200, Karthik Nayak wrote:
>>
>> > +failure:
>> > + for (cmd = commands; cmd; cmd = cmd->next) {
>> > + if (reported_error)
>> > + cmd->error_string = reported_error;
>> > + else if (strmap_contains(&failed_refs, cmd->ref_name))
>> > + cmd->error_string = xstrdup(strmap_get(&failed_refs, cmd->ref_name));
>> > }
>
> BTW, one other funny thing about this code: we duplicate the strings
> that we assign to cmd->error_string. But no other call path does so. So
> now we have allocated memory, but nobody can ever free() it because
> often it is not allocated!
>
> I'm surprised LSan does not report a leak here, so I might be missing
> something.
>
Yeah, indeed that is a leak and surprising that this wasn't caught by
LSan.
> It looks like there is some magic in the struct here to handle this
> like:
>
> cmd->error_string = cmd->error_string_owned = xstrdup(...);
>
> which would solve it. But I wonder: do these need to be allocated at
> all? We are pulling out strings owned by the strmap, which will free
> them. So as-is, yes, we need to make our own copies.
>
> But does the strmap need to own them in the first place? It is taking
> the values from ref_transaction_error_msg(). That returns an allocated
> string, but it doesn't need to. It could just return the string literals
> directly, which are valid for the life of the program. That would save
> other callers from having to call free(), though it does mean we have to
> cast away the constness when putting them into the strmap (since it
> accepts a non-const void pointer). Something like:
>
Thanks Jeff, this does make a lot of sense, I think with Junio's
suggestion in the first patch, making `ref_transaction_error_msg()`
return a 'const char *' solves this issue too, we no longer will hold
allocated strings here and as such no longer have to worry about
allocation/freeing of memory. Much cleaner.
In the end it looks similar to you patch below!
> diff --git a/builtin/fetch.c b/builtin/fetch.c
> index 4a3c46eca7..cf0bcf1ad0 100644
> --- a/builtin/fetch.c
> +++ b/builtin/fetch.c
> @@ -1665,10 +1665,9 @@ static void ref_transaction_rejection_handler(const char *refname,
> "branches"), data->remote_name);
> data->conflict_msg_shown = 1;
> } else {
> - char *reason = ref_transaction_error_msg(err);
> + const char *reason = ref_transaction_error_msg(err);
>
> error(_("fetching ref %s failed: %s"), refname, reason);
> - free(reason);
> }
>
> *data->retcode = 1;
> diff --git a/builtin/receive-pack.c b/builtin/receive-pack.c
> index bd0fb729ff..4cef2ddd3d 100644
> --- a/builtin/receive-pack.c
> +++ b/builtin/receive-pack.c
> @@ -1855,7 +1855,7 @@ static void ref_transaction_rejection_handler(const char *refname,
> {
> struct strmap *failed_refs = cb_data;
>
> - strmap_put(failed_refs, refname, ref_transaction_error_msg(err));
> + strmap_put(failed_refs, refname, (char *)ref_transaction_error_msg(err));
> }
>
> static void execute_commands_non_atomic(struct command *commands,
> @@ -1897,15 +1897,16 @@ static void execute_commands_non_atomic(struct command *commands,
>
> failure:
> for (cmd = commands; cmd; cmd = cmd->next) {
> + const char *reason;
> if (reported_error)
> cmd->error_string = reported_error;
> - else if (strmap_contains(&failed_refs, cmd->ref_name))
> - cmd->error_string = xstrdup(strmap_get(&failed_refs, cmd->ref_name));
> + else if ((reason = strmap_get(&failed_refs, cmd->ref_name)))
> + cmd->error_string = reason;
> }
>
> cleanup:
> ref_transaction_free(transaction);
> - strmap_clear(&failed_refs, 1);
> + strmap_clear(&failed_refs, 0);
> strbuf_release(&err);
> }
>
> diff --git a/builtin/update-ref.c b/builtin/update-ref.c
> index 09b99143bf..1e6131e04a 100644
> --- a/builtin/update-ref.c
> +++ b/builtin/update-ref.c
> @@ -575,15 +575,14 @@ static void print_rejected_refs(const char *refname,
> void *cb_data UNUSED)
> {
> struct strbuf sb = STRBUF_INIT;
> - char *reason = ref_transaction_error_msg(err);
> + const char *reason = ref_transaction_error_msg(err);
>
> strbuf_addf(&sb, "rejected %s %s %s %s\n", refname,
> new_oid ? oid_to_hex(new_oid) : new_target,
> old_oid ? oid_to_hex(old_oid) : old_target,
> reason);
>
> fwrite(sb.buf, sb.len, 1, stdout);
> - free(reason);
> strbuf_release(&sb);
> }
>
> diff --git a/refs.c b/refs.c
> index 351ed52deb..953f83bb52 100644
> --- a/refs.c
> +++ b/refs.c
> @@ -3315,7 +3315,7 @@ int ref_update_expects_existing_old_ref(struct ref_update *update)
> (!is_null_oid(&update->old_oid) || update->old_target);
> }
>
> -char *ref_transaction_error_msg(enum ref_transaction_error err)
> +const char *ref_transaction_error_msg(enum ref_transaction_error err)
> {
> const char *reason = "";
>
> @@ -3342,5 +3342,5 @@ char *ref_transaction_error_msg(enum ref_transaction_error err)
> reason = "unkown failure";
> }
>
> - return xstrdup(reason);
> + return reason;
> }
> diff --git a/refs.h b/refs.h
> index a0b2e3c43d..2d58af3d88 100644
> --- a/refs.h
> +++ b/refs.h
> @@ -910,7 +910,7 @@ void ref_transaction_for_each_rejected_update(struct ref_transaction *transactio
> /*
> * Translate errors to human readable error messages.
> */
> -char *ref_transaction_error_msg(enum ref_transaction_error err);
> +const char *ref_transaction_error_msg(enum ref_transaction_error err);
>
> /*
> * Free `*transaction` and all associated data.
>
> -Peff
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 690 bytes --]
next prev parent reply other threads:[~2025-05-16 19:49 UTC|newest]
Thread overview: 41+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-05-14 9:03 [PATCH 0/3] fetch/receive: use batched reference updates Karthik Nayak
2025-05-14 9:03 ` [PATCH 1/3] fetch: " Karthik Nayak
2025-05-14 12:31 ` Patrick Steinhardt
2025-05-15 11:13 ` Karthik Nayak
2025-05-15 11:30 ` Patrick Steinhardt
2025-05-15 11:36 ` Karthik Nayak
2025-05-14 17:36 ` Junio C Hamano
2025-05-14 9:03 ` [PATCH 2/3] send-pack: fix memory leak around duplicate refs Karthik Nayak
2025-05-14 17:46 ` Junio C Hamano
2025-05-15 11:23 ` Karthik Nayak
2025-05-14 9:03 ` [PATCH 3/3] receive-pack: use batched reference updates Karthik Nayak
2025-05-14 12:31 ` Patrick Steinhardt
2025-05-14 19:00 ` Junio C Hamano
2025-05-15 11:30 ` Karthik Nayak
2025-05-15 14:07 ` [PATCH v2 0/4] fetch/receive: " Karthik Nayak
2025-05-15 14:07 ` [PATCH v2 1/4] refs: add function to translate errors to strings Karthik Nayak
2025-05-15 19:11 ` Jeff King
2025-05-16 9:11 ` Karthik Nayak
2025-05-15 20:26 ` Junio C Hamano
2025-05-16 9:12 ` Karthik Nayak
2025-05-15 14:07 ` [PATCH v2 2/4] fetch: use batched reference updates Karthik Nayak
2025-05-16 5:40 ` Patrick Steinhardt
2025-05-16 9:53 ` Karthik Nayak
2025-05-16 10:00 ` Patrick Steinhardt
2025-05-18 11:30 ` Karthik Nayak
2025-05-15 14:07 ` [PATCH v2 3/4] send-pack: fix memory leak around duplicate refs Karthik Nayak
2025-05-15 14:07 ` [PATCH v2 4/4] receive-pack: use batched reference updates Karthik Nayak
2025-05-15 18:55 ` Jeff King
2025-05-15 19:09 ` Jeff King
2025-05-16 19:49 ` Karthik Nayak [this message]
2025-05-19 9:58 ` [PATCH v3 0/4] fetch/receive: " Karthik Nayak
2025-05-19 9:58 ` [PATCH v3 1/4] refs: add function to translate errors to strings Karthik Nayak
2025-05-19 9:58 ` [PATCH v3 2/4] fetch: use batched reference updates Karthik Nayak
2025-05-19 9:58 ` [PATCH v3 3/4] send-pack: fix memory leak around duplicate refs Karthik Nayak
2025-05-19 9:58 ` [PATCH v3 4/4] receive-pack: use batched reference updates Karthik Nayak
2025-05-19 18:14 ` [PATCH v3 0/4] fetch/receive: " Junio C Hamano
2025-05-20 9:05 ` Karthik Nayak
2025-05-21 13:14 ` Junio C Hamano
2025-05-22 6:00 ` Jeff King
2025-05-22 8:50 ` Karthik Nayak
2025-05-22 15:31 ` Jeff King
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to='CAOLa=ZSwzWm=43daWfu7aAb7q9gnseT=bifh0DUS3Cr02taCRQ@mail.gmail.com' \
--to=karthik.188@gmail.com \
--cc=git@vger.kernel.org \
--cc=gitster@pobox.com \
--cc=peff@peff.net \
--cc=ps@pks.im \
--cc=toon@iotcl.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).