Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Destroying a PyCapsule object

Tags:

python

c

cpython

According to documentation, the third argument to PyCapsule_New() can specify a destructor, which I assume should be called when the capsule is destroyed.

void mapDestroy(PyObject *capsule) {

    lash_map_simple_t *map;
    fprintf(stderr, "Entered destructor\n");
    map = (lash_map_simple_t*)PyCapsule_GetPointer(capsule, "MAP_C_API");
    if (map == NULL)
         return;
    fprintf(stderr, "Destroying map %p\n", map);
    lashMapSimpleFree(map);
    free(map);

}

static PyObject * mapSimpleInit_func(PyObject *self, PyObject *args) {

    unsigned int w;
    unsigned int h;
    PyObject *pymap;

    lash_map_simple_t *map = (lash_map_simple_t*)malloc(sizeof(lash_map_simple_t));

    pymap = PyCapsule_New((void *)map, "MAP_C_API", mapDestroy);

    if (!PyArg_ParseTuple(args, "II", &w, &h))
        return NULL;

    lashMapSimpleInit(map, &w, &h);

    return Py_BuildValue("O", pymap);

} 

However, when I instantiate the object and delete it or exit from Python console, the destructor doesn't seem to be called:

>>> a = mapSimpleInit(10,20)
>>> a
<capsule object "MAP_C_API" at 0x7fcf4959f930>
>>> del(a)
>>> a = mapSimpleInit(10,20)
>>> a
<capsule object "MAP_C_API" at 0x7fcf495186f0>
>>> quit()
lash@CANTANDO ~/programming/src/liblashgame $ 

My guess is that it has something to do with the Py_BuildValue() returning a new reference to the "capsule", which upon deletion doesn't affect the original. Anyway, how would I go about ensuring that the object is properly destroyed?

Using Python 3.4.3 [GCC 4.8.4] (on linux)

like image 627
lash Avatar asked Nov 08 '22 09:11

lash


1 Answers

The code above has a reference leak: pymap = PyCapsule_New() returns a new object (its refcount is 1), but Py_BuildValue("O", pymap) creates a new reference to the same object, and its refcount is now 2.

Just return pymap;.

like image 104
Amaury Avatar answered Nov 14 '22 23:11

Amaury