Skip to content

Commit d19fa7a

Browse files
authored
bpo-38823: Fix refleaks in _ctypes extension init (GH-23247)
Fix reference leaks in the error path of the initialization function the _ctypes extension module: call Py_DECREF(mod) on error. Change PyCFuncPtr_Type name from _ctypes.PyCFuncPtr to _ctypes.CFuncPtr to be consistent with the name exposed in the _ctypes namespace (_ctypes.CFuncPtr). Split PyInit__ctypes() function into sub-functions and add macros for readability.
1 parent c640915 commit d19fa7a

File tree

2 files changed

+156
-162
lines changed

2 files changed

+156
-162
lines changed

Modules/_ctypes/_ctypes.c

+153-157
Original file line numberDiff line numberDiff line change
@@ -125,9 +125,13 @@ PyObject *_ctypes_ptrtype_cache = NULL;
125125

126126
static PyTypeObject Simple_Type;
127127

128-
/* a callable object used for unpickling */
128+
/* a callable object used for unpickling:
129+
strong reference to _ctypes._unpickle() function */
129130
static PyObject *_unpickle;
130131

132+
#ifdef MS_WIN32
133+
PyObject *ComError; // Borrowed reference to: &PyComError_Type
134+
#endif
131135

132136

133137
/****************************************************************/
@@ -4307,7 +4311,7 @@ static PyNumberMethods PyCFuncPtr_as_number = {
43074311

43084312
PyTypeObject PyCFuncPtr_Type = {
43094313
PyVarObject_HEAD_INIT(NULL, 0)
4310-
"_ctypes.PyCFuncPtr",
4314+
"_ctypes.CFuncPtr",
43114315
sizeof(PyCFuncPtrObject), /* tp_basicsize */
43124316
0, /* tp_itemsize */
43134317
(destructor)PyCFuncPtr_dealloc, /* tp_dealloc */
@@ -5555,20 +5559,7 @@ static PyTypeObject PyComError_Type = {
55555559
0, /* tp_alloc */
55565560
0, /* tp_new */
55575561
};
5558-
5559-
5560-
static int
5561-
create_comerror(void)
5562-
{
5563-
PyComError_Type.tp_base = (PyTypeObject*)PyExc_Exception;
5564-
if (PyType_Ready(&PyComError_Type) < 0)
5565-
return -1;
5566-
Py_INCREF(&PyComError_Type);
5567-
ComError = (PyObject*)&PyComError_Type;
5568-
return 0;
5569-
}
5570-
5571-
#endif
5562+
#endif // MS_WIN32
55725563

55735564
static PyObject *
55745565
string_at(const char *ptr, int size)
@@ -5679,194 +5670,199 @@ wstring_at(const wchar_t *ptr, int size)
56795670

56805671
static struct PyModuleDef _ctypesmodule = {
56815672
PyModuleDef_HEAD_INIT,
5682-
"_ctypes",
5683-
module_docs,
5684-
-1,
5685-
_ctypes_module_methods,
5686-
NULL,
5687-
NULL,
5688-
NULL,
5689-
NULL
5673+
.m_name = "_ctypes",
5674+
.m_doc = module_docs,
5675+
.m_size = -1,
5676+
.m_methods = _ctypes_module_methods,
56905677
};
56915678

5692-
PyMODINIT_FUNC
5693-
PyInit__ctypes(void)
5694-
{
5695-
PyObject *m;
5696-
5697-
/* Note:
5698-
ob_type is the metatype (the 'type'), defaults to PyType_Type,
5699-
tp_base is the base type, defaults to 'object' aka PyBaseObject_Type.
5700-
*/
5701-
m = PyModule_Create(&_ctypesmodule);
5702-
if (!m)
5703-
return NULL;
5704-
5705-
_ctypes_ptrtype_cache = PyDict_New();
5706-
if (_ctypes_ptrtype_cache == NULL)
5707-
return NULL;
5708-
5709-
PyModule_AddObject(m, "_pointer_type_cache", (PyObject *)_ctypes_ptrtype_cache);
5710-
5711-
_unpickle = PyObject_GetAttrString(m, "_unpickle");
5712-
if (_unpickle == NULL)
5713-
return NULL;
5714-
5715-
if (PyType_Ready(&PyCArg_Type) < 0)
5716-
return NULL;
5717-
5718-
if (PyType_Ready(&PyCThunk_Type) < 0)
5719-
return NULL;
57205679

5680+
static int
5681+
_ctypes_add_types(PyObject *mod)
5682+
{
5683+
#define TYPE_READY(TYPE) \
5684+
if (PyType_Ready(TYPE) < 0) { \
5685+
return -1; \
5686+
}
5687+
5688+
#define TYPE_READY_BASE(TYPE_EXPR, TP_BASE) \
5689+
do { \
5690+
PyTypeObject *type = (TYPE_EXPR); \
5691+
type->tp_base = (TP_BASE); \
5692+
TYPE_READY(type); \
5693+
} while (0)
5694+
5695+
#define MOD_ADD_TYPE(TYPE_EXPR, TP_TYPE, TP_BASE) \
5696+
do { \
5697+
PyTypeObject *type = (TYPE_EXPR); \
5698+
Py_SET_TYPE(type, TP_TYPE); \
5699+
type->tp_base = TP_BASE; \
5700+
if (PyModule_AddType(mod, type) < 0) { \
5701+
return -1; \
5702+
} \
5703+
} while (0)
5704+
5705+
/* Note:
5706+
ob_type is the metatype (the 'type'), defaults to PyType_Type,
5707+
tp_base is the base type, defaults to 'object' aka PyBaseObject_Type.
5708+
*/
5709+
TYPE_READY(&PyCArg_Type);
5710+
TYPE_READY(&PyCThunk_Type);
5711+
TYPE_READY(&PyCData_Type);
57215712
/* StgDict is derived from PyDict_Type */
5722-
PyCStgDict_Type.tp_base = &PyDict_Type;
5723-
if (PyType_Ready(&PyCStgDict_Type) < 0)
5724-
return NULL;
5713+
TYPE_READY_BASE(&PyCStgDict_Type, &PyDict_Type);
57255714

57265715
/*************************************************
57275716
*
57285717
* Metaclasses
57295718
*/
5730-
5731-
PyCStructType_Type.tp_base = &PyType_Type;
5732-
if (PyType_Ready(&PyCStructType_Type) < 0)
5733-
return NULL;
5734-
5735-
UnionType_Type.tp_base = &PyType_Type;
5736-
if (PyType_Ready(&UnionType_Type) < 0)
5737-
return NULL;
5738-
5739-
PyCPointerType_Type.tp_base = &PyType_Type;
5740-
if (PyType_Ready(&PyCPointerType_Type) < 0)
5741-
return NULL;
5742-
5743-
PyCArrayType_Type.tp_base = &PyType_Type;
5744-
if (PyType_Ready(&PyCArrayType_Type) < 0)
5745-
return NULL;
5746-
5747-
PyCSimpleType_Type.tp_base = &PyType_Type;
5748-
if (PyType_Ready(&PyCSimpleType_Type) < 0)
5749-
return NULL;
5750-
5751-
PyCFuncPtrType_Type.tp_base = &PyType_Type;
5752-
if (PyType_Ready(&PyCFuncPtrType_Type) < 0)
5753-
return NULL;
5719+
TYPE_READY_BASE(&PyCStructType_Type, &PyType_Type);
5720+
TYPE_READY_BASE(&UnionType_Type, &PyType_Type);
5721+
TYPE_READY_BASE(&PyCPointerType_Type, &PyType_Type);
5722+
TYPE_READY_BASE(&PyCArrayType_Type, &PyType_Type);
5723+
TYPE_READY_BASE(&PyCSimpleType_Type, &PyType_Type);
5724+
TYPE_READY_BASE(&PyCFuncPtrType_Type, &PyType_Type);
57545725

57555726
/*************************************************
57565727
*
57575728
* Classes using a custom metaclass
57585729
*/
57595730

5760-
if (PyType_Ready(&PyCData_Type) < 0)
5761-
return NULL;
5762-
5763-
Py_SET_TYPE(&Struct_Type, &PyCStructType_Type);
5764-
Struct_Type.tp_base = &PyCData_Type;
5765-
if (PyType_Ready(&Struct_Type) < 0)
5766-
return NULL;
5767-
Py_INCREF(&Struct_Type);
5768-
PyModule_AddObject(m, "Structure", (PyObject *)&Struct_Type);
5769-
5770-
Py_SET_TYPE(&Union_Type, &UnionType_Type);
5771-
Union_Type.tp_base = &PyCData_Type;
5772-
if (PyType_Ready(&Union_Type) < 0)
5773-
return NULL;
5774-
Py_INCREF(&Union_Type);
5775-
PyModule_AddObject(m, "Union", (PyObject *)&Union_Type);
5776-
5777-
Py_SET_TYPE(&PyCPointer_Type, &PyCPointerType_Type);
5778-
PyCPointer_Type.tp_base = &PyCData_Type;
5779-
if (PyType_Ready(&PyCPointer_Type) < 0)
5780-
return NULL;
5781-
Py_INCREF(&PyCPointer_Type);
5782-
PyModule_AddObject(m, "_Pointer", (PyObject *)&PyCPointer_Type);
5783-
5784-
Py_SET_TYPE(&PyCArray_Type, &PyCArrayType_Type);
5785-
PyCArray_Type.tp_base = &PyCData_Type;
5786-
if (PyType_Ready(&PyCArray_Type) < 0)
5787-
return NULL;
5788-
Py_INCREF(&PyCArray_Type);
5789-
PyModule_AddObject(m, "Array", (PyObject *)&PyCArray_Type);
5790-
5791-
Py_SET_TYPE(&Simple_Type, &PyCSimpleType_Type);
5792-
Simple_Type.tp_base = &PyCData_Type;
5793-
if (PyType_Ready(&Simple_Type) < 0)
5794-
return NULL;
5795-
Py_INCREF(&Simple_Type);
5796-
PyModule_AddObject(m, "_SimpleCData", (PyObject *)&Simple_Type);
5797-
5798-
Py_SET_TYPE(&PyCFuncPtr_Type, &PyCFuncPtrType_Type);
5799-
PyCFuncPtr_Type.tp_base = &PyCData_Type;
5800-
if (PyType_Ready(&PyCFuncPtr_Type) < 0)
5801-
return NULL;
5802-
Py_INCREF(&PyCFuncPtr_Type);
5803-
PyModule_AddObject(m, "CFuncPtr", (PyObject *)&PyCFuncPtr_Type);
5731+
MOD_ADD_TYPE(&Struct_Type, &PyCStructType_Type, &PyCData_Type);
5732+
MOD_ADD_TYPE(&Union_Type, &UnionType_Type, &PyCData_Type);
5733+
MOD_ADD_TYPE(&PyCPointer_Type, &PyCPointerType_Type, &PyCData_Type);
5734+
MOD_ADD_TYPE(&PyCArray_Type, &PyCArrayType_Type, &PyCData_Type);
5735+
MOD_ADD_TYPE(&Simple_Type, &PyCSimpleType_Type, &PyCData_Type);
5736+
MOD_ADD_TYPE(&PyCFuncPtr_Type, &PyCFuncPtrType_Type, &PyCData_Type);
58045737

58055738
/*************************************************
58065739
*
58075740
* Simple classes
58085741
*/
58095742

58105743
/* PyCField_Type is derived from PyBaseObject_Type */
5811-
if (PyType_Ready(&PyCField_Type) < 0)
5812-
return NULL;
5744+
TYPE_READY(&PyCField_Type);
58135745

58145746
/*************************************************
58155747
*
58165748
* Other stuff
58175749
*/
58185750

58195751
DictRemover_Type.tp_new = PyType_GenericNew;
5820-
if (PyType_Ready(&DictRemover_Type) < 0)
5821-
return NULL;
5822-
5823-
if (PyType_Ready(&StructParam_Type) < 0) {
5824-
return NULL;
5825-
}
5752+
TYPE_READY(&DictRemover_Type);
5753+
TYPE_READY(&StructParam_Type);
58265754

58275755
#ifdef MS_WIN32
5828-
if (create_comerror() < 0)
5829-
return NULL;
5830-
PyModule_AddObject(m, "COMError", ComError);
5756+
TYPE_READY_BASE(&PyComError_Type, PyExc_Exception);
5757+
#endif
58315758

5832-
PyModule_AddObject(m, "FUNCFLAG_HRESULT", PyLong_FromLong(FUNCFLAG_HRESULT));
5833-
PyModule_AddObject(m, "FUNCFLAG_STDCALL", PyLong_FromLong(FUNCFLAG_STDCALL));
5759+
#undef TYPE_READY
5760+
#undef TYPE_READY_BASE
5761+
#undef MOD_ADD_TYPE
5762+
return 0;
5763+
}
5764+
5765+
5766+
static int
5767+
_ctypes_add_objects(PyObject *mod)
5768+
{
5769+
#define MOD_ADD(name, expr) \
5770+
do { \
5771+
PyObject *obj = (expr); \
5772+
if (obj == NULL) { \
5773+
return -1; \
5774+
} \
5775+
if (PyModule_AddObjectRef(mod, name, obj) < 0) { \
5776+
Py_DECREF(obj); \
5777+
return -1; \
5778+
} \
5779+
Py_DECREF(obj); \
5780+
} while (0)
5781+
5782+
MOD_ADD("_pointer_type_cache", Py_NewRef(_ctypes_ptrtype_cache));
5783+
5784+
#ifdef MS_WIN32
5785+
MOD_ADD("COMError", Py_NewRef(ComError));
5786+
MOD_ADD("FUNCFLAG_HRESULT", PyLong_FromLong(FUNCFLAG_HRESULT));
5787+
MOD_ADD("FUNCFLAG_STDCALL", PyLong_FromLong(FUNCFLAG_STDCALL));
58345788
#endif
5835-
PyModule_AddObject(m, "FUNCFLAG_CDECL", PyLong_FromLong(FUNCFLAG_CDECL));
5836-
PyModule_AddObject(m, "FUNCFLAG_USE_ERRNO", PyLong_FromLong(FUNCFLAG_USE_ERRNO));
5837-
PyModule_AddObject(m, "FUNCFLAG_USE_LASTERROR", PyLong_FromLong(FUNCFLAG_USE_LASTERROR));
5838-
PyModule_AddObject(m, "FUNCFLAG_PYTHONAPI", PyLong_FromLong(FUNCFLAG_PYTHONAPI));
5839-
PyModule_AddStringConstant(m, "__version__", "1.1.0");
5840-
5841-
PyModule_AddObject(m, "_memmove_addr", PyLong_FromVoidPtr(memmove));
5842-
PyModule_AddObject(m, "_memset_addr", PyLong_FromVoidPtr(memset));
5843-
PyModule_AddObject(m, "_string_at_addr", PyLong_FromVoidPtr(string_at));
5844-
PyModule_AddObject(m, "_cast_addr", PyLong_FromVoidPtr(cast));
5789+
MOD_ADD("FUNCFLAG_CDECL", PyLong_FromLong(FUNCFLAG_CDECL));
5790+
MOD_ADD("FUNCFLAG_USE_ERRNO", PyLong_FromLong(FUNCFLAG_USE_ERRNO));
5791+
MOD_ADD("FUNCFLAG_USE_LASTERROR", PyLong_FromLong(FUNCFLAG_USE_LASTERROR));
5792+
MOD_ADD("FUNCFLAG_PYTHONAPI", PyLong_FromLong(FUNCFLAG_PYTHONAPI));
5793+
MOD_ADD("__version__", PyUnicode_FromString("1.1.0"));
5794+
5795+
MOD_ADD("_memmove_addr", PyLong_FromVoidPtr(memmove));
5796+
MOD_ADD("_memset_addr", PyLong_FromVoidPtr(memset));
5797+
MOD_ADD("_string_at_addr", PyLong_FromVoidPtr(string_at));
5798+
MOD_ADD("_cast_addr", PyLong_FromVoidPtr(cast));
58455799
#ifdef CTYPES_UNICODE
5846-
PyModule_AddObject(m, "_wstring_at_addr", PyLong_FromVoidPtr(wstring_at));
5800+
MOD_ADD("_wstring_at_addr", PyLong_FromVoidPtr(wstring_at));
58475801
#endif
58485802

58495803
/* If RTLD_LOCAL is not defined (Windows!), set it to zero. */
58505804
#if !HAVE_DECL_RTLD_LOCAL
5851-
#define RTLD_LOCAL 0
5805+
# define RTLD_LOCAL 0
58525806
#endif
58535807

58545808
/* If RTLD_GLOBAL is not defined (cygwin), set it to the same value as
5855-
RTLD_LOCAL.
5856-
*/
5809+
RTLD_LOCAL. */
58575810
#if !HAVE_DECL_RTLD_GLOBAL
5858-
#define RTLD_GLOBAL RTLD_LOCAL
5811+
# define RTLD_GLOBAL RTLD_LOCAL
58595812
#endif
5813+
MOD_ADD("RTLD_LOCAL", PyLong_FromLong(RTLD_LOCAL));
5814+
MOD_ADD("RTLD_GLOBAL", PyLong_FromLong(RTLD_GLOBAL));
5815+
MOD_ADD("ArgumentError", Py_NewRef(PyExc_ArgError));
5816+
return 0;
5817+
#undef MOD_ADD
5818+
}
5819+
5820+
5821+
static int
5822+
_ctypes_mod_exec(PyObject *mod)
5823+
{
5824+
_unpickle = PyObject_GetAttrString(mod, "_unpickle");
5825+
if (_unpickle == NULL) {
5826+
return -1;
5827+
}
58605828

5861-
PyModule_AddObject(m, "RTLD_LOCAL", PyLong_FromLong(RTLD_LOCAL));
5862-
PyModule_AddObject(m, "RTLD_GLOBAL", PyLong_FromLong(RTLD_GLOBAL));
5829+
_ctypes_ptrtype_cache = PyDict_New();
5830+
if (_ctypes_ptrtype_cache == NULL) {
5831+
return -1;
5832+
}
58635833

58645834
PyExc_ArgError = PyErr_NewException("ctypes.ArgumentError", NULL, NULL);
5865-
if (PyExc_ArgError) {
5866-
Py_INCREF(PyExc_ArgError);
5867-
PyModule_AddObject(m, "ArgumentError", PyExc_ArgError);
5835+
if (!PyExc_ArgError) {
5836+
return -1;
5837+
}
5838+
5839+
if (_ctypes_add_types(mod) < 0) {
5840+
return -1;
5841+
}
5842+
#ifdef MS_WIN32
5843+
ComError = (PyObject*)&PyComError_Type;
5844+
#endif
5845+
5846+
if (_ctypes_add_objects(mod) < 0) {
5847+
return -1;
5848+
}
5849+
return 0;
5850+
}
5851+
5852+
5853+
PyMODINIT_FUNC
5854+
PyInit__ctypes(void)
5855+
{
5856+
PyObject *mod = PyModule_Create(&_ctypesmodule);
5857+
if (!mod) {
5858+
return NULL;
5859+
}
5860+
5861+
if (_ctypes_mod_exec(mod) < 0) {
5862+
Py_DECREF(mod);
5863+
return NULL;
58685864
}
5869-
return m;
5865+
return mod;
58705866
}
58715867

58725868
/*

0 commit comments

Comments
 (0)