diff --git a/Lib/test/test_ctypes/test_simplesubclasses.py b/Lib/test/test_ctypes/test_simplesubclasses.py index c96798e67f23f7..0c13d708d0bc8b 100644 --- a/Lib/test/test_ctypes/test_simplesubclasses.py +++ b/Lib/test/test_ctypes/test_simplesubclasses.py @@ -26,6 +26,12 @@ def test_type_flags(self): self.assertTrue(_SimpleCData.__flags__ & Py_TPFLAGS_IMMUTABLETYPE) self.assertFalse(_SimpleCData.__flags__ & Py_TPFLAGS_DISALLOW_INSTANTIATION) + def test_swapped_type_creation(self): + cls = PyCSimpleType.__new__(PyCSimpleType, '', (), {'_type_': 'i'}) + PyCSimpleType.__init__(cls) + self.assertEqual(cls.__ctype_le__.__dict__.get('_type_'), 'i') + self.assertEqual(cls.__ctype_be__.__dict__.get('_type_'), 'i') + def test_compare(self): self.assertEqual(MyInt(3), MyInt(3)) self.assertNotEqual(MyInt(42), MyInt(43)) diff --git a/Modules/_ctypes/_ctypes.c b/Modules/_ctypes/_ctypes.c index 94245ae41afffc..0433b70b12e53c 100644 --- a/Modules/_ctypes/_ctypes.c +++ b/Modules/_ctypes/_ctypes.c @@ -1847,6 +1847,42 @@ static PyMethodDef c_void_p_method = { "from_param", c_void_p_from_param, METH_O static PyMethodDef c_char_p_method = { "from_param", c_char_p_from_param, METH_O }; static PyMethodDef c_wchar_p_method = { "from_param", c_wchar_p_from_param, METH_O }; +// Complete arguments passed to PyCSimpleType_init() and CreateSwappedType() +static PyObject * +CreateSwappedType_ready(PyObject *self, PyObject *args) +{ + PyObject *dict; + if (!PyTuple_CheckExact(args) || PyTuple_GET_SIZE(args) < 3) { + dict = PyDict_New(); + } + else { + dict = PyDict_Copy(PyTuple_GET_ITEM(args, 2)); + } + if (!dict) { + return NULL; + } + if (PyDict_Update(dict, ((PyTypeObject *)self)->tp_dict) < 0) { + Py_DECREF(dict); + return NULL; + } + if (PyDict_DelItem(dict, &_Py_ID(__dict__))) { + PyErr_Clear(); + } + if (PyDict_DelItem(dict, &_Py_ID(__weakref__))) { + PyErr_Clear(); + } + + PyObject *safe_args = PyTuple_New(3); + if (!safe_args) { + Py_DECREF(dict); + return NULL; + } + PyTuple_SET_ITEM(safe_args, 0, PyType_GetName((PyTypeObject *)self)); + PyTuple_SET_ITEM(safe_args, 1, Py_NewRef(((PyTypeObject *)self)->tp_bases)); + PyTuple_SET_ITEM(safe_args, 2, dict); + return safe_args; +} + static PyObject *CreateSwappedType(PyTypeObject *type, PyObject *args, PyObject *kwds, PyObject *proto, struct fielddesc *fmt) { @@ -1948,10 +1984,9 @@ PyCSimpleType_paramfunc(CDataObject *self) return parg; } -static PyObject * -PyCSimpleType_new(PyTypeObject *type, PyObject *args, PyObject *kwds) +static int +PyCSimpleType_init(PyObject *self, PyObject *args, PyObject *kwds) { - PyTypeObject *result; StgDictObject *stgdict; PyObject *proto; const char *proto_str; @@ -1959,22 +1994,15 @@ PyCSimpleType_new(PyTypeObject *type, PyObject *args, PyObject *kwds) PyMethodDef *ml; struct fielddesc *fmt; - /* create the new instance (which is a class, - since we are a metatype!) */ - result = (PyTypeObject *)PyType_Type.tp_new(type, args, kwds); - if (result == NULL) - return NULL; - - if (PyObject_GetOptionalAttr((PyObject *)result, &_Py_ID(_type_), &proto) < 0) { - return NULL; + if (PyObject_GetOptionalAttr(self, &_Py_ID(_type_), &proto) < 0) { + return -1; } if (!proto) { PyErr_SetString(PyExc_AttributeError, "class must define a '_type_' attribute"); error: Py_XDECREF(proto); - Py_DECREF(result); - return NULL; + return -1; } if (PyUnicode_Check(proto)) { proto_str = PyUnicode_AsUTF8AndSize(proto, &proto_len); @@ -2023,15 +2051,14 @@ PyCSimpleType_new(PyTypeObject *type, PyObject *args, PyObject *kwds) stgdict->format = _ctypes_alloc_format_string_for_type(proto_str[0], 0); #endif if (stgdict->format == NULL) { - Py_DECREF(result); Py_DECREF(proto); Py_DECREF((PyObject *)stgdict); - return NULL; + return -1; } stgdict->paramfunc = PyCSimpleType_paramfunc; /* - if (result->tp_base != st->Simple_Type) { + if (self->tp_base != st->Simple_Type) { stgdict->setfunc = NULL; stgdict->getfunc = NULL; } @@ -2041,17 +2068,16 @@ PyCSimpleType_new(PyTypeObject *type, PyObject *args, PyObject *kwds) stgdict->proto = proto; /* replace the class dict by our updated spam dict */ - if (-1 == PyDict_Update((PyObject *)stgdict, result->tp_dict)) { - Py_DECREF(result); + if (-1 == PyDict_Update((PyObject *)stgdict, ((PyTypeObject *)self)->tp_dict)) { Py_DECREF((PyObject *)stgdict); - return NULL; + return -1; } - Py_SETREF(result->tp_dict, (PyObject *)stgdict); + Py_SETREF(((PyTypeObject *)self)->tp_dict, (PyObject *)stgdict); /* Install from_param class methods in ctypes base classes. Overrides the PyCSimpleType_from_param generic method. */ - if (result->tp_base == st->Simple_Type) { + if (((PyTypeObject *)self)->tp_base == st->Simple_Type) { switch (*proto_str) { case 'z': /* c_char_p */ ml = &c_char_p_method; @@ -2079,57 +2105,59 @@ PyCSimpleType_new(PyTypeObject *type, PyObject *args, PyObject *kwds) if (ml) { PyObject *meth; int x; - meth = PyDescr_NewClassMethod(result, ml); + meth = PyDescr_NewClassMethod((PyTypeObject*)self, ml); if (!meth) { - Py_DECREF(result); - return NULL; + return -1; } - x = PyDict_SetItemString(result->tp_dict, + x = PyDict_SetItemString(((PyTypeObject*)self)->tp_dict, ml->ml_name, meth); Py_DECREF(meth); if (x == -1) { - Py_DECREF(result); - return NULL; + return -1; } } } + PyTypeObject *type = Py_TYPE(self); if (type == st->PyCSimpleType_Type && fmt->setfunc_swapped && fmt->getfunc_swapped) { - PyObject *swapped = CreateSwappedType(type, args, kwds, + PyObject *safe_args = CreateSwappedType_ready(self, args); + if (!safe_args) { + return -1; + } + PyObject *swapped = CreateSwappedType(type, safe_args, kwds, proto, fmt); + Py_DECREF(safe_args); StgDictObject *sw_dict; if (swapped == NULL) { - Py_DECREF(result); - return NULL; + return -1; } sw_dict = PyType_stgdict(swapped); #ifdef WORDS_BIGENDIAN - PyObject_SetAttrString((PyObject *)result, "__ctype_le__", swapped); - PyObject_SetAttrString((PyObject *)result, "__ctype_be__", (PyObject *)result); - PyObject_SetAttrString(swapped, "__ctype_be__", (PyObject *)result); + PyObject_SetAttrString(self, "__ctype_le__", swapped); + PyObject_SetAttrString(self, "__ctype_be__", self); + PyObject_SetAttrString(swapped, "__ctype_be__", self); PyObject_SetAttrString(swapped, "__ctype_le__", swapped); /* We are creating the type for the OTHER endian */ sw_dict->format = _ctypes_alloc_format_string("<", stgdict->format+1); #else - PyObject_SetAttrString((PyObject *)result, "__ctype_be__", swapped); - PyObject_SetAttrString((PyObject *)result, "__ctype_le__", (PyObject *)result); - PyObject_SetAttrString(swapped, "__ctype_le__", (PyObject *)result); + PyObject_SetAttrString(self, "__ctype_be__", swapped); + PyObject_SetAttrString(self, "__ctype_le__", self); + PyObject_SetAttrString(swapped, "__ctype_le__", self); PyObject_SetAttrString(swapped, "__ctype_be__", swapped); /* We are creating the type for the OTHER endian */ sw_dict->format = _ctypes_alloc_format_string(">", stgdict->format+1); #endif Py_DECREF(swapped); if (PyErr_Occurred()) { - Py_DECREF(result); - return NULL; + return -1; } }; - return (PyObject *)result; + return 0; } /* @@ -2218,7 +2246,7 @@ static PyMethodDef PyCSimpleType_methods[] = { static PyType_Slot pycsimple_type_slots[] = { {Py_tp_doc, PyDoc_STR("metatype for the PyCSimpleType Objects")}, {Py_tp_methods, PyCSimpleType_methods}, - {Py_tp_new, PyCSimpleType_new}, + {Py_tp_init, PyCSimpleType_init}, {Py_tp_traverse, CDataType_traverse}, {Py_tp_clear, CDataType_clear},