ref-filter: fix leak with unterminated %(if) atoms
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>
This commit is contained in:
parent
db629c61f0
commit
04d9744f83
@ -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, ¤t->output);
|
||||
strbuf_release(¤t->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;
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user