summaryrefslogtreecommitdiffstats
path: root/Objects
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>1997-08-25 21:23:56 (GMT)
committerGuido van Rossum <guido@python.org>1997-08-25 21:23:56 (GMT)
commitb2173c3146e945100ba53bfe6343d20ec3c9a333 (patch)
tree8e69dd57a2a4bdf072e2b7747405f1cd83b851d2 /Objects
parenta27d11221303d9cc6a2359b6de2cdaba6a2b1e97 (diff)
downloadcpython-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.c74
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)