summaryrefslogtreecommitdiffstats
path: root/Objects
diff options
context:
space:
mode:
authorArmin Rigo <arigo@tunes.org>2007-05-02 19:23:31 (GMT)
committerArmin Rigo <arigo@tunes.org>2007-05-02 19:23:31 (GMT)
commit9790a2706573359e02fcfc5f18f9907467f4ec49 (patch)
treed953c06fbbb8325b8ed86e707ed17f0b43b870dd /Objects
parentd83eb316dce49606041304afb6b68e85fb1794af (diff)
downloadcpython-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.c89
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__");