diff mbox series

[04/22] builtin/push: fix leaking refspec query result

Message ID 92fc97b3db86bb0bdf610a2f76c03a96a99bfe8d.1724656120.git.ps@pks.im (mailing list archive)
State Superseded
Headers show
Series Memory leak fixes (pt.6) | expand

Commit Message

Patrick Steinhardt Aug. 26, 2024, 7:21 a.m. UTC
When appending a refspec via `refspec_append_mapped()` we leak the
result of `query_refspecs()`. The overall logic around refspec queries
is quite weird, as callers are expected to either set the `src` or `dst`
pointers, and then the (allocated) result will be in the respective
other struct member.

As we have the `src` member set, plugging the memory leak is thus as
easy as just freeing the `dst` member. While at it, use designated
initializers to initialize the structure.

This leak was exposed by t5516, but fixing it is not sufficient to make
the whole test suite leak free.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 builtin/push.c | 8 +++++---
 1 file changed, 5 insertions(+), 3 deletions(-)

Comments

Junio C Hamano Aug. 30, 2024, 9:59 p.m. UTC | #1
Patrick Steinhardt <ps@pks.im> writes:

> When appending a refspec via `refspec_append_mapped()` we leak the
> result of `query_refspecs()`. The overall logic around refspec queries
> is quite weird, as callers are expected to either set the `src` or `dst`
> pointers, and then the (allocated) result will be in the respective
> other struct member.

Hmph, is it necessary to say "quite weird" for the purpose of this
change?  The query interface is designed to be usable to query both
ways and within that constraints, I find it designed very nicely
(but I do not think that is necessary to be said for the purpose of
this change, either)..

> As we have the `src` member set, plugging the memory leak is thus as
> easy as just freeing the `dst` member. While at it, use designated
> initializers to initialize the structure.

In order to understand this paragraph, of course, it helps for a
reader to understand that the query_refspecs() gives an answer by
populating the side other than the query side, and the answers are
what we want to release.

> This leak was exposed by t5516, but fixing it is not sufficient to make
> the whole test suite leak free.
>
> Signed-off-by: Patrick Steinhardt <ps@pks.im>
> ---
>  builtin/push.c | 8 +++++---
>  1 file changed, 5 insertions(+), 3 deletions(-)
>
> diff --git a/builtin/push.c b/builtin/push.c
> index 7a67398124f..0b123eb9c1e 100644
> --- a/builtin/push.c
> +++ b/builtin/push.c
> @@ -72,13 +72,15 @@ static void refspec_append_mapped(struct refspec *refspec, const char *ref,
>  	const char *branch_name;
>  
>  	if (remote->push.nr) {
> -		struct refspec_item query;
> -		memset(&query, 0, sizeof(struct refspec_item));
> -		query.src = matched->name;
> +		struct refspec_item query = {
> +			.src = matched->name,
> +		};

This is "while at it" change that does not contribute to the leak or
the leakfix; the resulting code is easier to read.

>  		if (!query_refspecs(&remote->push, &query) && query.dst) {
>  			refspec_appendf(refspec, "%s%s:%s",
>  					query.force ? "+" : "",
>  					query.src, query.dst);
> +			free(query.dst);

And this is the real fix, which looks good.

Thanks.

>  			return;
>  		}
>  	}
Patrick Steinhardt Sept. 2, 2024, 9:27 a.m. UTC | #2
On Fri, Aug 30, 2024 at 02:59:01PM -0700, Junio C Hamano wrote:
> Patrick Steinhardt <ps@pks.im> writes:
> 
> > When appending a refspec via `refspec_append_mapped()` we leak the
> > result of `query_refspecs()`. The overall logic around refspec queries
> > is quite weird, as callers are expected to either set the `src` or `dst`
> > pointers, and then the (allocated) result will be in the respective
> > other struct member.
> 
> Hmph, is it necessary to say "quite weird" for the purpose of this
> change?  The query interface is designed to be usable to query both
> ways and within that constraints, I find it designed very nicely
> (but I do not think that is necessary to be said for the purpose of
> this change, either)..

I don't quite agree that it's nicely designed -- I find it rather hard
to use and reason about, and the fact that so many callsites get this
interface wrong seems to indicate that there is at least some sort of
truth to this assessment.

But I don't mind removing this subjective opinion from the commit
message. I'll do that in case I end up rerolling this patch series.

Thanks!

Patrick
diff mbox series

Patch

diff --git a/builtin/push.c b/builtin/push.c
index 7a67398124f..0b123eb9c1e 100644
--- a/builtin/push.c
+++ b/builtin/push.c
@@ -72,13 +72,15 @@  static void refspec_append_mapped(struct refspec *refspec, const char *ref,
 	const char *branch_name;
 
 	if (remote->push.nr) {
-		struct refspec_item query;
-		memset(&query, 0, sizeof(struct refspec_item));
-		query.src = matched->name;
+		struct refspec_item query = {
+			.src = matched->name,
+		};
+
 		if (!query_refspecs(&remote->push, &query) && query.dst) {
 			refspec_appendf(refspec, "%s%s:%s",
 					query.force ? "+" : "",
 					query.src, query.dst);
+			free(query.dst);
 			return;
 		}
 	}