[libvirt] [PATCH] python: Avoid memory leaks on libvirt_virNodeGetMemoryStats

Alex Jia ajia at redhat.com
Tue Feb 14 10:48:25 UTC 2012


On 02/14/2012 06:08 PM, Peter Krempa wrote:
> On 02/14/2012 09:31 AM, ajia at redhat.com wrote:
>> From: Alex Jia<ajia at redhat.com>
>>
>> Detected by valgrind. Leaks are introduced in commit 17c7795.
>>
>> * python/libvirt-override.c (libvirt_virNodeGetMemoryStats): fix 
>> memory leaks
>> and improve codes return value.
>>
>> For details, please see the following link:
>> RHBZ: https://bugzilla.redhat.com/show_bug.cgi?id=770944
>>
>> Signed-off-by: Alex Jia<ajia at redhat.com>
>> ---
>>   python/libvirt-override.c |   41 
>> ++++++++++++++++++++++++++++++-----------
>>   1 files changed, 30 insertions(+), 11 deletions(-)
>>
>> diff --git a/python/libvirt-override.c b/python/libvirt-override.c
>> index 4e8a97e..ecb11ea 100644
>> --- a/python/libvirt-override.c
>> +++ b/python/libvirt-override.c
>> @@ -2426,7 +2426,9 @@ libvirt_virNodeGetCPUStats(PyObject *self 
>> ATTRIBUTE_UNUSED, PyObject *args)
>>   static PyObject *
>>   libvirt_virNodeGetMemoryStats(PyObject *self ATTRIBUTE_UNUSED, 
>> PyObject *args)
>>   {
>> -    PyObject *ret;
>> +    PyObject *info, *ret;
>
> I'd initialize ret to VIR_PY_NONE here instead of doing it multiple 
> times later on.
>
>> +    PyObject *key = NULL;
>> +    PyObject *val = NULL;
>>       PyObject *pyobj_conn;
>>       virConnectPtr conn;
>>       unsigned int flags;
>> @@ -2446,28 +2448,45 @@ libvirt_virNodeGetMemoryStats(PyObject *self 
>> ATTRIBUTE_UNUSED, PyObject *args)
>>
>>       if (nparams) {
>>           if (VIR_ALLOC_N(stats, nparams)<  0)
>> -            return VIR_PY_NONE;
>> +            return PyErr_NoMemory();
>>
>>           LIBVIRT_BEGIN_ALLOW_THREADS;
>>           c_retval = virNodeGetMemoryStats(conn, cellNum, 
>> stats,&nparams, flags);
>>           LIBVIRT_END_ALLOW_THREADS;
>>           if (c_retval<  0) {
>> -            VIR_FREE(stats);
>> -            return VIR_PY_NONE;
>> +            ret = VIR_PY_NONE;
>
> Like here.
>
>> +            goto cleanup;
>>           }
>>       }
>> -    if (!(ret = PyDict_New())) {
>> -        VIR_FREE(stats);
>> -        return VIR_PY_NONE;
>> +    if (!(info = PyDict_New())) {
>> +        ret = VIR_PY_NONE;
>
> And here
>
>> +        goto cleanup;
>>       }
>> +
>>       for (i = 0; i<  nparams; i++) {
>> -        PyDict_SetItem(ret,
>> -                       libvirt_constcharPtrWrap(stats[i].field),
>> -                       libvirt_ulonglongWrap(stats[i].value));
>> +        key = libvirt_constcharPtrWrap(stats[i].field);
>> +        val = libvirt_ulonglongWrap(stats[i].value);
>> +
>> +        if (!key || !val)
>> +            goto cleanup;
>> +
>> +        if (PyDict_SetItem(info, key, val)<  0) {
>> +            Py_DECREF(info);
>> +            goto cleanup;
>> +        }
>> +
>> +        Py_DECREF(key);
>> +        Py_DECREF(val);
>>       }
>>
>>       VIR_FREE(stats);
>> -    return ret;
>> +    return info;
>> +
>> +cleanup:
>
> This label gets called only on a error path, so I'd call it "error" 
> instead of cleanup.
>
>> +    VIR_FREE(stats);
>> +    Py_XDECREF(key);
>> +    Py_XDECREF(val);
>> +    return NULL;
>
> You're returning NULL instead of VIR_PY_NONE. (or the variable err)
>
>>   }
>>
>>   static PyObject *
>
> With code like this, the variable err isn't used anywhere.
>
> Introduction of the new variable "info" is probably not needed, and 
> you may use "ret" for this purpose.
If so, the 'ret' will have 2 different function, the one is return 
value, the other is dictionary object,
I'm not sure it's a good idea to override previous variable 'ret', 
although the codes are quite simple.

Thanks for your comment,
Alex
>
> It should be possible to rewrite the code (especialy the cleanup 
> section) so that also the success path may pass that way. That would 
> simplify the code.
>
> Peter




More information about the libvir-list mailing list