]> granicus.if.org Git - python/commitdiff
Allow assignments to instance.__dict__ and instance.__class__. The
authorGuido van Rossum <guido@python.org>
Mon, 25 Aug 1997 21:23:56 +0000 (21:23 +0000)
committerGuido van Rossum <guido@python.org>
Mon, 25 Aug 1997 21:23:56 +0000 (21:23 +0000)
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).

Objects/classobject.c

index f0f023b96765e1e99a8d28cca2bf1219d9b96cda..91307f834c5d00366d8b4285ee944f950d3fc131 100644 (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)