Commit 326f154d authored by Thomas Heller's avatar Thomas Heller

Merged revisions 62481 via svnmerge from

svn+ssh://pythondev@svn.python.org/python/trunk

........
  r62481 | thomas.heller | 2008-04-24 20:14:19 +0200 (Do, 24 Apr 2008) | 3 lines

  Remove cyclic reference in CFuncPtr instances; see issue #2682.

  Backport candidate for the release25-maint branch.
........
parent 249bb671
...@@ -32,6 +32,9 @@ Extension Modules ...@@ -32,6 +32,9 @@ Extension Modules
Library Library
------- -------
- Issue #2682: ctypes callback functions now longer contain a cyclic
reference to themselves.
- Issue #2058: Remove the buf attribute and add __slots__ to the TarInfo - Issue #2058: Remove the buf attribute and add __slots__ to the TarInfo
class in order to reduce tarfile's memory usage. class in order to reduce tarfile's memory usage.
......
...@@ -3052,7 +3052,7 @@ CFuncPtr_new(PyTypeObject *type, PyObject *args, PyObject *kwds) ...@@ -3052,7 +3052,7 @@ CFuncPtr_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
CFuncPtrObject *self; CFuncPtrObject *self;
PyObject *callable; PyObject *callable;
StgDictObject *dict; StgDictObject *dict;
ffi_info *thunk; CThunkObject *thunk;
if (PyTuple_GET_SIZE(args) == 0) if (PyTuple_GET_SIZE(args) == 0)
return GenericCData_new(type, args, kwds); return GenericCData_new(type, args, kwds);
...@@ -3108,11 +3108,6 @@ CFuncPtr_new(PyTypeObject *type, PyObject *args, PyObject *kwds) ...@@ -3108,11 +3108,6 @@ CFuncPtr_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
return NULL; return NULL;
} }
/*****************************************************************/
/* The thunk keeps unowned references to callable and dict->argtypes
so we have to keep them alive somewhere else: callable is kept in self,
dict->argtypes is in the type's stgdict.
*/
thunk = AllocFunctionCallback(callable, thunk = AllocFunctionCallback(callable,
dict->argtypes, dict->argtypes,
dict->restype, dict->restype,
...@@ -3121,27 +3116,22 @@ CFuncPtr_new(PyTypeObject *type, PyObject *args, PyObject *kwds) ...@@ -3121,27 +3116,22 @@ CFuncPtr_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
return NULL; return NULL;
self = (CFuncPtrObject *)GenericCData_new(type, args, kwds); self = (CFuncPtrObject *)GenericCData_new(type, args, kwds);
if (self == NULL) if (self == NULL) {
Py_DECREF(thunk);
return NULL; return NULL;
}
Py_INCREF(callable); Py_INCREF(callable);
self->callable = callable; self->callable = callable;
self->thunk = thunk; self->thunk = thunk;
*(void **)self->b_ptr = *(void **)thunk; *(void **)self->b_ptr = (void *)thunk->pcl;
/* We store ourself in self->b_objects[0], because the whole instance Py_INCREF((PyObject *)thunk); /* for KeepRef */
must be kept alive if stored in a structure field, for example. if (-1 == KeepRef((CDataObject *)self, 0, (PyObject *)thunk)) {
Cycle GC to the rescue! And we have a unittest proving that this works
correctly...
*/
Py_INCREF((PyObject *)self); /* for KeepRef */
if (-1 == KeepRef((CDataObject *)self, 0, (PyObject *)self)) {
Py_DECREF((PyObject *)self); Py_DECREF((PyObject *)self);
return NULL; return NULL;
} }
return (PyObject *)self; return (PyObject *)self;
} }
...@@ -3590,6 +3580,7 @@ CFuncPtr_traverse(CFuncPtrObject *self, visitproc visit, void *arg) ...@@ -3590,6 +3580,7 @@ CFuncPtr_traverse(CFuncPtrObject *self, visitproc visit, void *arg)
Py_VISIT(self->argtypes); Py_VISIT(self->argtypes);
Py_VISIT(self->converters); Py_VISIT(self->converters);
Py_VISIT(self->paramflags); Py_VISIT(self->paramflags);
Py_VISIT(self->thunk);
return CData_traverse((CDataObject *)self, visit, arg); return CData_traverse((CDataObject *)self, visit, arg);
} }
...@@ -3603,13 +3594,7 @@ CFuncPtr_clear(CFuncPtrObject *self) ...@@ -3603,13 +3594,7 @@ CFuncPtr_clear(CFuncPtrObject *self)
Py_CLEAR(self->argtypes); Py_CLEAR(self->argtypes);
Py_CLEAR(self->converters); Py_CLEAR(self->converters);
Py_CLEAR(self->paramflags); Py_CLEAR(self->paramflags);
Py_CLEAR(self->thunk);
if (self->thunk) {
FreeClosure(self->thunk->pcl);
PyMem_Free(self->thunk);
self->thunk = NULL;
}
return CData_clear((CDataObject *)self); return CData_clear((CDataObject *)self);
} }
...@@ -5011,6 +4996,9 @@ init_ctypes(void) ...@@ -5011,6 +4996,9 @@ init_ctypes(void)
if (PyType_Ready(&PyCArg_Type) < 0) if (PyType_Ready(&PyCArg_Type) < 0)
return; return;
if (PyType_Ready(&CThunk_Type) < 0)
return;
/* StgDict is derived from PyDict_Type */ /* StgDict is derived from PyDict_Type */
StgDict_Type.tp_base = &PyDict_Type; StgDict_Type.tp_base = &PyDict_Type;
if (PyType_Ready(&StgDict_Type) < 0) if (PyType_Ready(&StgDict_Type) < 0)
......
...@@ -7,6 +7,73 @@ ...@@ -7,6 +7,73 @@
#endif #endif
#include "ctypes.h" #include "ctypes.h"
/**************************************************************/
static CThunkObject_dealloc(PyObject *_self)
{
CThunkObject *self = (CThunkObject *)_self;
Py_XDECREF(self->converters);
Py_XDECREF(self->callable);
Py_XDECREF(self->restype);
if (self->pcl)
FreeClosure(self->pcl);
PyObject_Del(self);
}
static int
CThunkObject_traverse(PyObject *_self, visitproc visit, void *arg)
{
CThunkObject *self = (CThunkObject *)_self;
Py_VISIT(self->converters);
Py_VISIT(self->callable);
Py_VISIT(self->restype);
return 0;
}
static int
CThunkObject_clear(PyObject *_self)
{
CThunkObject *self = (CThunkObject *)_self;
Py_CLEAR(self->converters);
Py_CLEAR(self->callable);
Py_CLEAR(self->restype);
return 0;
}
PyTypeObject CThunk_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
"_ctypes.CThunkObject",
sizeof(CThunkObject), /* tp_basicsize */
sizeof(ffi_type), /* tp_itemsize */
CThunkObject_dealloc, /* tp_dealloc */
0, /* tp_print */
0, /* tp_getattr */
0, /* tp_setattr */
0, /* tp_compare */
0, /* tp_repr */
0, /* tp_as_number */
0, /* tp_as_sequence */
0, /* tp_as_mapping */
0, /* tp_hash */
0, /* tp_call */
0, /* tp_str */
0, /* tp_getattro */
0, /* tp_setattro */
0, /* tp_as_buffer */
Py_TPFLAGS_DEFAULT, /* tp_flags */
"CThunkObject", /* tp_doc */
CThunkObject_traverse, /* tp_traverse */
CThunkObject_clear, /* tp_clear */
0, /* tp_richcompare */
0, /* tp_weaklistoffset */
0, /* tp_iter */
0, /* tp_iternext */
0, /* tp_methods */
0, /* tp_members */
};
/**************************************************************/
static void static void
PrintError(char *msg, ...) PrintError(char *msg, ...)
{ {
...@@ -244,32 +311,56 @@ static void closure_fcn(ffi_cif *cif, ...@@ -244,32 +311,56 @@ static void closure_fcn(ffi_cif *cif,
void **args, void **args,
void *userdata) void *userdata)
{ {
ffi_info *p = userdata; CThunkObject *p = (CThunkObject *)userdata;
_CallPythonObject(resp, _CallPythonObject(resp,
p->restype, p->ffi_restype,
p->setfunc, p->setfunc,
p->callable, p->callable,
p->converters, p->converters,
args); args);
} }
ffi_info *AllocFunctionCallback(PyObject *callable, static CThunkObject* CThunkObject_new(Py_ssize_t nArgs)
PyObject *converters, {
PyObject *restype, CThunkObject *p;
int is_cdecl) int i;
p = PyObject_NewVar(CThunkObject, &CThunk_Type, nArgs);
if (p == NULL) {
PyErr_NoMemory();
return NULL;
}
p->pcl = NULL;
memset(&p->cif, 0, sizeof(p->cif));
p->converters = NULL;
p->callable = NULL;
p->setfunc = NULL;
p->ffi_restype = NULL;
for (i = 0; i < nArgs + 1; ++i)
p->atypes[i] = NULL;
return p;
}
CThunkObject *AllocFunctionCallback(PyObject *callable,
PyObject *converters,
PyObject *restype,
int is_cdecl)
{ {
int result; int result;
ffi_info *p; CThunkObject *p;
Py_ssize_t nArgs, i; Py_ssize_t nArgs, i;
ffi_abi cc; ffi_abi cc;
nArgs = PySequence_Size(converters); nArgs = PySequence_Size(converters);
p = (ffi_info *)PyMem_Malloc(sizeof(ffi_info) + sizeof(ffi_type) * (nArgs)); p = CThunkObject_new(nArgs);
if (p == NULL) { if (p == NULL)
PyErr_NoMemory();
return NULL; return NULL;
}
assert(CThunk_CheckExact((PyObject *)p));
p->pcl = MallocClosure(); p->pcl = MallocClosure();
if (p->pcl == NULL) { if (p->pcl == NULL) {
PyErr_NoMemory(); PyErr_NoMemory();
...@@ -285,9 +376,11 @@ ffi_info *AllocFunctionCallback(PyObject *callable, ...@@ -285,9 +376,11 @@ ffi_info *AllocFunctionCallback(PyObject *callable,
} }
p->atypes[i] = NULL; p->atypes[i] = NULL;
Py_INCREF(restype);
p->restype = restype;
if (restype == Py_None) { if (restype == Py_None) {
p->setfunc = NULL; p->setfunc = NULL;
p->restype = &ffi_type_void; p->ffi_restype = &ffi_type_void;
} else { } else {
StgDictObject *dict = PyType_stgdict(restype); StgDictObject *dict = PyType_stgdict(restype);
if (dict == NULL || dict->setfunc == NULL) { if (dict == NULL || dict->setfunc == NULL) {
...@@ -296,7 +389,7 @@ ffi_info *AllocFunctionCallback(PyObject *callable, ...@@ -296,7 +389,7 @@ ffi_info *AllocFunctionCallback(PyObject *callable,
goto error; goto error;
} }
p->setfunc = dict->setfunc; p->setfunc = dict->setfunc;
p->restype = &dict->ffi_type_pointer; p->ffi_restype = &dict->ffi_type_pointer;
} }
cc = FFI_DEFAULT_ABI; cc = FFI_DEFAULT_ABI;
...@@ -320,16 +413,14 @@ ffi_info *AllocFunctionCallback(PyObject *callable, ...@@ -320,16 +413,14 @@ ffi_info *AllocFunctionCallback(PyObject *callable,
goto error; goto error;
} }
Py_INCREF(converters);
p->converters = converters; p->converters = converters;
Py_INCREF(callable);
p->callable = callable; p->callable = callable;
return p; return p;
error: error:
if (p) { Py_XDECREF(p);
if (p->pcl)
FreeClosure(p->pcl);
PyMem_Free(p);
}
return NULL; return NULL;
} }
......
...@@ -53,14 +53,18 @@ struct tagCDataObject { ...@@ -53,14 +53,18 @@ struct tagCDataObject {
}; };
typedef struct { typedef struct {
PyObject_VAR_HEAD
ffi_closure *pcl; /* the C callable */ ffi_closure *pcl; /* the C callable */
ffi_cif cif; ffi_cif cif;
PyObject *converters; PyObject *converters;
PyObject *callable; PyObject *callable;
PyObject *restype;
SETFUNC setfunc; SETFUNC setfunc;
ffi_type *restype; ffi_type *ffi_restype;
ffi_type *atypes[1]; ffi_type *atypes[1];
} ffi_info; } CThunkObject;
extern PyTypeObject CThunk_Type;
#define CThunk_CheckExact(v) ((v)->ob_type == &CThunk_Type)
typedef struct { typedef struct {
/* First part identical to tagCDataObject */ /* First part identical to tagCDataObject */
...@@ -76,7 +80,7 @@ typedef struct { ...@@ -76,7 +80,7 @@ typedef struct {
union value b_value; union value b_value;
/* end of tagCDataObject, additional fields follow */ /* end of tagCDataObject, additional fields follow */
ffi_info *thunk; CThunkObject *thunk;
PyObject *callable; PyObject *callable;
/* These two fields will override the ones in the type's stgdict if /* These two fields will override the ones in the type's stgdict if
...@@ -147,10 +151,10 @@ extern void init_callbacks_in_module(PyObject *m); ...@@ -147,10 +151,10 @@ extern void init_callbacks_in_module(PyObject *m);
extern PyMethodDef module_methods[]; extern PyMethodDef module_methods[];
extern ffi_info *AllocFunctionCallback(PyObject *callable, extern CThunkObject *AllocFunctionCallback(PyObject *callable,
PyObject *converters, PyObject *converters,
PyObject *restype, PyObject *restype,
int stdcall); int stdcall);
/* a table entry describing a predefined ctypes type */ /* a table entry describing a predefined ctypes type */
struct fielddesc { struct fielddesc {
char code; char code;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment