Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit e106dc3

Browse files
author
Thomas Heller
committed
Merged revisions 62481 via svnmerge from
svn+ssh://[email protected]/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. ........
1 parent a461873 commit e106dc3

4 files changed

Lines changed: 136 additions & 50 deletions

File tree

Misc/NEWS

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,9 @@ Extension Modules
3232
Library
3333
-------
3434

35+
- Issue #2682: ctypes callback functions now longer contain a cyclic
36+
reference to themselves.
37+
3538
- Issue #2058: Remove the buf attribute and add __slots__ to the TarInfo
3639
class in order to reduce tarfile's memory usage.
3740

Modules/_ctypes/_ctypes.c

Lines changed: 13 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -3052,7 +3052,7 @@ CFuncPtr_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
30523052
CFuncPtrObject *self;
30533053
PyObject *callable;
30543054
StgDictObject *dict;
3055-
ffi_info *thunk;
3055+
CThunkObject *thunk;
30563056

30573057
if (PyTuple_GET_SIZE(args) == 0)
30583058
return GenericCData_new(type, args, kwds);
@@ -3108,11 +3108,6 @@ CFuncPtr_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
31083108
return NULL;
31093109
}
31103110

3111-
/*****************************************************************/
3112-
/* The thunk keeps unowned references to callable and dict->argtypes
3113-
so we have to keep them alive somewhere else: callable is kept in self,
3114-
dict->argtypes is in the type's stgdict.
3115-
*/
31163111
thunk = AllocFunctionCallback(callable,
31173112
dict->argtypes,
31183113
dict->restype,
@@ -3121,27 +3116,22 @@ CFuncPtr_new(PyTypeObject *type, PyObject *args, PyObject *kwds)
31213116
return NULL;
31223117

31233118
self = (CFuncPtrObject *)GenericCData_new(type, args, kwds);
3124-
if (self == NULL)
3119+
if (self == NULL) {
3120+
Py_DECREF(thunk);
31253121
return NULL;
3122+
}
31263123

31273124
Py_INCREF(callable);
31283125
self->callable = callable;
31293126

31303127
self->thunk = thunk;
3131-
*(void **)self->b_ptr = *(void **)thunk;
3132-
3133-
/* We store ourself in self->b_objects[0], because the whole instance
3134-
must be kept alive if stored in a structure field, for example.
3135-
Cycle GC to the rescue! And we have a unittest proving that this works
3136-
correctly...
3137-
*/
3138-
3139-
Py_INCREF((PyObject *)self); /* for KeepRef */
3140-
if (-1 == KeepRef((CDataObject *)self, 0, (PyObject *)self)) {
3128+
*(void **)self->b_ptr = (void *)thunk->pcl;
3129+
3130+
Py_INCREF((PyObject *)thunk); /* for KeepRef */
3131+
if (-1 == KeepRef((CDataObject *)self, 0, (PyObject *)thunk)) {
31413132
Py_DECREF((PyObject *)self);
31423133
return NULL;
31433134
}
3144-
31453135
return (PyObject *)self;
31463136
}
31473137

@@ -3590,6 +3580,7 @@ CFuncPtr_traverse(CFuncPtrObject *self, visitproc visit, void *arg)
35903580
Py_VISIT(self->argtypes);
35913581
Py_VISIT(self->converters);
35923582
Py_VISIT(self->paramflags);
3583+
Py_VISIT(self->thunk);
35933584
return CData_traverse((CDataObject *)self, visit, arg);
35943585
}
35953586

@@ -3603,13 +3594,7 @@ CFuncPtr_clear(CFuncPtrObject *self)
36033594
Py_CLEAR(self->argtypes);
36043595
Py_CLEAR(self->converters);
36053596
Py_CLEAR(self->paramflags);
3606-
3607-
if (self->thunk) {
3608-
FreeClosure(self->thunk->pcl);
3609-
PyMem_Free(self->thunk);
3610-
self->thunk = NULL;
3611-
}
3612-
3597+
Py_CLEAR(self->thunk);
36133598
return CData_clear((CDataObject *)self);
36143599
}
36153600

@@ -5011,6 +4996,9 @@ init_ctypes(void)
50114996
if (PyType_Ready(&PyCArg_Type) < 0)
50124997
return;
50134998

