Het Gala <het.g...@nutanix.com> writes:

> On 28/11/23 12:46 pm, Markus Armbruster wrote:
>> Your commit message is all in one line.  You need to format it like
>>
>>       migration: Plug memory leak
>>
>>      'channel' and 'addr' in qmp_migrate() are not auto-freed.
>>      migrate_uri_parse() allocates memory which is returned to 'channel',
>>      which is leaked because there is no code for freeing 'channel' or
>>      'addr'.  So, free addr and channel to avoid memory leak.  'addr'
>>      does shallow copying of channel->addr, hence free 'channel' itself
>>      and deep free contents of 'addr'.
>>
>> Het Gala<het.g...@nutanix.com>  writes:
> Yeah, I made the changes in v2 patchset.
>>> ---
>>>   migration/migration.c | 2 ++
>>>   1 file changed, 2 insertions(+)
>>>
>>> diff --git a/migration/migration.c b/migration/migration.c
>>> index 28a34c9068..29efb51b62 100644
>>> --- a/migration/migration.c
>>> +++ b/migration/migration.c
>>> @@ -2004,6 +2004,8 @@ void qmp_migrate(const char *uri, bool has_channels,
>>>                             MIGRATION_STATUS_FAILED);
>>>           block_cleanup_parameters();
>>>       }
>>> +    g_free(channel);
>>> +    qapi_free_MigrationAddress(addr);
>>>         if (local_err) {
>>>           if (!resume_requested) {
>> 2. hmp_migrate()
>>
>>     hmp_migrate() allocates @channel with migrate_uri_parse(), adds it to
>>     list @caps, passes @caps to qmp_migrate(), then frees @caps with
>>     qapi_free_MigrationChannelList().
>
> Markus, sorry if I was not able to put point clearly, what I meant is that 
> the local 'channel' variable used in qmp_migrate() i.e.
>
> 'MigrationChannel *channel = NULL', is defined in qmp_migrate() and if the 
> user opts for 'uri' then '@channels' coming from hmp_migrate() will be NULL, 
> and then migrate_uri_parse() will populate memory into 'channel', and that is 
> not getting freed after it's use is over.
>
> I think, that is where memory leak might be happening ?

Aha!

    if (uri && has_channels) {
        error_setg(errp, "'uri' and 'channels' arguments are mutually "
                   "exclusive; exactly one of the two should be present in "
                   "'migrate' qmp command ");
        return;
    } else if (channels) {
        /* To verify that Migrate channel list has only item */
        if (channels->next) {
            error_setg(errp, "Channel list has more than one entries");
            return;
        }
        channel = channels->value;
    } else if (uri) {
        /* caller uses the old URI syntax */
        if (!migrate_uri_parse(uri, &channel, errp)) {
            return;
        }
    } else {
        error_setg(errp, "neither 'uri' or 'channels' argument are "
                   "specified in 'migrate' qmp command ");
        return;
    }

At this point, @channel is either channels->value, or from
migrate_uri_parse().

We must not free in the former case, we must free in the latter case,

Before your patch, we don't free.  Memory leak in the latter case.

Afterwards, we free.  Double-free in the former case.

You could guard the free, like so:

    if (uri) {
        qapi_free_MigrationChannel(channel);
    }


By the way, I the conditional shown above is harder to understand than
necessary.  I like to get the errors out of the way at the beginning,
like this:

    if (uri && has_channels) {
        error_setg(errp, "'uri' and 'channels' arguments are mutually "
                   "exclusive; exactly one of the two should be present in "
                   "'migrate' qmp command ");
        return;
    }
    if (!uri && !has_channels) {
        error_setg(errp, "neither 'uri' or 'channels' argument are "
                   "specified in 'migrate' qmp command ");
        return;
    }

    if (channels) {
        /* To verify that Migrate channel list has only item */

Or even

    if (!uri == !has_channels) {
        error_setg(errp, "need either 'uri' or 'channels' argument")
        return;
    }

Suggestion, not demand.  If you do it, separate patch.


Reply via email to