summaryrefslogtreecommitdiffstats
path: root/Modules
diff options
context:
space:
mode:
authorVictor Stinner <vstinner@python.org>2020-11-12 13:09:57 (GMT)
committerGitHub <noreply@github.com>2020-11-12 13:09:57 (GMT)
commitd19fa7a337d829e3dab3e9f919f5dcf09cf6f6ba (patch)
tree2a6f34f3b2e8eacb43770e112e500d7cfd612d0e /Modules
parentc6409156c4f0743dfb3d625c4e024a8258fc6181 (diff)
downloadcpython-d19fa7a337d829e3dab3e9f919f5dcf09cf6f6ba.zip
cpython-d19fa7a337d829e3dab3e9f919f5dcf09cf6f6ba.tar.gz
cpython-d19fa7a337d829e3dab3e9f919f5dcf09cf6f6ba.tar.bz2
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.
Diffstat (limited to 'Modules')
-rw-r--r--Modules/_ctypes/_ctypes.c310
-rw-r--r--Modules/_ctypes/callproc.c8
2 files changed, 156 insertions, 162 deletions
diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c
index 8d5594c..2990708 100644
--- a/Modules/_ctypes/_ctypes.c
+++ b/Modules/_ctypes/_ctypes.c
@@ -125,9 +125,13 @@ PyObject *_ctypes_ptrtype_cache = NULL;
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;
+#ifdef MS_WIN32
+PyObject *ComError; // Borrowed reference to: &PyComError_Type
+#endif
/****************************************************************/
@@ -4307,7 +4311,7 @@ static PyNumberMethods PyCFuncPtr_as_number = {
PyTypeObject PyCFuncPtr_Type = {
PyVarObject_HEAD_INIT(NULL, 0)
- "_ctypes.PyCFuncPtr",
+ "_ctypes.CFuncPtr",
sizeof(PyCFuncPtrObject), /* tp_basicsize */
0, /* tp_itemsize */
(destructor)PyCFuncPtr_dealloc, /* tp_dealloc */
@@ -5555,20 +5559,7 @@ static PyTypeObject PyComError_Type = {
0, /* tp_alloc */
0, /* tp_new */
};
-
-
-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
+#endif // MS_WIN32
static PyObject *
string_at(const char *ptr, int size)
@@ -5679,128 +5670,70 @@ wstring_at(const wchar_t *ptr, int size)
static struct PyModuleDef _ctypesmodule = {
PyModuleDef_HEAD_INIT,
- "_ctypes",
- module_docs,
- -1,
- _ctypes_module_methods,
- NULL,
- NULL,
- NULL,
- NULL
+ .m_name = "_ctypes",
+ .m_doc = module_docs,
+ .m_size = -1,
+ .m_methods = _ctypes_module_methods,
};
-PyMODINIT_FUNC
-PyInit__ctypes(void)
-{
- PyObject *m;
-
-/* Note:
- ob_type is the metatype (the 'type'), defaults to PyType_Type,
- tp_base is the base type, defaults to 'object' aka PyBaseObject_Type.
-*/
- m = PyModule_Create(&_ctypesmodule);
- if (!m)
- return NULL;
-
- _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;
+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,
+ tp_base is the base type, defaults to 'object' aka PyBaseObject_Type.
+ */
+ TYPE_READY(&PyCArg_Type);
+ TYPE_READY(&PyCThunk_Type);
+ TYPE_READY(&PyCData_Type);
/* StgDict is derived from PyDict_Type */
- PyCStgDict_Type.tp_base = &PyDict_Type;
- if (PyType_Ready(&PyCStgDict_Type) < 0)
- return NULL;
+ TYPE_READY_BASE(&PyCStgDict_Type, &PyDict_Type);
/*************************************************
*
* Metaclasses
*/
-
- PyCStructType_Type.tp_base = &PyType_Type;
- if (PyType_Ready(&PyCStructType_Type) < 0)
- return NULL;
-
- UnionType_Type.tp_base = &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;
+ TYPE_READY_BASE(&PyCStructType_Type, &PyType_Type);
+ TYPE_READY_BASE(&UnionType_Type, &PyType_Type);
+ TYPE_READY_BASE(&PyCPointerType_Type, &PyType_Type);
+ TYPE_READY_BASE(&PyCArrayType_Type, &PyType_Type);
+ TYPE_READY_BASE(&PyCSimpleType_Type, &PyType_Type);
+ TYPE_READY_BASE(&PyCFuncPtrType_Type, &PyType_Type);
/*************************************************
*
* Classes using a custom metaclass
*/
- if (PyType_Ready(&PyCData_Type) < 0)
- return NULL;
-
- Py_SET_TYPE(&Struct_Type, &PyCStructType_Type);
- Struct_Type.tp_base = &PyCData_Type;
- if (PyType_Ready(&Struct_Type) < 0)
- 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);
+ MOD_ADD_TYPE(&Struct_Type, &PyCStructType_Type, &PyCData_Type);
+ MOD_ADD_TYPE(&Union_Type, &UnionType_Type, &PyCData_Type);
+ MOD_ADD_TYPE(&PyCPointer_Type, &PyCPointerType_Type, &PyCData_Type);
+ MOD_ADD_TYPE(&PyCArray_Type, &PyCArrayType_Type, &PyCData_Type);
+ MOD_ADD_TYPE(&Simple_Type, &PyCSimpleType_Type, &PyCData_Type);
+ MOD_ADD_TYPE(&PyCFuncPtr_Type, &PyCFuncPtrType_Type, &PyCData_Type);
/*************************************************
*
@@ -5808,8 +5741,7 @@ PyInit__ctypes(void)
*/
/* PyCField_Type is derived from PyBaseObject_Type */
- if (PyType_Ready(&PyCField_Type) < 0)
- return NULL;
+ TYPE_READY(&PyCField_Type);
/*************************************************
*
@@ -5817,56 +5749,120 @@ PyInit__ctypes(void)
*/
DictRemover_Type.tp_new = PyType_GenericNew;
- if (PyType_Ready(&DictRemover_Type) < 0)
- return NULL;
-
- if (PyType_Ready(&StructParam_Type) < 0) {
- return NULL;
- }
+ TYPE_READY(&DictRemover_Type);
+ TYPE_READY(&StructParam_Type);
#ifdef MS_WIN32
- if (create_comerror() < 0)
- return NULL;
- PyModule_AddObject(m, "COMError", ComError);
+ TYPE_READY_BASE(&PyComError_Type, PyExc_Exception);
+#endif
- PyModule_AddObject(m, "FUNCFLAG_HRESULT", PyLong_FromLong(FUNCFLAG_HRESULT));
- PyModule_AddObject(m, "FUNCFLAG_STDCALL", PyLong_FromLong(FUNCFLAG_STDCALL));
+#undef TYPE_READY
+#undef TYPE_READY_BASE
+#undef MOD_ADD_TYPE
+ 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
- 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));
- PyModule_AddObject(m, "_memset_addr", PyLong_FromVoidPtr(memset));
- PyModule_AddObject(m, "_string_at_addr", PyLong_FromVoidPtr(string_at));
- PyModule_AddObject(m, "_cast_addr", PyLong_FromVoidPtr(cast));
+ 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
- PyModule_AddObject(m, "_wstring_at_addr", PyLong_FromVoidPtr(wstring_at));
+ MOD_ADD("_wstring_at_addr", PyLong_FromVoidPtr(wstring_at));
#endif
/* If RTLD_LOCAL is not defined (Windows!), set it to zero. */
#if !HAVE_DECL_RTLD_LOCAL
-#define RTLD_LOCAL 0
+# define RTLD_LOCAL 0
#endif
/* If RTLD_GLOBAL is not defined (cygwin), set it to the same value as
- RTLD_LOCAL.
-*/
+ RTLD_LOCAL. */
#if !HAVE_DECL_RTLD_GLOBAL
-#define RTLD_GLOBAL RTLD_LOCAL
+# define RTLD_GLOBAL RTLD_LOCAL
#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
+}
+
+
+static int
+_ctypes_mod_exec(PyObject *mod)
+{
+ _unpickle = PyObject_GetAttrString(mod, "_unpickle");
+ if (_unpickle == NULL) {
+ return -1;
+ }
- PyModule_AddObject(m, "RTLD_LOCAL", PyLong_FromLong(RTLD_LOCAL));
- PyModule_AddObject(m, "RTLD_GLOBAL", PyLong_FromLong(RTLD_GLOBAL));
+ _ctypes_ptrtype_cache = PyDict_New();
+ if (_ctypes_ptrtype_cache == NULL) {
+ return -1;
+ }
PyExc_ArgError = PyErr_NewException("ctypes.ArgumentError", NULL, NULL);
- if (PyExc_ArgError) {
- Py_INCREF(PyExc_ArgError);
- PyModule_AddObject(m, "ArgumentError", PyExc_ArgError);
+ if (!PyExc_ArgError) {
+ return -1;
+ }
+
+ 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 m;
+ return mod;
}
/*
diff --git a/Modules/_ctypes/callproc.c b/Modules/_ctypes/callproc.c
index a52d343..13b2fb0 100644
--- a/Modules/_ctypes/callproc.c
+++ b/Modules/_ctypes/callproc.c
@@ -254,8 +254,6 @@ set_last_error(PyObject *self, PyObject *args)
return set_error_internal(self, args, 1);
}
-PyObject *ComError;
-
static WCHAR *FormatError(DWORD code)
{
WCHAR *lpMsgBuf;
@@ -1471,14 +1469,14 @@ static PyObject *py_dyld_shared_cache_contains_path(PyObject *self, PyObject *ar
if (!PyArg_ParseTuple(args, "O", &name))
return NULL;
-
+
if (name == Py_None)
Py_RETURN_FALSE;
-
+
if (PyUnicode_FSConverter(name, &name2) == 0)
return NULL;
name_str = PyBytes_AS_STRING(name2);
-
+
r = _dyld_shared_cache_contains_path(name_str);
Py_DECREF(name2);