[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [PATCH] tests/qtest: Plug memory leaks in qtest_get_machines
From: |
Fabiano Rosas |
Subject: |
Re: [PATCH] tests/qtest: Plug memory leaks in qtest_get_machines |
Date: |
Mon, 23 Jan 2023 18:22:06 -0300 |
Thomas Huth <thuth@redhat.com> writes:
> On 23/01/2023 14.32, Fabiano Rosas wrote:
>> Thomas Huth <thuth@redhat.com> writes:
>>
>>> On 20/01/2023 20.44, Fabiano Rosas wrote:
>>>> These leaks can be avoided:
>>>>
>>>> 759 bytes in 61 blocks are still reachable in loss record 56 of 60
>>>> at 0x4034744: malloc (in
>>>> /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
>>>> by 0x4A88518: g_malloc (in /usr/lib64/libglib-2.0.so.0.7000.5)
>>>> by 0x4AA313E: g_strdup (in /usr/lib64/libglib-2.0.so.0.7000.5)
>>>> by 0x12083E: qtest_get_machines (libqtest.c:1323)
>>>> by 0x12098C: qtest_cb_for_every_machine (libqtest.c:1348)
>>>> by 0x11556C: main (test-hmp.c:160)
>>>>
>>>> 992 bytes in 1 blocks are still reachable in loss record 57 of 60
>>>> at 0x4034744: malloc (in
>>>> /usr/lib/valgrind/vgpreload_memcheck-amd64-linux.so)
>>>> by 0x4A88518: g_malloc (in /usr/lib64/libglib-2.0.so.0.7000.5)
>>>> by 0x120725: qtest_get_machines (libqtest.c:1313)
>>>> by 0x12098C: qtest_cb_for_every_machine (libqtest.c:1348)
>>>> by 0x11556C: main (test-hmp.c:160)
>>>>
>>>> Signed-off-by: Fabiano Rosas <farosas@suse.de>
>>>> ---
>>>> tests/qtest/libqtest.c | 14 ++++++++++++++
>>>> 1 file changed, 14 insertions(+)
>>>>
>>>> diff --git a/tests/qtest/libqtest.c b/tests/qtest/libqtest.c
>>>> index 6b2216cb20..65abac5029 100644
>>>> --- a/tests/qtest/libqtest.c
>>>> +++ b/tests/qtest/libqtest.c
>>>> @@ -1285,6 +1285,18 @@ struct MachInfo {
>>>> char *alias;
>>>> };
>>>>
>>>> +static void qtest_free_machine_info(gpointer data)
>>>> +{
>>>> + struct MachInfo *machines = data;
>>>> + int i;
>>>> +
>>>> + for (i = 0; machines[i].name != NULL; i++) {
>>>> + g_free((void *)machines[i].name); > + g_free((void
>>>> *)machines[i].alias);
>>>
>>> I'd suggest setting .name and .alias to NULL after freeing them, to avoid
>>> that danling pointers are left behind.
>>>
>>>> + }
>>>> + g_free(machines);
>>>> +}
>>>> +
>>>> /*
>>>> * Returns an array with pointers to the available machine names.
>>>> * The terminating entry has the name set to NULL.
>>>> @@ -1336,6 +1348,8 @@ static struct MachInfo *qtest_get_machines(void)
>>>> qobject_unref(response);
>>>>
>>>> memset(&machines[idx], 0, sizeof(struct MachInfo)); /* Terminating
>>>> entry */
>>>> + g_test_queue_destroy(qtest_free_machine_info, machines);
>>>
>>> So this frees the machines structure...
>>>
>>>> return machines;
>>>
>>> ... but here it gets returned, too? ... that looks wrong. Did you maybe
>>> rather want to free it at the end of qtest_cb_for_every_machine() and
>>> qtest_has_machine ?
>>
>> g_test_queue_destroy will only call qtest_free_machine_info during the
>> test teardown phase:
>>
>> #0 qtest_free_machine_info (data=0x555555677870) at
>> ../tests/qtest/libqtest.c:1289
>> #1 0x00007ffff7b1d9d1 in ?? () from /usr/lib64/libglib-2.0.so.0
>> #2 0x00007ffff7b1d8b3 in ?? () from /usr/lib64/libglib-2.0.so.0
>> #3 0x00007ffff7b1d8b3 in ?? () from /usr/lib64/libglib-2.0.so.0
>> #4 0x00007ffff7b1de82 in g_test_run_suite () from
>> /usr/lib64/libglib-2.0.so.0
>> #5 0x00007ffff7b1deab in g_test_run () from /usr/lib64/libglib-2.0.so.0
>> #6 0x0000555555561221 in main (argc=<optimized out>, argv=<optimized
>> #out>) at ../tests/qtest/qom-test.c:12
>>
>> As long as 'machines' is static and not being exposed to the tests, I
>> think this should be fine.
>
> Ah, thanks for the explanation, I really got that wrong.
>
> But I think g_test_queue_destroy() might still be the wrong thing to use
> here. I added a fprintf() to your new qtest_free_machine_info() funcion, and
> it seems to be called once at the end of the very first test already.
Yes, because we currently only use qtest_get_machines to construct the
test paths. So it is only needed before the tests.
The g_test_queue_destroy function is actually attaching the callback to
the first test.
> So if anything else calls qtest_get_machines() again after the first
> test finished, it will crash due to the dangling static machine
> pointer.
Ah, my reply about it being fine was while looking at the v2 which sets
'machines' to NULL. So we would go around qtest_get_machines once more and
register qtest_free_machine_info a second time. Every time we have to
fetch the machines, we register the cleanup callback.
> So maybe the static machine pointer should be moved outside of the function
> and then be released from qtest_quit() instead?
Hm.. let me give it a try. I'm not sure if it works because we call
qtest_quit while still using the machines array. Maybe if I move it out
and do the cleanup in qtest_cb_for_every_machine...
> (Also, it's valgrind that you used, isn't it? - I wonder why it's
> complaining here at all since the pointer to the memory should still be
> valid at the end?)
valgrind is complaining about the memory not being explicitly freed at
any point. I guess "leak" was not the most precise term to use in the
commit message.