pythonccpythonpython-cffi

Python CFFI `<cdata>` data pointer replace from C land - is it safe?


I am trying to use CFFI to create a python C extension.

Suppose I have the following C code:

void freeSomeType(SomeType_t **ptr)
{
    free(*ptr);
    *ptr = NULL;
}

void func(SomeType_t **ptr)
{
    freeSomeType(ptr);
    *ptr = malloc(...);
}

Then, suppose I call it from python land like so:

ptr = ffi.new("SomeType_t **")

# Init and do stuff with ptr...

lib.func(ptr)

In essence, the pointer holding the actual SomeType ** data inside the ptr's cdata object has changed its value. What happens if I then do:

lib.freeSomeType(ptr)
del ptr

Solution

  • "The pointer holding the actual SomeType ** data (...) has changed": no, the only pointer that changes is of type SomeType *. In CFFI, if you allocate ptr = ffi.new("SomeType **"), then the SomeType ** that you get cannot change. It always points to the same memory, which itself is just pointer-sized and holds a SomeType * pointer. And this is the memory that can change---and that's what the call to lib.func() will do.

    It looks to me like the code you suggest is correct. It is safe to do and won't create memory leaks. Memory ownership is up to the context but that seems right too. The final del ptr has little effect in Python and can be omitted: when the ptr object is no longer referenced from Python, it will free the (pointer-sized) memory it points to.

    If you forget to call lib.freeSomeType(), then indeed you have a leak because the C code called malloc() but never called the corresponding free(). This is the only kind of leak you need to worry about; ffi.new() from Python allocates memory that is managed by Python and disappears if the object returned by ffi.new() goes out of scope.