]> git.ipfire.org Git - thirdparty/git.git/commitdiff
ref-filter: fix leak with unterminated %(if) atoms
authorPatrick Steinhardt <ps@pks.im>
Tue, 10 Sep 2024 06:57:15 +0000 (08:57 +0200)
committerJunio C Hamano <gitster@pobox.com>
Tue, 10 Sep 2024 16:26:13 +0000 (09:26 -0700)
When parsing `%(if)` atoms we expect a few other atoms to exist to
complete it, like `%(then)` and `%(end)`. Whether or not we have seen
these other atoms is tracked in an allocated `if_then_else` structure,
which gets free'd by the `if_then_else_handler()` once we have parsed
the complete conditional expression.

This results in a memory leak when the `%(if)` atom is not terminated
correctly and thus incomplete. We never end up executing its handler and
thus don't end up freeing the structure.

Plug this memory leak by introducing a new `at_end_data_free` callback
function. If set, we'll execute it in `pop_stack_element()` and pass it
the `at_end_data` variable with the intent to free its state. Wire it up
for the `%(if)` atom accordingly.

Signed-off-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
ref-filter.c
t/t6302-for-each-ref-filter.sh

index ce1bcfad85783d8b24384761011d5077aa42a46b..b06e18a569ae068f346fcccb81ed590c435e75a2 100644 (file)
@@ -1001,6 +1001,7 @@ struct ref_formatting_stack {
        struct ref_formatting_stack *prev;
        struct strbuf output;
        void (*at_end)(struct ref_formatting_stack **stack);
+       void (*at_end_data_free)(void *data);
        void *at_end_data;
 };
 
@@ -1169,6 +1170,8 @@ static void pop_stack_element(struct ref_formatting_stack **stack)
        if (prev)
                strbuf_addbuf(&prev->output, &current->output);
        strbuf_release(&current->output);
+       if (current->at_end_data_free)
+               current->at_end_data_free(current->at_end_data);
        free(current);
        *stack = prev;
 }
@@ -1228,15 +1231,13 @@ static void if_then_else_handler(struct ref_formatting_stack **stack)
        }
 
        *stack = cur;
-       free(if_then_else);
 }
 
 static int if_atom_handler(struct atom_value *atomv, struct ref_formatting_state *state,
                           struct strbuf *err UNUSED)
 {
        struct ref_formatting_stack *new_stack;
-       struct if_then_else *if_then_else = xcalloc(1,
-                                                   sizeof(struct if_then_else));
+       struct if_then_else *if_then_else = xcalloc(1, sizeof(*if_then_else));
 
        if_then_else->str = atomv->atom->u.if_then_else.str;
        if_then_else->cmp_status = atomv->atom->u.if_then_else.cmp_status;
@@ -1245,6 +1246,7 @@ static int if_atom_handler(struct atom_value *atomv, struct ref_formatting_state
        new_stack = state->stack;
        new_stack->at_end = if_then_else_handler;
        new_stack->at_end_data = if_then_else;
+       new_stack->at_end_data_free = free;
        return 0;
 }
 
index 163c378cfd16577a00199dc1696c136662854004..7f44d3c3f22898369d87a3169cca75ab0f827622 100755 (executable)
@@ -2,6 +2,7 @@
 
 test_description='test for-each-refs usage of ref-filter APIs'
 
+TEST_PASSES_SANITIZE_LEAK=true
 . ./test-lib.sh
 . "$TEST_DIRECTORY"/lib-gpg.sh