diff mbox series

[09/28] transport-helper: fix strbuf leak in push_refs_with_push()

Message ID 20240924215634.GI1143820@coredump.intra.peff.net (mailing list archive)
State Accepted
Commit e00e1cff0d845a66c58180d75c33be109a958ba3
Headers show
Series leak fixes for http fetch/push | expand

Commit Message

Jeff King Sept. 24, 2024, 9:56 p.m. UTC
We loop over the refs to push, building up a strbuf with the set of
"push" directives to send to the remote helper. But if the atomic-push
flag is set and we hit a rejected ref, we'll bail from the function
early. We clean up most things, but forgot to release the strbuf.

Fixing this lets us mark t5541 as leak-free.

Signed-off-by: Jeff King <peff@peff.net>
---
Arguably this whole function could benefit from a cleanup goto, but it's
a little non-trivial. So I stuck with simple-and-stupid.

 t/t5541-http-push-smart.sh | 1 +
 transport-helper.c         | 1 +
 2 files changed, 2 insertions(+)

Comments

Patrick Steinhardt Sept. 26, 2024, 1:50 p.m. UTC | #1
On Tue, Sep 24, 2024 at 05:56:34PM -0400, Jeff King wrote:
> diff --git a/transport-helper.c b/transport-helper.c
> index c688967b8c..9c8abd8eca 100644
> --- a/transport-helper.c
> +++ b/transport-helper.c
> @@ -1023,6 +1023,7 @@ static int push_refs_with_push(struct transport *transport,
>  			if (atomic) {
>  				reject_atomic_push(remote_refs, mirror);
>  				string_list_clear(&cas_options, 0);
> +				strbuf_release(&buf);
>  				return 0;
>  			} else
>  				continue;

What's not visible here is that a few lines further down we have another
early return where we don't clear `buf`. But that exit is conditioned on
`buf.len == 0`, and given that we never `strbuf_reset()` the buffer we
know that `buf.len == 0` only when it hasn't ever be allocated.

So this LGTM.

Patrick
Jeff King Sept. 27, 2024, 3:49 a.m. UTC | #2
On Thu, Sep 26, 2024 at 03:50:14PM +0200, Patrick Steinhardt wrote:

> On Tue, Sep 24, 2024 at 05:56:34PM -0400, Jeff King wrote:
> > diff --git a/transport-helper.c b/transport-helper.c
> > index c688967b8c..9c8abd8eca 100644
> > --- a/transport-helper.c
> > +++ b/transport-helper.c
> > @@ -1023,6 +1023,7 @@ static int push_refs_with_push(struct transport *transport,
> >  			if (atomic) {
> >  				reject_atomic_push(remote_refs, mirror);
> >  				string_list_clear(&cas_options, 0);
> > +				strbuf_release(&buf);
> >  				return 0;
> >  			} else
> >  				continue;
> 
> What's not visible here is that a few lines further down we have another
> early return where we don't clear `buf`. But that exit is conditioned on
> `buf.len == 0`, and given that we never `strbuf_reset()` the buffer we
> know that `buf.len == 0` only when it hasn't ever be allocated.

Yeah, I noticed that, too, and came to the same conclusion. As you note,
it's _possible_ to have an allocated but zero-length strbuf, but I don't
think it happens here. So it's OK in practice.

If we were going to refactor, I think it would make sense to do it with
a cleanup label to cover both of these early returns, plus the cleanup
at the end. I was mostly just going for minimal changes where possible.

-Peff
diff mbox series

Patch

diff --git a/t/t5541-http-push-smart.sh b/t/t5541-http-push-smart.sh
index 71428f3d5c..3ad514bbd4 100755
--- a/t/t5541-http-push-smart.sh
+++ b/t/t5541-http-push-smart.sh
@@ -7,6 +7,7 @@  test_description='test smart pushing over http via http-backend'
 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 
 ROOT_PATH="$PWD"
diff --git a/transport-helper.c b/transport-helper.c
index c688967b8c..9c8abd8eca 100644
--- a/transport-helper.c
+++ b/transport-helper.c
@@ -1023,6 +1023,7 @@  static int push_refs_with_push(struct transport *transport,
 			if (atomic) {
 				reject_atomic_push(remote_refs, mirror);
 				string_list_clear(&cas_options, 0);
+				strbuf_release(&buf);
 				return 0;
 			} else
 				continue;