开发者

c++-to-python swig caused memory leak! Related to Py_BuildValue and SWIG_NewPointerObj

I have the following Swig code that caused memory leak.

  PyObject* FindBestMatch(const Bar& fp) {
    Foo* ptr(new Foo());
    float match;

    // call a function to fill the foo pointer

    return Py_BuildValue(
        "(fO)",
        match,
        SWIG_NewPointerObj(ptr,
                           SWIGTYPE_p_Foo,
                           0 /* own */));
  }

I figured that ptr is not freed properly. So I did the following:

  PyObject* FindBestMatch(const Bar& fp) {
    Foo* ptr(new Foo());
    float match;

    // call a function to fill the foo pointer

    *PyObject *o = SWIG_NewPointerObj(ptr,
                       SWIGTYPE_p_Foo,
                       1 /* own */);*  <------- 1 means pass the ownership to python
    PyObject *result = Py_BuildValue("(fO)", match, o);
    Py_XDECREF(o);
    return result;
  }

But I am not very sure whether this will cause memory corruption. Here, Py_XDECREF(o) will decrease the ref count, which can free memory used by object "o". But o is part of the return value "result". Freeing "o" can cause data corrupt, I guess?

I tried my change. It works fine and the caller (python code) does see the expected data. But this could be because nobody else overwrites to that memory area.

So what's the right way to deal with memory management of the above code? I search the swig docs, but don't see v开发者_StackOverflow中文版ery concrete description.

Please help!

Thanks, xin


Well according to the code automatically generated by SWIG for function that allocate a new object, the proper way should be to just set the Python Ownership flag to one, which means : python owns this pointer
This make sense : where else could your new Foo() be deallocated ? The Swig wrapper object will handle it.

PyObject* FindBestMatch(const Bar& fp) {
    Foo* ptr(new Foo());
    float match;

    // call a function to fill the foo pointer

    PyObject* o = SWIG_NewPointerObj(ptr,
                   SWIGTYPE_p_Foo,
                   SWIG_BUILTIN_INIT |  0);

    PyObject* result = Py_BuildValue("(fO)", match, o);
    return result;
}

However I don't see why you would decrease the reference count on o : if I recall correctly when passing an object to a tuple or list the reference is stolen.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