4999+
if (PyType_Ready(&CThunk_Type) < 0)
5000+
return;
5001+
50145002
/* StgDict is derived from PyDict_Type */
50155003
StgDict_Type.tp_base = &PyDict_Type;
50165004
if (PyType_Ready(&StgDict_Type) < 0)

Modules/_ctypes/callbacks.c

Lines changed: 109 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,73 @@
77
#endif
88
#include "ctypes.h"
99

10+
/**************************************************************/
11+
12+
static CThunkObject_dealloc(PyObject *_self)
13+
{
14+
CThunkObject *self = (CThunkObject *)_self;
15+
Py_XDECREF(self->converters);
16+
Py_XDECREF(self->callable);
17+
Py_XDECREF(self->restype);
18+
if (self->pcl)
19+
FreeClosure(self->pcl);
20+
PyObject_Del(self);
21+
}
22+
23+
static int
24+
CThunkObject_traverse(PyObject *_self, visitproc visit, void *arg)
25+
{
26+
CThunkObject *self = (CThunkObject *)_self;
27+
Py_VISIT(self->converters);
28+
Py_VISIT(self->callable);
29+
Py_VISIT(self->restype);
30+
return 0;
31+
}
32+
33+
static int
34+
CThunkObject_clear(PyObject *_self)
35+
{
36+
CThunkObject *self = (CThunkObject *)_self;
37+
Py_CLEAR(self->converters);
38+
Py_CLEAR(self->callable);
39+
Py_CLEAR(self->restype);
40+
return 0;
41+
}
42+
43+
PyTypeObject CThunk_Type = {
44+
PyVarObject_HEAD_INIT(NULL, 0)
45+
"_ctypes.CThunkObject",
46+
sizeof(CThunkObject), /* tp_basicsize */
47+
sizeof(ffi_type), /* tp_itemsize */
48+
CThunkObject_dealloc, /* tp_dealloc */
49+
0, /* tp_print */
50+
0, /* tp_getattr */
51+
0, /* tp_setattr */
52+
0, /* tp_compare */
53+
0, /* tp_repr */
54+
0, /* tp_as_number */
55+
0, /* tp_as_sequence */
56+
0, /* tp_as_mapping */
57+
0, /* tp_hash */
58+
0, /* tp_call */
59+
0, /* tp_str */
60+
0, /* tp_getattro */
61+
0, /* tp_setattro */
62+
0, /* tp_as_buffer */
63+
Py_TPFLAGS_DEFAULT, /* tp_flags */
64+
"CThunkObject", /* tp_doc */
65+
CThunkObject_traverse, /* tp_traverse */
66+
CThunkObject_clear, /* tp_clear */
67+
0, /* tp_richcompare */
68+
0, /* tp_weaklistoffset */
69+
0, /* tp_iter */
70+
0, /* tp_iternext */
71+
0, /* tp_methods */
72+
0, /* tp_members */
73+
};
74+
75+
/**************************************************************/
76+
1077
static void
1178
PrintError(char *msg, ...)
1279
{
@@ -244,32 +311,56 @@ static void closure_fcn(ffi_cif *cif,
244311
void **args,
245312
void *userdata)
246313
{
247-
ffi_info *p = userdata;
314+
CThunkObject *p = (CThunkObject *)userdata;
248315

249316
_CallPythonObject(resp,
250-
p->restype,
317+
p->ffi_restype,
251318
p->setfunc,
252319
p->callable,
253320
p->converters,
254321
args);
255322
}
256323

257-
ffi_info *AllocFunctionCallback(PyObject *callable,
258-
PyObject *converters,
259-
PyObject *restype,
260-
int is_cdecl)
324+
static CThunkObject* CThunkObject_new(Py_ssize_t nArgs)
325+
{
326+
CThunkObject *p;
327+
int i;
328+
329+
p = PyObject_NewVar(CThunkObject, &CThunk_Type, nArgs);
330+
if (p == NULL) {
331+
PyErr_NoMemory();
332+
return NULL;
333+
}
334+
335+
p->pcl = NULL;
336+
memset(&p->cif, 0, sizeof(p->cif));
337+
p->converters = NULL;
338+
p->callable = NULL;
339+
p->setfunc = NULL;
340+
p->ffi_restype = NULL;
341+
342+
for (i = 0; i < nArgs + 1; ++i)
343+
p->atypes[i] = NULL;
344+
return p;
345+
}
346+
347+
CThunkObject *AllocFunctionCallback(PyObject *callable,
348+
PyObject *converters,
349+
PyObject *restype,
350+
int is_cdecl)
261351
{
262352
int result;
263-
ffi_info *p;
353+
CThunkObject *p;
264354
Py_ssize_t nArgs, i;
265355
ffi_abi cc;
266356

267357
nArgs = PySequence_Size(converters);
268-
p = (ffi_info *)PyMem_Malloc(sizeof(ffi_info) + sizeof(ffi_type) * (nArgs));
269-
if (p == NULL) {
270-
PyErr_NoMemory();
358+
p = CThunkObject_new(nArgs);
359+
if (p == NULL)
271360
return NULL;
272-
}
361+
362+
assert(CThunk_CheckExact((PyObject *)p));
363+
273364
p->pcl = MallocClosure();
274365
if (p->pcl == NULL) {
275366
PyErr_NoMemory();
@@ -285,9 +376,11 @@ ffi_info *AllocFunctionCallback(PyObject *callable,
285376
}
286377
p->atypes[i] = NULL;
287378

379+
Py_INCREF(restype);
380+
p->restype = restype;
288381
if (restype == Py_None) {
289382
p->setfunc = NULL;
290-
p->restype = &ffi_type_void;
383+
p->ffi_restype = &ffi_type_void;
291384
} else {
292385
StgDictObject *dict = PyType_stgdict(restype);
293386
if (dict == NULL || dict->setfunc == NULL) {
@@ -296,7 +389,7 @@ ffi_info *AllocFunctionCallback(PyObject *callable,
296389
goto error;
297390
}
298391
p->setfunc = dict->setfunc;
299-
p->restype = &dict->ffi_type_pointer;
392+
p->ffi_restype = &dict->ffi_type_pointer;
300393
}
301394

302395
cc = FFI_DEFAULT_ABI;
@@ -320,16 +413,14 @@ ffi_info *AllocFunctionCallback(PyObject *callable,
320413
goto error;
321414
}
322415

416+
Py_INCREF(converters);
323417
p->converters = converters;
418+
Py_INCREF(callable);
324419
p->callable = callable;
325420
return p;
326421

327422
error:
328-
if (p) {
329-
if (p->pcl)
330-
FreeClosure(p->pcl);
331-
PyMem_Free(p);
332-
}
423+
Py_XDECREF(p);
333424
return NULL;
334425
}
335426

Modules/_ctypes/ctypes.h

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -53,14 +53,18 @@ struct tagCDataObject {
5353
};
5454

5555
typedef struct {
56+
PyObject_VAR_HEAD
5657
ffi_closure *pcl; /* the C callable */
5758
ffi_cif cif;
5859
PyObject *converters;
5960
PyObject *callable;
61+
PyObject *restype;
6062
SETFUNC setfunc;
61-
ffi_type *restype;
63+
ffi_type *ffi_restype;
6264
ffi_type *atypes[1];
63-
} ffi_info;
65+
} CThunkObject;
66+
extern PyTypeObject CThunk_Type;
67+
#define CThunk_CheckExact(v) ((v)->ob_type == &CThunk_Type)
6468

6569
typedef struct {
6670
/* First part identical to tagCDataObject */
@@ -76,7 +80,7 @@ typedef struct {
7680
union value b_value;
7781
/* end of tagCDataObject, additional fields follow */
7882

79-
ffi_info *thunk;
83+
CThunkObject *thunk;
8084
PyObject *callable;
8185

8286
/* 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);
147151

148152
extern PyMethodDef module_methods[];
149153

150-
extern ffi_info *AllocFunctionCallback(PyObject *callable,
151-
PyObject *converters,
152-
PyObject *restype,
153-
int stdcall);
154+
extern CThunkObject *AllocFunctionCallback(PyObject *callable,
155+
PyObject *converters,
156+
PyObject *restype,
157+
int stdcall);
154158
/* a table entry describing a predefined ctypes type */
155159
struct fielddesc {
156160
char code;

0 commit comments

Comments
 (0)