diff options
author | Guido van Rossum <guido@python.org> | 1993-05-20 14:24:46 (GMT) |
---|---|---|
committer | Guido van Rossum <guido@python.org> | 1993-05-20 14:24:46 (GMT) |
commit | 81daa32c15cfa9f05eda037916cdbfd5b4323431 (patch) | |
tree | 82d67f6db4ff6f1ae1a682f2ec4b01d075f3e405 /Objects | |
parent | 25831652fd4c03323066d4cafdc0551c396a993e (diff) | |
download | cpython-81daa32c15cfa9f05eda037916cdbfd5b4323431.zip cpython-81daa32c15cfa9f05eda037916cdbfd5b4323431.tar.gz cpython-81daa32c15cfa9f05eda037916cdbfd5b4323431.tar.bz2 |
Access checks now work, at least for instance data (not for methods
yet). The class is now passed to eval_code and stored in the current
frame. It is also stored in instance method objects. An "unbound"
instance method is now returned when a function is retrieved through
"classname.funcname", which when called passes the class to eval_code.
Diffstat (limited to 'Objects')
-rw-r--r-- | Objects/accessobject.c | 320 | ||||
-rw-r--r-- | Objects/classobject.c | 258 | ||||
-rw-r--r-- | Objects/frameobject.c | 8 | ||||
-rw-r--r-- | Objects/moduleobject.c | 5 |
4 files changed, 503 insertions, 88 deletions
diff --git a/Objects/accessobject.c b/Objects/accessobject.c new file mode 100644 index 0000000..41790cd --- /dev/null +++ b/Objects/accessobject.c @@ -0,0 +1,320 @@ +/*********************************************************** +Copyright 1991, 1992, 1993 by Stichting Mathematisch Centrum, +Amsterdam, The Netherlands. + + All Rights Reserved + +Permission to use, copy, modify, and distribute this software and its +documentation for any purpose and without fee is hereby granted, +provided that the above copyright notice appear in all copies and that +both that copyright notice and this permission notice appear in +supporting documentation, and that the names of Stichting Mathematisch +Centrum or CWI not be used in advertising or publicity pertaining to +distribution of the software without specific, written prior permission. + +STICHTING MATHEMATISCH CENTRUM DISCLAIMS ALL WARRANTIES WITH REGARD TO +THIS SOFTWARE, INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS, IN NO EVENT SHALL STICHTING MATHEMATISCH CENTRUM BE LIABLE +FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN +ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT +OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + +******************************************************************/ + +/* Access object implementation */ + +#include "allobjects.h" + +#include "structmember.h" +#include "modsupport.h" /* For getargs() etc. */ + +typedef struct { + OB_HEAD + object *ac_value; + object *ac_class; + typeobject *ac_type; + int ac_mode; +} accessobject; + +/* Forward */ +static int typecheck PROTO((object *, typeobject *)); +static int classcheck PROTO((object *, object *, int, int)); + +object * +newaccessobject(value, class, type, mode) + object *value; + object *class; + typeobject *type; + int mode; +{ + accessobject *ap; + if (class != NULL && !is_classobject(class)) { + err_badcall(); + return NULL; + } + if (!typecheck(value, type)) { + err_setstr(AccessError, + "access: initial value has inappropriate type"); + return NULL; + } + ap = NEWOBJ(accessobject, &Accesstype); + if (ap == NULL) + return NULL; + XINCREF(value); + ap->ac_value = value; + XINCREF(class); + ap->ac_class = class; + XINCREF(type); + ap->ac_type = (typeobject *)type; + ap->ac_mode = mode; + return (object *)ap; +} + +object * +cloneaccessobject(op) + object *op; +{ + register accessobject *ap; + if (!is_accessobject(op)) { + err_badcall(); + return NULL; + } + ap = (accessobject *)op; + return newaccessobject(ap->ac_value, ap->ac_class, + ap->ac_type, ap->ac_mode); +} + +void +setaccessowner(op, class) + object *op; + object *class; +{ + register accessobject *ap; + if (!is_accessobject(op) || class != NULL && !is_classobject(class)) + return; /* XXX no error */ + ap = (accessobject *)op; + XDECREF(ap->ac_class); + XINCREF(class); + ap->ac_class = class; +} + +object * +getaccessvalue(op, class) + object *op; + object *class; +{ + register accessobject *ap; + if (!is_accessobject(op)) { + err_badcall(); + return NULL; + } + ap = (accessobject *)op; + + if (!classcheck(class, ap->ac_class, AC_R, ap->ac_mode)) { + err_setstr(AccessError, "read access denied"); + return NULL; + } + + if (ap->ac_value == NULL) { + err_setstr(AccessError, "no current value"); + return NULL; + } + INCREF(ap->ac_value); + return ap->ac_value; +} + +int +setaccessvalue(op, class, value) + object *op; + object *class; + object *value; +{ + register accessobject *ap; + if (!is_accessobject(op)) { + err_badcall(); + return -1; + } + ap = (accessobject *)op; + + if (!classcheck(class, ap->ac_class, AC_W, ap->ac_mode)) { + err_setstr(AccessError, "write access denied"); + return -1; + } + + if (!typecheck(value, ap->ac_type)) { + err_setstr(AccessError, "assign value of inappropriate type"); + return -1; + } + + if (value == NULL) { /* Delete it */ + if (ap->ac_value == NULL) { + err_setstr(AccessError, "no current value"); + return -1; + } + DECREF(ap->ac_value); + ap->ac_value = NULL; + return 0; + } + XDECREF(ap->ac_value); + INCREF(value); + ap->ac_value = value; + return 0; +} + +static int +typecheck(value, type) + object *value; + typeobject *type; +{ + object *x; + if (value == NULL || type == NULL) + return 1; /* No check */ + if (value->ob_type == type) + return 1; /* Exact match */ + if (type == &Anynumbertype) { + if (value->ob_type->tp_as_number == NULL) + return 0; + if (!is_instanceobject(value)) + return 1; + /* For instances, make sure it really looks like a number */ + x = getattr(value, "__sub__"); + if (x == NULL) { + err_clear(); + return 0; + } + DECREF(x); + return 1; + } + if (type == &Anysequencetype) { + if (value->ob_type->tp_as_sequence == NULL) + return 0; + if (!is_instanceobject(value)) + return 1; + /* For instances, make sure it really looks like a sequence */ + x = getattr(value, "__getslice__"); + if (x == NULL) { + err_clear(); + return 0; + } + DECREF(x); + return 1; + } + if (type == &Anymappingtype) { + if (value->ob_type->tp_as_mapping == NULL) + return 0; + if (!is_instanceobject(value)) + return 1; + /* For instances, make sure it really looks like a mapping */ + x = getattr(value, "__getitem__"); + if (x == NULL) { + err_clear(); + return 0; + } + DECREF(x); + return 1; + } + return 0; +} + +static int +classcheck(caller, owner, access, mode) + object *caller; + object *owner; + int access; + int mode; +{ + if (caller == owner && owner != NULL) + return access & mode & (AC_PRIVATE|AC_PROTECTED|AC_PUBLIC); + if (caller != NULL && owner != NULL && issubclass(caller, owner)) + return access & mode & (AC_PROTECTED|AC_PUBLIC); + return access & mode & AC_PUBLIC; +} + +/* Access methods */ + +static void +access_dealloc(ap) + accessobject *ap; +{ + XDECREF(ap->ac_value); + XDECREF(ap->ac_class); + XDECREF(ap->ac_type); + DEL(ap); +} + +#define OFF(x) offsetof(accessobject, x) + +static struct memberlist access_memberlist[] = { + {"ac_value", T_OBJECT, OFF(ac_value)}, + {"ac_class", T_OBJECT, OFF(ac_class)}, + {"ac_type", T_OBJECT, OFF(ac_type)}, + {"ac_mode", T_INT, OFF(ac_mode)}, + {NULL} /* Sentinel */ +}; + +static object * +access_getattr(ap, name) + accessobject *ap; + char *name; +{ + return getmember((char *)ap, access_memberlist, name); +} + +static object * +access_repr(ap) + accessobject *ap; +{ + char buf[300]; + classobject *class = (classobject *)ap->ac_class; + typeobject *type = ap->ac_type; + sprintf(buf, "<access object, class %.100s, type %.100s, mode 0%o>", + class ? getstringvalue(class->cl_name) : "-", + type ? type->tp_name : "-", + ap->ac_mode); + return newstringobject(buf); +} + +typeobject Accesstype = { + OB_HEAD_INIT(&Typetype) + 0, /*ob_size*/ + "access", /*tp_name*/ + sizeof(accessobject), /*tp_size*/ + 0, /*tp_itemsize*/ + /* methods */ + access_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + access_getattr, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + access_repr, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ +}; + +/* Dummy type objects to indicate classes of types */ + +/* XXX This should be replaced by a more general "subclassing" + XXX mechanism for type objects... */ + +typeobject Anynumbertype = { + OB_HEAD_INIT(&Typetype) + 0, /*ob_size*/ + "*number*", /*tp_name*/ +}; + +/* XXX Should really distinguish mutable and immutable sequences as well */ + +typeobject Anysequencetype = { + OB_HEAD_INIT(&Typetype) + 0, /*ob_size*/ + "*sequence*", /*tp_name*/ +}; + +typeobject Anymappingtype = { + OB_HEAD_INIT(&Typetype) + 0, /*ob_size*/ + "*mapping*", /*tp_name*/ +}; diff --git a/Objects/classobject.c b/Objects/classobject.c index bc61b64..e2a5e63 100644 --- a/Objects/classobject.c +++ b/Objects/classobject.c @@ -29,19 +29,14 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. #include "structmember.h" #include "ceval.h" -typedef struct { - OB_HEAD - object *cl_bases; /* A tuple */ - object *cl_methods; /* A dictionary */ - object *cl_name; /* A string */ -} classobject; - object * -newclassobject(bases, methods, name) +newclassobject(bases, dict, name) object *bases; /* NULL or tuple of classobjects! */ - object *methods; + object *dict; object *name; /* String; NULL if unknown */ { + int pos; + object *key, *value; classobject *op; if (bases == NULL) { bases = newtupleobject(0); @@ -56,10 +51,15 @@ newclassobject(bases, methods, name) return NULL; } op->cl_bases = bases; - INCREF(methods); - op->cl_methods = methods; + INCREF(dict); + op->cl_dict = dict; XINCREF(name); op->cl_name = name; + pos = 0; + while (mappinggetnext(dict, &pos, &key, &value)) { + if (is_accessobject(value)) + setaccessowner(value, (object *)op); + } return (object *) op; } @@ -70,20 +70,43 @@ class_dealloc(op) classobject *op; { DECREF(op->cl_bases); - DECREF(op->cl_methods); + DECREF(op->cl_dict); XDECREF(op->cl_name); free((ANY *)op); } static object * +class_lookup(cp, name, pclass) + classobject *cp; + char *name; + classobject **pclass; +{ + int i, n; + object *value = dictlookup(cp->cl_dict, name); + if (value != NULL) { + *pclass = cp; + return value; + } + n = gettuplesize(cp->cl_bases); + for (i = 0; i < n; i++) { + object *v = class_lookup((classobject *) + gettupleitem(cp->cl_bases, i), name, pclass); + if (v != NULL) + return v; + } + return NULL; +} + +static object * class_getattr(op, name) register classobject *op; register char *name; { register object *v; + object *class; if (strcmp(name, "__dict__") == 0) { - INCREF(op->cl_methods); - return op->cl_methods; + INCREF(op->cl_dict); + return op->cl_dict; } if (strcmp(name, "__bases__") == 0) { INCREF(op->cl_bases); @@ -97,25 +120,17 @@ class_getattr(op, name) INCREF(v); return v; } - v = dictlookup(op->cl_methods, name); + v = class_lookup(op, name, &class); if (v != NULL) { if (is_accessobject(v)) - v = getaccessvalue(v, (object *)NULL); + v = getaccessvalue(v, getclass()); + else if (is_funcobject(v)) + v = newinstancemethodobject(v, (object *)NULL, + (object *)class); else INCREF(v); return v; } - { - int n = gettuplesize(op->cl_bases); - int i; - for (i = 0; i < n; i++) { - v = class_getattr((classobject *) - gettupleitem(op->cl_bases, i), name); - if (v != NULL) - return v; - err_clear(); - } - } err_setstr(AttributeError, name); return NULL; } @@ -134,18 +149,18 @@ class_setattr(op, name, v) return -1; } } - ac = dictlookup(op->cl_methods, name); + ac = dictlookup(op->cl_dict, name); if (ac != NULL && is_accessobject(ac)) - return setaccessvalue(ac, (object *)NULL, v); + return setaccessvalue(ac, getclass(), v); if (v == NULL) { - int rv = dictremove(op->cl_methods, name); + int rv = dictremove(op->cl_dict, name); if (rv < 0) err_setstr(AttributeError, "delete non-existing class attribute"); return rv; } else - return dictinsert(op->cl_methods, name, v); + return dictinsert(op->cl_dict, name, v); } static object * @@ -179,17 +194,71 @@ typeobject Classtype = { 0, /*tp_as_mapping*/ }; +int +issubclass(class, base) + object *class; + object *base; +{ + int i, n; + classobject *cp; + if (class == NULL || !is_classobject(class)) + return 0; + if (class == base) + return 1; + cp = (classobject *)class; + n = gettuplesize(cp->cl_bases); + for (i = 0; i < n; i++) { + if (issubclass(gettupleitem(cp->cl_bases, i), base)) + return 1; + } + return 0; +} + -/* We're not done yet: next, we define instance objects... */ +/* Instance objects */ typedef struct { OB_HEAD classobject *in_class; /* The class object */ - object *in_attr; /* A dictionary */ + object *in_dict; /* A dictionary */ } instanceobject; static object *instance_getattr PROTO((instanceobject *, char *)); +static int +addaccess(class, inst) + classobject *class; + instanceobject *inst; +{ + int i, n, pos, ret; + object *key, *value, *ac; + + n = gettuplesize(class->cl_bases); + for (i = 0; i < n; i++) { + if (addaccess(gettupleitem(class->cl_bases, i), inst) < 0) + return -1; + } + + pos = 0; + while (mappinggetnext(class->cl_dict, &pos, &key, &value)) { + if (!is_accessobject(value)) + continue; + ac = dict2lookup(inst->in_dict, key); + if (ac != NULL && is_accessobject(ac)) { + err_setval(ConflictError, key); + return -1; + } + ac = cloneaccessobject(value); + if (ac == NULL) + return -1; + ret = dict2insert(inst->in_dict, key, ac); + DECREF(ac); + if (ret != 0) + return -1; + } + return 0; +} + object * newinstanceobject(class, arg) object *class; @@ -198,8 +267,6 @@ newinstanceobject(class, arg) register instanceobject *inst; object *v; object *init; - int pos; - object *key, *value; if (!is_classobject(class)) { err_badcall(); return NULL; @@ -209,26 +276,12 @@ newinstanceobject(class, arg) return NULL; INCREF(class); inst->in_class = (classobject *)class; - inst->in_attr = newdictobject(); - if (inst->in_attr == NULL) { - error: + inst->in_dict = newdictobject(); + if (inst->in_dict == NULL || + addaccess((classobject *)class, inst) != 0) { DECREF(inst); return NULL; } - pos = 0; - while (mappinggetnext(((classobject *)class)->cl_methods, - &pos, &key, &value)) { - if (is_accessobject(value)) { - object *ac = cloneaccessobject(value); - int err; - if (ac == NULL) - goto error; - err = dict2insert(inst->in_attr, key, ac); - DECREF(ac); - if (err) - goto error; - } - } init = instance_getattr(inst, "__init__"); if (init == NULL) { err_clear(); @@ -288,7 +341,7 @@ instance_dealloc(inst) if (--inst->ob_refcnt > 0) return; /* __del__ added a reference; don't delete now */ DECREF(inst->in_class); - XDECREF(inst->in_attr); + XDECREF(inst->in_dict); free((ANY *)inst); } @@ -298,31 +351,30 @@ instance_getattr(inst, name) register char *name; { register object *v; + classobject *class; if (strcmp(name, "__dict__") == 0) { - INCREF(inst->in_attr); - return inst->in_attr; + INCREF(inst->in_dict); + return inst->in_dict; } if (strcmp(name, "__class__") == 0) { INCREF(inst->in_class); return (object *)inst->in_class; } - v = dictlookup(inst->in_attr, name); + v = dictlookup(inst->in_dict, name); if (v != NULL) { if (is_accessobject(v)) - v = getaccessvalue(v, (object *)NULL); + v = getaccessvalue(v, getclass()); else INCREF(v); return v; } - v = class_getattr(inst->in_class, name); + v = class_lookup(inst->in_class, name, &class); if (v == NULL) - return v; /* class_getattr() has set the error */ - if (is_funcobject(v)) { - object *w = newinstancemethodobject(v, (object *)inst); - DECREF(v); - return w; - } - DECREF(v); + goto error; + if (is_funcobject(v)) + return newinstancemethodobject(v, (object *)inst, + (object *)class); + error: err_setstr(AttributeError, name); return NULL; } @@ -341,18 +393,18 @@ instance_setattr(inst, name, v) return -1; } } - ac = dictlookup(inst->in_attr, name); + ac = dictlookup(inst->in_dict, name); if (ac != NULL && is_accessobject(ac)) - return setaccessvalue(ac, (object *)NULL, v); + return setaccessvalue(ac, getclass(), v); if (v == NULL) { - int rv = dictremove(inst->in_attr, name); + int rv = dictremove(inst->in_dict, name); if (rv < 0) err_setstr(AttributeError, "delete non-existing instance attribute"); return rv; } else - return dictinsert(inst->in_attr, name, v); + return dictinsert(inst->in_dict, name, v); } static object * @@ -893,18 +945,24 @@ instance_convert(inst, methodname) } -/* And finally, here are instance method objects */ +/* Instance method objects are used for two purposes: + (a) as bound instance methods (returned by instancename.methodname) + (b) as unbound methods (returned by ClassName.methodname) + In case (b), im_self is NULL +*/ typedef struct { OB_HEAD - object *im_func; /* The method function */ - object *im_self; /* The object to which this applies */ + object *im_func; /* The function implementing the method */ + object *im_self; /* The instance it is bound to, or NULL */ + object *im_class; /* The class that defined the method */ } instancemethodobject; object * -newinstancemethodobject(func, self) +newinstancemethodobject(func, self, class) object *func; object *self; + object *class; { register instancemethodobject *im; if (!is_funcobject(func)) { @@ -916,8 +974,10 @@ newinstancemethodobject(func, self) return NULL; INCREF(func); im->im_func = func; - INCREF(self); + XINCREF(self); im->im_self = self; + INCREF(class); + im->im_class = class; return (object *)im; } @@ -943,6 +1003,17 @@ instancemethodgetself(im) return ((instancemethodobject *)im)->im_self; } +object * +instancemethodgetclass(im) + register object *im; +{ + if (!is_instancemethodobject(im)) { + err_badcall(); + return NULL; + } + return ((instancemethodobject *)im)->im_class; +} + /* Class method methods */ #define OFF(x) offsetof(instancemethodobject, x) @@ -950,6 +1021,7 @@ instancemethodgetself(im) static struct memberlist instancemethod_memberlist[] = { {"im_func", T_OBJECT, OFF(im_func)}, {"im_self", T_OBJECT, OFF(im_self)}, + {"im_class", T_OBJECT, OFF(im_class)}, {NULL} /* Sentinel */ }; @@ -966,7 +1038,8 @@ instancemethod_dealloc(im) register instancemethodobject *im; { DECREF(im->im_func); - DECREF(im->im_self); + XDECREF(im->im_self); + DECREF(im->im_class); free((ANY *)im); } @@ -985,20 +1058,32 @@ instancemethod_repr(a) instancemethodobject *a; { char buf[240]; - object *classname = - ((instanceobject *)(a->im_self))->in_class->cl_name; - object *funcname = ((funcobject *)(a->im_func))->func_name; - char *cname, *fname; - if (classname != NULL && is_stringobject(classname)) - cname = getstringvalue(classname); + instanceobject *self = (instanceobject *)(a->im_self); + funcobject *func = (funcobject *)(a->im_func); + classobject *class = (classobject *)(a->im_class); + object *fclassname, *iclassname, *funcname; + char *fcname, *icname, *fname; + fclassname = class->cl_name; + funcname = func->func_name; + if (fclassname != NULL && is_stringobject(fclassname)) + fcname = getstringvalue(fclassname); else - cname = "?"; + fcname = "?"; if (funcname != NULL && is_stringobject(funcname)) fname = getstringvalue(funcname); else fname = "?"; - sprintf(buf, "<method %.100s of %.100s instance at %lx>", - fname, cname, (long)a->im_func); + if (self == NULL) + sprintf(buf, "<unbound method %.100s.%.100s>", fcname, fname); + else { + iclassname = self->in_class->cl_name; + if (iclassname != NULL && is_stringobject(iclassname)) + icname = getstringvalue(iclassname); + else + icname = "?"; + sprintf(buf, "<method %.60s.%.60s of %.60s instance at %lx>", + fcname, fname, icname, (long)self); + } return newstringobject(buf); } @@ -1007,7 +1092,10 @@ instancemethod_hash(a) instancemethodobject *a; { long x, y; - x = hashobject(a->im_self); + if (a->im_self == NULL) + x = hashobject(None); + else + x = hashobject(a->im_self); if (x == -1) return -1; y = hashobject(a->im_func); diff --git a/Objects/frameobject.c b/Objects/frameobject.c index aa29795..7c2aeae 100644 --- a/Objects/frameobject.c +++ b/Objects/frameobject.c @@ -38,6 +38,7 @@ static struct memberlist frame_memberlist[] = { {"f_code", T_OBJECT, OFF(f_code)}, {"f_globals", T_OBJECT, OFF(f_globals)}, {"f_locals", T_OBJECT, OFF(f_locals)}, + {"f_class", T_OBJECT, OFF(f_class)}, /* {"f_fastlocals",T_OBJECT, OFF(f_fastlocals)}, /* XXX Unsafe */ {"f_localmap", T_OBJECT, OFF(f_localmap)}, {"f_lasti", T_INT, OFF(f_lasti)}, @@ -84,6 +85,7 @@ frame_dealloc(f) XDECREF(f->f_code); XDECREF(f->f_globals); XDECREF(f->f_locals); + XDECREF(f->f_class); XDECREF(f->f_fastlocals); XDECREF(f->f_localmap); f->f_back = free_list; @@ -108,11 +110,12 @@ typeobject Frametype = { }; frameobject * -newframeobject(back, code, globals, locals, nvalues, nblocks) +newframeobject(back, code, globals, locals, class, nvalues, nblocks) frameobject *back; codeobject *code; object *globals; object *locals; + object *class; int nvalues; int nblocks; { @@ -121,6 +124,7 @@ newframeobject(back, code, globals, locals, nvalues, nblocks) code == NULL || !is_codeobject(code) || globals == NULL || !is_dictobject(globals) || locals == NULL || !is_dictobject(locals) || + (class != NULL && !is_classobject(class)) || nvalues < 0 || nblocks < 0) { err_badcall(); return NULL; @@ -146,6 +150,8 @@ newframeobject(back, code, globals, locals, nvalues, nblocks) f->f_globals = globals; INCREF(locals); f->f_locals = locals; + XINCREF(class); + f->f_class = class; f->f_fastlocals = NULL; f->f_localmap = NULL; if (nvalues > f->f_nvalues || f->f_valuestack == NULL) { diff --git a/Objects/moduleobject.c b/Objects/moduleobject.c index 8949c7d..5c0db15 100644 --- a/Objects/moduleobject.c +++ b/Objects/moduleobject.c @@ -25,6 +25,7 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* Module object implementation */ #include "allobjects.h" +#include "ceval.h" typedef struct { OB_HEAD @@ -111,7 +112,7 @@ module_getattr(m, name) err_setstr(AttributeError, name); else { if (is_accessobject(res)) - res = getaccessvalue(res, (object *)NULL); + res = getaccessvalue(res, getclass()); else INCREF(res); } @@ -134,7 +135,7 @@ module_setattr(m, name, v) } ac = dictlookup(m->md_dict, name); if (ac != NULL && is_accessobject(ac)) - return setaccessvalue(ac, (object *)NULL, v); + return setaccessvalue(ac, getclass(), v); if (v == NULL) { int rv = dictremove(m->md_dict, name); if (rv < 0) |