Skip to content

Instantly share code, notes, and snippets.

@RoadrunnerWMC
Created August 11, 2019 02:26
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save RoadrunnerWMC/fb434e7ebaa12f533a2ce1df8d094579 to your computer and use it in GitHub Desktop.
Save RoadrunnerWMC/fb434e7ebaa12f533a2ce1df8d094579 to your computer and use it in GitHub Desktop.
Test case for cffi ffi.gc() callback-upon-deletion subinterpreter issue
from cffi import FFI
ffibuilder = FFI()
ffibuilder.cdef(
"""
typedef struct c_class c_class;
typedef void destroy_callback_function();
extern c_class* c_class_create(destroy_callback_function *callback);
extern void c_class_destroy(c_class *obj);
extern "Python" void _py_destroy_callback_function_impl();
""")
ffibuilder.set_source('_c_code', # name of the output C extension
"""
#include "c_code.h"
""",
sources=['c_code.c'])
if __name__ == '__main__':
ffibuilder.compile(verbose=True)
#include <stdlib.h>
#include "c_code.h"
struct c_class {
destroy_callback_function *destroy_callback;
};
extern void c_class_destroy(c_class *obj)
{
if (obj->destroy_callback) {
obj->destroy_callback();
}
free(obj);
}
extern c_class* c_class_create(destroy_callback_function *callback)
{
c_class *obj = malloc(sizeof (c_class));
*obj = (c_class) {
.destroy_callback = callback
};
return obj;
}
#ifndef C_CODE_H
#define C_CODE_H
typedef struct c_class c_class;
typedef void destroy_callback_function();
extern c_class* c_class_create(destroy_callback_function *callback);
extern void c_class_destroy(c_class *obj);
#endif // C_CODE_H
import wrapper
# Removing this function causes the callback to execute successfully, for some reason?
def unused_function():
print('(Nothing calls or references this function, so this print call will never execute)')
obj = wrapper.make_class()
print('End of test.py')
# (obj goes out of scope here)
from _c_code import lib, ffi
@ffi.def_extern()
def _py_destroy_callback_function_impl():
print('Destroy callback')
def make_class():
return ffi.gc(
lib.c_class_create(lib._py_destroy_callback_function_impl),
lib.c_class_destroy,
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment