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.
This commit is contained in:
parent
c6409156c4
commit
d19fa7a337
|
@ -125,9 +125,13 @@ PyObject *_ctypes_ptrtype_cache = NULL;
|
||||||
|
|
||||||
static PyTypeObject Simple_Type;
|
static PyTypeObject Simple_Type;
|
||||||
|
|
||||||
/* a callable object used for unpickling */
|
/* a callable object used for unpickling:
|
||||||
|
strong reference to _ctypes._unpickle() function */
|
||||||
static PyObject *_unpickle;
|
static PyObject *_unpickle;
|
||||||
|
|
||||||
|
#ifdef MS_WIN32
|
||||||
|
PyObject *ComError; // Borrowed reference to: &PyComError_Type
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
/****************************************************************/
|
/****************************************************************/
|
||||||
|
@ -4307,7 +4311,7 @@ static PyNumberMethods PyCFuncPtr_as_number = {
|
||||||
|
|
||||||
PyTypeObject PyCFuncPtr_Type = {
|
PyTypeObject PyCFuncPtr_Type = {
|
||||||
PyVarObject_HEAD_INIT(NULL, 0)
|
PyVarObject_HEAD_INIT(NULL, 0)
|
||||||
"_ctypes.PyCFuncPtr",
|
"_ctypes.CFuncPtr",
|
||||||
sizeof(PyCFuncPtrObject), /* tp_basicsize */
|
sizeof(PyCFuncPtrObject), /* tp_basicsize */
|
||||||
0, /* tp_itemsize */
|
0, /* tp_itemsize */
|
||||||
(destructor)PyCFuncPtr_dealloc, /* tp_dealloc */
|
(destructor)PyCFuncPtr_dealloc, /* tp_dealloc */
|
||||||
|
@ -5555,20 +5559,7 @@ static PyTypeObject PyComError_Type = {
|
||||||
0, /* tp_alloc */
|
0, /* tp_alloc */
|
||||||
0, /* tp_new */
|
0, /* tp_new */
|
||||||
};
|
};
|
||||||
|
#endif // MS_WIN32
|
||||||
|
|
||||||
static int
|
|
||||||
create_comerror(void)
|
|
||||||
{
|
|
||||||
PyComError_Type.tp_base = (PyTypeObject*)PyExc_Exception;
|
|
||||||
if (PyType_Ready(&PyComError_Type) < 0)
|
|
||||||
return -1;
|
|
||||||
Py_INCREF(&PyComError_Type);
|
|
||||||
ComError = (PyObject*)&PyComError_Type;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static PyObject *
|
static PyObject *
|
||||||
string_at(const char *ptr, int size)
|
string_at(const char *ptr, int size)
|
||||||
|
@ -5679,128 +5670,70 @@ wstring_at(const wchar_t *ptr, int size)
|
||||||
|
|
||||||
static struct PyModuleDef _ctypesmodule = {
|
static struct PyModuleDef _ctypesmodule = {
|
||||||
PyModuleDef_HEAD_INIT,
|
PyModuleDef_HEAD_INIT,
|
||||||
"_ctypes",
|
.m_name = "_ctypes",
|
||||||
module_docs,
|
.m_doc = module_docs,
|
||||||
-1,
|
.m_size = -1,
|
||||||
_ctypes_module_methods,
|
.m_methods = _ctypes_module_methods,
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
NULL
|
|
||||||
};
|
};
|
||||||
|
|
||||||
PyMODINIT_FUNC
|
|
||||||
PyInit__ctypes(void)
|
|
||||||
{
|
|
||||||
PyObject *m;
|
|
||||||
|
|
||||||
/* Note:
|
static int
|
||||||
|
_ctypes_add_types(PyObject *mod)
|
||||||
|
{
|
||||||
|
#define TYPE_READY(TYPE) \
|
||||||
|
if (PyType_Ready(TYPE) < 0) { \
|
||||||
|
return -1; \
|
||||||
|
}
|
||||||
|
|
||||||
|
#define TYPE_READY_BASE(TYPE_EXPR, TP_BASE) \
|
||||||
|
do { \
|
||||||
|
PyTypeObject *type = (TYPE_EXPR); \
|
||||||
|
type->tp_base = (TP_BASE); \
|
||||||
|
TYPE_READY(type); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
#define MOD_ADD_TYPE(TYPE_EXPR, TP_TYPE, TP_BASE) \
|
||||||
|
do { \
|
||||||
|
PyTypeObject *type = (TYPE_EXPR); \
|
||||||
|
Py_SET_TYPE(type, TP_TYPE); \
|
||||||
|
type->tp_base = TP_BASE; \
|
||||||
|
if (PyModule_AddType(mod, type) < 0) { \
|
||||||
|
return -1; \
|
||||||
|
} \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
/* Note:
|
||||||
ob_type is the metatype (the 'type'), defaults to PyType_Type,
|
ob_type is the metatype (the 'type'), defaults to PyType_Type,
|
||||||
tp_base is the base type, defaults to 'object' aka PyBaseObject_Type.
|
tp_base is the base type, defaults to 'object' aka PyBaseObject_Type.
|
||||||
*/
|
*/
|
||||||
m = PyModule_Create(&_ctypesmodule);
|
TYPE_READY(&PyCArg_Type);
|
||||||
if (!m)
|
TYPE_READY(&PyCThunk_Type);
|
||||||
return NULL;
|
TYPE_READY(&PyCData_Type);
|
||||||
|
|
||||||
_ctypes_ptrtype_cache = PyDict_New();
|
|
||||||
if (_ctypes_ptrtype_cache == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
PyModule_AddObject(m, "_pointer_type_cache", (PyObject *)_ctypes_ptrtype_cache);
|
|
||||||
|
|
||||||
_unpickle = PyObject_GetAttrString(m, "_unpickle");
|
|
||||||
if (_unpickle == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (PyType_Ready(&PyCArg_Type) < 0)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
if (PyType_Ready(&PyCThunk_Type) < 0)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
/* StgDict is derived from PyDict_Type */
|
/* StgDict is derived from PyDict_Type */
|
||||||
PyCStgDict_Type.tp_base = &PyDict_Type;
|
TYPE_READY_BASE(&PyCStgDict_Type, &PyDict_Type);
|
||||||
if (PyType_Ready(&PyCStgDict_Type) < 0)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
/*************************************************
|
/*************************************************
|
||||||
*
|
*
|
||||||
* Metaclasses
|
* Metaclasses
|
||||||
*/
|
*/
|
||||||
|
TYPE_READY_BASE(&PyCStructType_Type, &PyType_Type);
|
||||||
PyCStructType_Type.tp_base = &PyType_Type;
|
TYPE_READY_BASE(&UnionType_Type, &PyType_Type);
|
||||||
if (PyType_Ready(&PyCStructType_Type) < 0)
|
TYPE_READY_BASE(&PyCPointerType_Type, &PyType_Type);
|
||||||
return NULL;
|
TYPE_READY_BASE(&PyCArrayType_Type, &PyType_Type);
|
||||||
|
TYPE_READY_BASE(&PyCSimpleType_Type, &PyType_Type);
|
||||||
UnionType_Type.tp_base = &PyType_Type;
|
TYPE_READY_BASE(&PyCFuncPtrType_Type, &PyType_Type);
|
||||||
if (PyType_Ready(&UnionType_Type) < 0)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
PyCPointerType_Type.tp_base = &PyType_Type;
|
|
||||||
if (PyType_Ready(&PyCPointerType_Type) < 0)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
PyCArrayType_Type.tp_base = &PyType_Type;
|
|
||||||
if (PyType_Ready(&PyCArrayType_Type) < 0)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
PyCSimpleType_Type.tp_base = &PyType_Type;
|
|
||||||
if (PyType_Ready(&PyCSimpleType_Type) < 0)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
PyCFuncPtrType_Type.tp_base = &PyType_Type;
|
|
||||||
if (PyType_Ready(&PyCFuncPtrType_Type) < 0)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
/*************************************************
|
/*************************************************
|
||||||
*
|
*
|
||||||
* Classes using a custom metaclass
|
* Classes using a custom metaclass
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if (PyType_Ready(&PyCData_Type) < 0)
|
MOD_ADD_TYPE(&Struct_Type, &PyCStructType_Type, &PyCData_Type);
|
||||||
return NULL;
|
MOD_ADD_TYPE(&Union_Type, &UnionType_Type, &PyCData_Type);
|
||||||
|
MOD_ADD_TYPE(&PyCPointer_Type, &PyCPointerType_Type, &PyCData_Type);
|
||||||
Py_SET_TYPE(&Struct_Type, &PyCStructType_Type);
|
MOD_ADD_TYPE(&PyCArray_Type, &PyCArrayType_Type, &PyCData_Type);
|
||||||
Struct_Type.tp_base = &PyCData_Type;
|
MOD_ADD_TYPE(&Simple_Type, &PyCSimpleType_Type, &PyCData_Type);
|
||||||
if (PyType_Ready(&Struct_Type) < 0)
|
MOD_ADD_TYPE(&PyCFuncPtr_Type, &PyCFuncPtrType_Type, &PyCData_Type);
|
||||||
return NULL;
|
|
||||||
Py_INCREF(&Struct_Type);
|
|
||||||
PyModule_AddObject(m, "Structure", (PyObject *)&Struct_Type);
|
|
||||||
|
|
||||||
Py_SET_TYPE(&Union_Type, &UnionType_Type);
|
|
||||||
Union_Type.tp_base = &PyCData_Type;
|
|
||||||
if (PyType_Ready(&Union_Type) < 0)
|
|
||||||
return NULL;
|
|
||||||
Py_INCREF(&Union_Type);
|
|
||||||
PyModule_AddObject(m, "Union", (PyObject *)&Union_Type);
|
|
||||||
|
|
||||||
Py_SET_TYPE(&PyCPointer_Type, &PyCPointerType_Type);
|
|
||||||
PyCPointer_Type.tp_base = &PyCData_Type;
|
|
||||||
if (PyType_Ready(&PyCPointer_Type) < 0)
|
|
||||||
return NULL;
|
|
||||||
Py_INCREF(&PyCPointer_Type);
|
|
||||||
PyModule_AddObject(m, "_Pointer", (PyObject *)&PyCPointer_Type);
|
|
||||||
|
|
||||||
Py_SET_TYPE(&PyCArray_Type, &PyCArrayType_Type);
|
|
||||||
PyCArray_Type.tp_base = &PyCData_Type;
|
|
||||||
if (PyType_Ready(&PyCArray_Type) < 0)
|
|
||||||
return NULL;
|
|
||||||
Py_INCREF(&PyCArray_Type);
|
|
||||||
PyModule_AddObject(m, "Array", (PyObject *)&PyCArray_Type);
|
|
||||||
|
|
||||||
Py_SET_TYPE(&Simple_Type, &PyCSimpleType_Type);
|
|
||||||
Simple_Type.tp_base = &PyCData_Type;
|
|
||||||
if (PyType_Ready(&Simple_Type) < 0)
|
|
||||||
return NULL;
|
|
||||||
Py_INCREF(&Simple_Type);
|
|
||||||
PyModule_AddObject(m, "_SimpleCData", (PyObject *)&Simple_Type);
|
|
||||||
|
|
||||||
Py_SET_TYPE(&PyCFuncPtr_Type, &PyCFuncPtrType_Type);
|
|
||||||
PyCFuncPtr_Type.tp_base = &PyCData_Type;
|
|
||||||
if (PyType_Ready(&PyCFuncPtr_Type) < 0)
|
|
||||||
return NULL;
|
|
||||||
Py_INCREF(&PyCFuncPtr_Type);
|
|
||||||
PyModule_AddObject(m, "CFuncPtr", (PyObject *)&PyCFuncPtr_Type);
|
|
||||||
|
|
||||||
/*************************************************
|
/*************************************************
|
||||||
*
|
*
|
||||||
|
@ -5808,8 +5741,7 @@ PyInit__ctypes(void)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* PyCField_Type is derived from PyBaseObject_Type */
|
/* PyCField_Type is derived from PyBaseObject_Type */
|
||||||
if (PyType_Ready(&PyCField_Type) < 0)
|
TYPE_READY(&PyCField_Type);
|
||||||
return NULL;
|
|
||||||
|
|
||||||
/*************************************************
|
/*************************************************
|
||||||
*
|
*
|
||||||
|
@ -5817,56 +5749,120 @@ PyInit__ctypes(void)
|
||||||
*/
|
*/
|
||||||
|
|
||||||
DictRemover_Type.tp_new = PyType_GenericNew;
|
DictRemover_Type.tp_new = PyType_GenericNew;
|
||||||
if (PyType_Ready(&DictRemover_Type) < 0)
|
TYPE_READY(&DictRemover_Type);
|
||||||
return NULL;
|
TYPE_READY(&StructParam_Type);
|
||||||
|
|
||||||
if (PyType_Ready(&StructParam_Type) < 0) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifdef MS_WIN32
|
#ifdef MS_WIN32
|
||||||
if (create_comerror() < 0)
|
TYPE_READY_BASE(&PyComError_Type, PyExc_Exception);
|
||||||
return NULL;
|
|
||||||
PyModule_AddObject(m, "COMError", ComError);
|
|
||||||
|
|
||||||
PyModule_AddObject(m, "FUNCFLAG_HRESULT", PyLong_FromLong(FUNCFLAG_HRESULT));
|
|
||||||
PyModule_AddObject(m, "FUNCFLAG_STDCALL", PyLong_FromLong(FUNCFLAG_STDCALL));
|
|
||||||
#endif
|
#endif
|
||||||
PyModule_AddObject(m, "FUNCFLAG_CDECL", PyLong_FromLong(FUNCFLAG_CDECL));
|
|
||||||
PyModule_AddObject(m, "FUNCFLAG_USE_ERRNO", PyLong_FromLong(FUNCFLAG_USE_ERRNO));
|
|
||||||
PyModule_AddObject(m, "FUNCFLAG_USE_LASTERROR", PyLong_FromLong(FUNCFLAG_USE_LASTERROR));
|
|
||||||
PyModule_AddObject(m, "FUNCFLAG_PYTHONAPI", PyLong_FromLong(FUNCFLAG_PYTHONAPI));
|
|
||||||
PyModule_AddStringConstant(m, "__version__", "1.1.0");
|
|
||||||
|
|
||||||
PyModule_AddObject(m, "_memmove_addr", PyLong_FromVoidPtr(memmove));
|
#undef TYPE_READY
|
||||||
PyModule_AddObject(m, "_memset_addr", PyLong_FromVoidPtr(memset));
|
#undef TYPE_READY_BASE
|
||||||
PyModule_AddObject(m, "_string_at_addr", PyLong_FromVoidPtr(string_at));
|
#undef MOD_ADD_TYPE
|
||||||
PyModule_AddObject(m, "_cast_addr", PyLong_FromVoidPtr(cast));
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static int
|
||||||
|
_ctypes_add_objects(PyObject *mod)
|
||||||
|
{
|
||||||
|
#define MOD_ADD(name, expr) \
|
||||||
|
do { \
|
||||||
|
PyObject *obj = (expr); \
|
||||||
|
if (obj == NULL) { \
|
||||||
|
return -1; \
|
||||||
|
} \
|
||||||
|
if (PyModule_AddObjectRef(mod, name, obj) < 0) { \
|
||||||
|
Py_DECREF(obj); \
|
||||||
|
return -1; \
|
||||||
|
} \
|
||||||
|
Py_DECREF(obj); \
|
||||||
|
} while (0)
|
||||||
|
|
||||||
|
MOD_ADD("_pointer_type_cache", Py_NewRef(_ctypes_ptrtype_cache));
|
||||||
|
|
||||||
|
#ifdef MS_WIN32
|
||||||
|
MOD_ADD("COMError", Py_NewRef(ComError));
|
||||||
|
MOD_ADD("FUNCFLAG_HRESULT", PyLong_FromLong(FUNCFLAG_HRESULT));
|
||||||
|
MOD_ADD("FUNCFLAG_STDCALL", PyLong_FromLong(FUNCFLAG_STDCALL));
|
||||||
|
#endif
|
||||||
|
MOD_ADD("FUNCFLAG_CDECL", PyLong_FromLong(FUNCFLAG_CDECL));
|
||||||
|
MOD_ADD("FUNCFLAG_USE_ERRNO", PyLong_FromLong(FUNCFLAG_USE_ERRNO));
|
||||||
|
MOD_ADD("FUNCFLAG_USE_LASTERROR", PyLong_FromLong(FUNCFLAG_USE_LASTERROR));
|
||||||
|
MOD_ADD("FUNCFLAG_PYTHONAPI", PyLong_FromLong(FUNCFLAG_PYTHONAPI));
|
||||||
|
MOD_ADD("__version__", PyUnicode_FromString("1.1.0"));
|
||||||
|
|
||||||
|
MOD_ADD("_memmove_addr", PyLong_FromVoidPtr(memmove));
|
||||||
|
MOD_ADD("_memset_addr", PyLong_FromVoidPtr(memset));
|
||||||
|
MOD_ADD("_string_at_addr", PyLong_FromVoidPtr(string_at));
|
||||||
|
MOD_ADD("_cast_addr", PyLong_FromVoidPtr(cast));
|
||||||
#ifdef CTYPES_UNICODE
|
#ifdef CTYPES_UNICODE
|
||||||
PyModule_AddObject(m, "_wstring_at_addr", PyLong_FromVoidPtr(wstring_at));
|
MOD_ADD("_wstring_at_addr", PyLong_FromVoidPtr(wstring_at));
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* If RTLD_LOCAL is not defined (Windows!), set it to zero. */
|
/* If RTLD_LOCAL is not defined (Windows!), set it to zero. */
|
||||||
#if !HAVE_DECL_RTLD_LOCAL
|
#if !HAVE_DECL_RTLD_LOCAL
|
||||||
#define RTLD_LOCAL 0
|
# define RTLD_LOCAL 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* If RTLD_GLOBAL is not defined (cygwin), set it to the same value as
|
/* If RTLD_GLOBAL is not defined (cygwin), set it to the same value as
|
||||||
RTLD_LOCAL.
|
RTLD_LOCAL. */
|
||||||
*/
|
|
||||||
#if !HAVE_DECL_RTLD_GLOBAL
|
#if !HAVE_DECL_RTLD_GLOBAL
|
||||||
#define RTLD_GLOBAL RTLD_LOCAL
|
# define RTLD_GLOBAL RTLD_LOCAL
|
||||||
#endif
|
#endif
|
||||||
|
MOD_ADD("RTLD_LOCAL", PyLong_FromLong(RTLD_LOCAL));
|
||||||
|
MOD_ADD("RTLD_GLOBAL", PyLong_FromLong(RTLD_GLOBAL));
|
||||||
|
MOD_ADD("ArgumentError", Py_NewRef(PyExc_ArgError));
|
||||||
|
return 0;
|
||||||
|
#undef MOD_ADD
|
||||||
|
}
|
||||||
|
|
||||||
PyModule_AddObject(m, "RTLD_LOCAL", PyLong_FromLong(RTLD_LOCAL));
|
|
||||||
PyModule_AddObject(m, "RTLD_GLOBAL", PyLong_FromLong(RTLD_GLOBAL));
|
static int
|
||||||
|
_ctypes_mod_exec(PyObject *mod)
|
||||||
|
{
|
||||||
|
_unpickle = PyObject_GetAttrString(mod, "_unpickle");
|
||||||
|
if (_unpickle == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
_ctypes_ptrtype_cache = PyDict_New();
|
||||||
|
if (_ctypes_ptrtype_cache == NULL) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
PyExc_ArgError = PyErr_NewException("ctypes.ArgumentError", NULL, NULL);
|
PyExc_ArgError = PyErr_NewException("ctypes.ArgumentError", NULL, NULL);
|
||||||
if (PyExc_ArgError) {
|
if (!PyExc_ArgError) {
|
||||||
Py_INCREF(PyExc_ArgError);
|
return -1;
|
||||||
PyModule_AddObject(m, "ArgumentError", PyExc_ArgError);
|
|
||||||
}
|
}
|
||||||
return m;
|
|
||||||
|
if (_ctypes_add_types(mod) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
#ifdef MS_WIN32
|
||||||
|
ComError = (PyObject*)&PyComError_Type;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
if (_ctypes_add_objects(mod) < 0) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
PyMODINIT_FUNC
|
||||||
|
PyInit__ctypes(void)
|
||||||
|
{
|
||||||
|
PyObject *mod = PyModule_Create(&_ctypesmodule);
|
||||||
|
if (!mod) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_ctypes_mod_exec(mod) < 0) {
|
||||||
|
Py_DECREF(mod);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
return mod;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -254,8 +254,6 @@ set_last_error(PyObject *self, PyObject *args)
|
||||||
return set_error_internal(self, args, 1);
|
return set_error_internal(self, args, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
PyObject *ComError;
|
|
||||||
|
|
||||||
static WCHAR *FormatError(DWORD code)
|
static WCHAR *FormatError(DWORD code)
|
||||||
{
|
{
|
||||||
WCHAR *lpMsgBuf;
|
WCHAR *lpMsgBuf;
|
||||||
|
|
Loading…
Reference in New Issue