diff options
author | Armin Rigo <arigo@tunes.org> | 2007-05-02 19:23:31 (GMT) |
---|---|---|
committer | Armin Rigo <arigo@tunes.org> | 2007-05-02 19:23:31 (GMT) |
commit | 9790a2706573359e02fcfc5f18f9907467f4ec49 (patch) | |
tree | d953c06fbbb8325b8ed86e707ed17f0b43b870dd /Objects | |
parent | d83eb316dce49606041304afb6b68e85fb1794af (diff) | |
download | cpython-9790a2706573359e02fcfc5f18f9907467f4ec49.zip cpython-9790a2706573359e02fcfc5f18f9907467f4ec49.tar.gz cpython-9790a2706573359e02fcfc5f18f9907467f4ec49.tar.bz2 |
Fix for #1303614 and #1174712:
- __dict__ descriptor abuse for subclasses of built-in types
- subclassing from both ModuleType and another built-in types
Thanks zseil for the patch.
Diffstat (limited to 'Objects')
-rw-r--r-- | Objects/typeobject.c | 89 |
1 files changed, 85 insertions, 4 deletions
diff --git a/Objects/typeobject.c b/Objects/typeobject.c index 89d2d4f..7735851 100644 --- a/Objects/typeobject.c +++ b/Objects/typeobject.c @@ -1423,10 +1423,12 @@ extra_ivars(PyTypeObject *type, PyTypeObject *base) type->tp_itemsize != base->tp_itemsize; } if (type->tp_weaklistoffset && base->tp_weaklistoffset == 0 && - type->tp_weaklistoffset + sizeof(PyObject *) == t_size) + type->tp_weaklistoffset + sizeof(PyObject *) == t_size && + type->tp_flags & Py_TPFLAGS_HEAPTYPE) t_size -= sizeof(PyObject *); if (type->tp_dictoffset && base->tp_dictoffset == 0 && - type->tp_dictoffset + sizeof(PyObject *) == t_size) + type->tp_dictoffset + sizeof(PyObject *) == t_size && + type->tp_flags & Py_TPFLAGS_HEAPTYPE) t_size -= sizeof(PyObject *); return t_size != b_size; @@ -1452,12 +1454,73 @@ static int object_init(PyObject *, PyObject *, PyObject *); static int update_slot(PyTypeObject *, PyObject *); static void fixup_slot_dispatchers(PyTypeObject *); +/* + * Helpers for __dict__ descriptor. We don't want to expose the dicts + * inherited from various builtin types. The builtin base usually provides + * its own __dict__ descriptor, so we use that when we can. + */ +static PyTypeObject * +get_builtin_base_with_dict(PyTypeObject *type) +{ + while (type->tp_base != NULL) { + if (type->tp_dictoffset != 0 && + !(type->tp_flags & Py_TPFLAGS_HEAPTYPE)) + return type; + type = type->tp_base; + } + return NULL; +} + +static PyObject * +get_dict_descriptor(PyTypeObject *type) +{ + static PyObject *dict_str; + PyObject *descr; + + if (dict_str == NULL) { + dict_str = PyString_InternFromString("__dict__"); + if (dict_str == NULL) + return NULL; + } + descr = _PyType_Lookup(type, dict_str); + if (descr == NULL || !PyDescr_IsData(descr)) + return NULL; + + return descr; +} + +static void +raise_dict_descr_error(PyObject *obj) +{ + PyErr_Format(PyExc_TypeError, + "this __dict__ descriptor does not support " + "'%.200s' objects", obj->ob_type->tp_name); +} + static PyObject * subtype_dict(PyObject *obj, void *context) { - PyObject **dictptr = _PyObject_GetDictPtr(obj); + PyObject **dictptr; PyObject *dict; + PyTypeObject *base; + + base = get_builtin_base_with_dict(obj->ob_type); + if (base != NULL) { + descrgetfunc func; + PyObject *descr = get_dict_descriptor(base); + if (descr == NULL) { + raise_dict_descr_error(obj); + return NULL; + } + func = descr->ob_type->tp_descr_get; + if (func == NULL) { + raise_dict_descr_error(obj); + return NULL; + } + return func(descr, obj, (PyObject *)(obj->ob_type)); + } + dictptr = _PyObject_GetDictPtr(obj); if (dictptr == NULL) { PyErr_SetString(PyExc_AttributeError, "This object has no __dict__"); @@ -1473,9 +1536,27 @@ subtype_dict(PyObject *obj, void *context) static int subtype_setdict(PyObject *obj, PyObject *value, void *context) { - PyObject **dictptr = _PyObject_GetDictPtr(obj); + PyObject **dictptr; PyObject *dict; + PyTypeObject *base; + + base = get_builtin_base_with_dict(obj->ob_type); + if (base != NULL) { + descrsetfunc func; + PyObject *descr = get_dict_descriptor(base); + if (descr == NULL) { + raise_dict_descr_error(obj); + return -1; + } + func = descr->ob_type->tp_descr_set; + if (func == NULL) { + raise_dict_descr_error(obj); + return -1; + } + return func(descr, obj, value); + } + dictptr = _PyObject_GetDictPtr(obj); if (dictptr == NULL) { PyErr_SetString(PyExc_AttributeError, "This object has no __dict__"); |