diff mbox series

[v3,12/22] builtin/fast-export: fix leaking diff options

Message ID 9591fb7b5e1dac2f989bd10ef2c13a191571a060.1723540931.git.ps@pks.im (mailing list archive)
State Superseded
Headers show
Series Memory leak fixes (pt.4) | expand

Commit Message

Patrick Steinhardt Aug. 13, 2024, 9:31 a.m. UTC
Before calling `handle_commit()` in a loop, we set `diffopt.no_free`
such that its contents aren't getting freed inside of `handle_commit()`.
We never unset that flag though, which means that it'll ultimately leak
when calling `release_revisions()`.

Fix this by unsetting the flag after the loop.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
---
 builtin/fast-export.c | 2 ++
 1 file changed, 2 insertions(+)

Comments

Junio C Hamano Aug. 13, 2024, 4:34 p.m. UTC | #1
Patrick Steinhardt <ps@pks.im> writes:

> Before calling `handle_commit()` in a loop, we set `diffopt.no_free`
> such that its contents aren't getting freed inside of `handle_commit()`.
> We never unset that flag though, which means that it'll ultimately leak
> when calling `release_revisions()`.
>
> Fix this by unsetting the flag after the loop.

If I grep for 

    $ git grep -nH -E -e '(\.|->)no_free' \*.c

I notice that in a lot of places there is a pattern of doing

    set .no_free to 1
    cause a bunch of diff using the same set of options
    set .no_free to 0
    call diff_free().

I am curious why we do not need any diff_free() here?

> Signed-off-by: Patrick Steinhardt <ps@pks.im>
> ---
>  builtin/fast-export.c | 2 ++
>  1 file changed, 2 insertions(+)
>
> diff --git a/builtin/fast-export.c b/builtin/fast-export.c
> index 4b6e8c6832..fe92d2436c 100644
> --- a/builtin/fast-export.c
> +++ b/builtin/fast-export.c
> @@ -1278,9 +1278,11 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
>  	revs.diffopt.format_callback = show_filemodify;
>  	revs.diffopt.format_callback_data = &paths_of_changed_objects;
>  	revs.diffopt.flags.recursive = 1;
> +
>  	revs.diffopt.no_free = 1;
>  	while ((commit = get_revision(&revs)))
>  		handle_commit(commit, &revs, &paths_of_changed_objects);
> +	revs.diffopt.no_free = 0;
>  
>  	handle_tags_and_duplicates(&extra_refs);
>  	handle_tags_and_duplicates(&tag_refs);
Patrick Steinhardt Aug. 14, 2024, 4:49 a.m. UTC | #2
On Tue, Aug 13, 2024 at 09:34:40AM -0700, Junio C Hamano wrote:
> Patrick Steinhardt <ps@pks.im> writes:
> 
> > Before calling `handle_commit()` in a loop, we set `diffopt.no_free`
> > such that its contents aren't getting freed inside of `handle_commit()`.
> > We never unset that flag though, which means that it'll ultimately leak
> > when calling `release_revisions()`.
> >
> > Fix this by unsetting the flag after the loop.
> 
> If I grep for 
> 
>     $ git grep -nH -E -e '(\.|->)no_free' \*.c
> 
> I notice that in a lot of places there is a pattern of doing
> 
>     set .no_free to 1
>     cause a bunch of diff using the same set of options
>     set .no_free to 0
>     call diff_free().
> 
> I am curious why we do not need any diff_free() here?

Because it's already being called via `release_revisions()`.

Patrick
diff mbox series

Patch

diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index 4b6e8c6832..fe92d2436c 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -1278,9 +1278,11 @@  int cmd_fast_export(int argc, const char **argv, const char *prefix)
 	revs.diffopt.format_callback = show_filemodify;
 	revs.diffopt.format_callback_data = &paths_of_changed_objects;
 	revs.diffopt.flags.recursive = 1;
+
 	revs.diffopt.no_free = 1;
 	while ((commit = get_revision(&revs)))
 		handle_commit(commit, &revs, &paths_of_changed_objects);
+	revs.diffopt.no_free = 0;
 
 	handle_tags_and_duplicates(&extra_refs);
 	handle_tags_and_duplicates(&tag_refs);