diff options
author | Guido van Rossum <guido@python.org> | 1997-08-25 21:23:56 (GMT) |
---|---|---|
committer | Guido van Rossum <guido@python.org> | 1997-08-25 21:23:56 (GMT) |
commit | b2173c3146e945100ba53bfe6343d20ec3c9a333 (patch) | |
tree | 8e69dd57a2a4bdf072e2b7747405f1cd83b851d2 /Objects | |
parent | a27d11221303d9cc6a2359b6de2cdaba6a2b1e97 (diff) | |
download | cpython-b2173c3146e945100ba53bfe6343d20ec3c9a333.zip cpython-b2173c3146e945100ba53bfe6343d20ec3c9a333.tar.gz cpython-b2173c3146e945100ba53bfe6343d20ec3c9a333.tar.bz2 |
Allow assignments to instance.__dict__ and instance.__class__. The
former lets you give an instance a set of new instance vars. The
latter lets you give it a new class. Both are typechecked and
disallowed in restricted mode.
For classes, the check for read-only special attributes is tightened
so that only assignments to __dict__, __bases__, __name__,
__getattr__, __setattr__, and __delattr__ (these could be made to work
as well, but I don't know if that's useful -- let's see first whether
mucking with instances will help).
Diffstat (limited to 'Objects')
-rw-r--r-- | Objects/classobject.c | 74 |
1 files changed, 57 insertions, 17 deletions
diff --git a/Objects/classobject.c b/Objects/classobject.c index f0f023b..91307f8 100644 --- a/Objects/classobject.c +++ b/Objects/classobject.c @@ -175,20 +175,31 @@ class_setattr(op, name, v) PyObject *name; PyObject *v; { - char *sname = PyString_AsString(name); - if (sname[0] == '_' && sname[1] == '_') { - int n = PyString_Size(name); - if (sname[n-1] == '_' && sname[n-2] == '_') { - PyErr_SetString(PyExc_TypeError, - "read-only special attribute"); - return -1; - } - } + char *sname; if (PyEval_GetRestricted()) { PyErr_SetString(PyExc_RuntimeError, "classes are read-only in restricted mode"); return -1; } + sname = PyString_AsString(name); + if (sname[0] == '_' && sname[1] == '_') { + int n = PyString_Size(name); + if (sname[n-1] == '_' && sname[n-2] == '_') { + if (strcmp(sname, "__dict__") == 0 || + strcmp(sname, "__bases__") == 0 || + strcmp(sname, "__name__") == 0 || + strcmp(sname, "__getattr__") == 0 || + strcmp(sname, "__setattr__") == 0 || + strcmp(sname, "__delattr__") == 0) + { + /* XXX In unrestricted mode, we should + XXX allow this -- with a type check */ + PyErr_SetString(PyExc_TypeError, + "read-only special attribute"); + return -1; + } + } + } if (v == NULL) { int rv = PyDict_DelItem(op->cl_dict, name); if (rv < 0) @@ -489,16 +500,45 @@ instance_setattr(inst, name, v) PyObject *name; PyObject *v; { - PyObject *func, *args, *res; + PyObject *func, *args, *res, *tmp; char *sname = PyString_AsString(name); - if (sname[0] == '_' && sname[1] == '_' - && (strcmp(sname, "__dict__") == 0 || - strcmp(sname, "__class__") == 0)) { - int n = PyString_Size(name); + if (sname[0] == '_' && sname[1] == '_') { + int n = PyString_Size(name); if (sname[n-1] == '_' && sname[n-2] == '_') { - PyErr_SetString(PyExc_TypeError, - "read-only special attribute"); - return -1; + if (strcmp(sname, "__dict__") == 0) { + if (PyEval_GetRestricted()) { + PyErr_SetString(PyExc_RuntimeError, + "__dict__ not accessible in restricted mode"); + return -1; + } + if (v == NULL || !PyDict_Check(v)) { + PyErr_SetString(PyExc_TypeError, + "__dict__ must be set to a dictionary"); + return -1; + } + tmp = inst->in_dict; + Py_INCREF(v); + inst->in_dict = v; + Py_DECREF(tmp); + return 0; + } + if (strcmp(sname, "__class__") == 0) { + if (PyEval_GetRestricted()) { + PyErr_SetString(PyExc_RuntimeError, + "__class__ not accessible in restricted mode"); + return -1; + } + if (v == NULL || !PyClass_Check(v)) { + PyErr_SetString(PyExc_TypeError, + "__class__ must be set to a class"); + return -1; + } + tmp = (PyObject *)(inst->in_class); + Py_INCREF(v); + inst->in_class = (PyClassObject *)v; + Py_DECREF(tmp); + return 0; + } } } if (v == NULL) |