summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>2003-04-14 21:46:03 (GMT)
committerGuido van Rossum <guido@python.org>2003-04-14 21:46:03 (GMT)
commit4dcdb78c6ffd203c9d72ef41638cc4a0e3857adf (patch)
tree8004c2c85681d2379d1a0c8d319e4506517666bb
parent2fd02eb80fdfd7b651d3df7e09a0b076e126cc03 (diff)
downloadcpython-4dcdb78c6ffd203c9d72ef41638cc4a0e3857adf.zip
cpython-4dcdb78c6ffd203c9d72ef41638cc4a0e3857adf.tar.gz
cpython-4dcdb78c6ffd203c9d72ef41638cc4a0e3857adf.tar.bz2
Close off the "Verre Carlo hack" as discussed on python-dev.
-rw-r--r--Lib/test/test_descr.py17
-rw-r--r--Objects/typeobject.c22
2 files changed, 39 insertions, 0 deletions
diff --git a/Lib/test/test_descr.py b/Lib/test/test_descr.py
index 507938e..37d8b65 100644
--- a/Lib/test/test_descr.py
+++ b/Lib/test/test_descr.py
@@ -3840,6 +3840,22 @@ def proxysuper():
p = Proxy(obj)
vereq(C.__dict__["f"](p), "B.f->C.f")
+def verrecarlo():
+ if verbose:
+ print "Testing prohibition of Verre Carlo's hack..."
+ try:
+ object.__setattr__(str, "foo", 42)
+ except TypeError:
+ pass
+ else:
+ raise TestFailed, "Verre Carlo __setattr__ suceeded!"
+ try:
+ object.__delattr__(str, "lower")
+ except TypeError:
+ pass
+ else:
+ raise TestFailed, "Verre Carlo __delattr__ succeeded!"
+
def test_main():
do_this_first()
@@ -3929,6 +3945,7 @@ def test_main():
meth_class_get()
isinst_isclass()
proxysuper()
+ verrecarlo()
if verbose: print "All OK"
diff --git a/Objects/typeobject.c b/Objects/typeobject.c
index a900f55..91c40b9 100644
--- a/Objects/typeobject.c
+++ b/Objects/typeobject.c
@@ -3574,6 +3574,24 @@ wrap_cmpfunc(PyObject *self, PyObject *args, void *wrapped)
return PyInt_FromLong((long)res);
}
+/* Helper to check for object.__setattr__ or __delattr__ applied to a type.
+ This is called the Verre Carlo hack after its discoverer. */
+static int
+hackcheck(PyObject *self, setattrofunc func, char *what)
+{
+ PyTypeObject *type = self->ob_type;
+ while (type && type->tp_flags & Py_TPFLAGS_HEAPTYPE)
+ type = type->tp_base;
+ if (type->tp_setattro != func) {
+ PyErr_Format(PyExc_TypeError,
+ "can't apply this %s to %s object",
+ what,
+ type->tp_name);
+ return 0;
+ }
+ return 1;
+}
+
static PyObject *
wrap_setattr(PyObject *self, PyObject *args, void *wrapped)
{
@@ -3583,6 +3601,8 @@ wrap_setattr(PyObject *self, PyObject *args, void *wrapped)
if (!PyArg_ParseTuple(args, "OO", &name, &value))
return NULL;
+ if (!hackcheck(self, func, "__setattr__"))
+ return NULL;
res = (*func)(self, name, value);
if (res < 0)
return NULL;
@@ -3599,6 +3619,8 @@ wrap_delattr(PyObject *self, PyObject *args, void *wrapped)
if (!PyArg_ParseTuple(args, "O", &name))
return NULL;
+ if (!hackcheck(self, func, "__delattr__"))
+ return NULL;
res = (*func)(self, name, NULL);
if (res < 0)
return NULL;