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).
This commit is contained in:
Guido van Rossum 1997-08-25 21:23:56 +00:00
parent a27d112213
commit b2173c3146
1 changed files with 57 additions and 17 deletions

View File

@ -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)