From 81daa32c15cfa9f05eda037916cdbfd5b4323431 Mon Sep 17 00:00:00 2001 From: Guido van Rossum Date: Thu, 20 May 1993 14:24:46 +0000 Subject: 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. --- Include/accessobject.h | 54 +++++++++ Include/ceval.h | 1 + Include/classobject.h | 12 +- Include/eval.h | 3 +- Include/frameobject.h | 3 +- Objects/accessobject.c | 320 +++++++++++++++++++++++++++++++++++++++++++++++++ Objects/classobject.c | 258 ++++++++++++++++++++++++++------------- Objects/frameobject.c | 8 +- Objects/moduleobject.c | 5 +- Python/bltinmodule.c | 2 +- Python/ceval.c | 127 ++++++++++++-------- Python/compile.c | 6 +- Python/import.c | 4 +- Python/pythonrun.c | 2 +- 14 files changed, 655 insertions(+), 150 deletions(-) create mode 100644 Include/accessobject.h create mode 100644 Objects/accessobject.c diff --git a/Include/accessobject.h b/Include/accessobject.h new file mode 100644 index 0000000..1c67849 --- /dev/null +++ b/Include/accessobject.h @@ -0,0 +1,54 @@ +/*********************************************************** +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 interface */ + +/* Access mode bits (note similarity with UNIX permissions) */ +#define AC_R 0444 +#define AC_W 0222 + +#define AC_PRIVATE 0700 +#define AC_R_PRIVATE 0400 +#define AC_W_PRIVATE 0200 + +#define AC_PROTECTED 0070 +#define AC_R_PROTECTED 0040 +#define AC_W_PROTECTED 0020 + +#define AC_PUBLIC 0007 +#define AC_R_PUBLIC 0004 +#define AC_W_PUBLIC 0002 + +extern typeobject Accesstype; + +#define is_accessobject(v) ((v)->ob_type == &Accesstype) + +object *newaccessobject PROTO((object *, object *, typeobject *, int)); +object *getaccessvalue PROTO((object *, object *)); +int setaccessvalue PROTO((object *, object *, object *)); + +void setaccessowner PROTO((object *, object *)); +object *cloneaccessobject PROTO((object *)); + +extern typeobject Anynumbertype, Anysequencetype, Anymappingtype; diff --git a/Include/ceval.h b/Include/ceval.h index a9f79b5..ab7659e 100644 --- a/Include/ceval.h +++ b/Include/ceval.h @@ -28,6 +28,7 @@ object *call_object PROTO((object *, object *)); object *getglobals PROTO((void)); object *getlocals PROTO((void)); +object *getclass PROTO((void)); void mergelocals PROTO((void)); void printtraceback PROTO((object *)); diff --git a/Include/classobject.h b/Include/classobject.h index b9bbc9b..ec07b59 100644 --- a/Include/classobject.h +++ b/Include/classobject.h @@ -30,6 +30,13 @@ It should be possible to use other object types as base classes, but currently it isn't. We'll see if we can fix that later, sigh... */ +typedef struct { + OB_HEAD + object *cl_bases; /* A tuple of class objects */ + object *cl_dict; /* A dictionary */ + object *cl_name; /* A string */ +} classobject; + extern typeobject Classtype, Instancetype, Instancemethodtype; #define is_classobject(op) ((op)->ob_type == &Classtype) @@ -38,9 +45,12 @@ extern typeobject Classtype, Instancetype, Instancemethodtype; extern object *newclassobject PROTO((object *, object *, object *)); extern object *newinstanceobject PROTO((object *, object *)); -extern object *newinstancemethodobject PROTO((object *, object *)); +extern object *newinstancemethodobject PROTO((object *, object *, object *)); extern object *instancemethodgetfunc PROTO((object *)); extern object *instancemethodgetself PROTO((object *)); +extern object *instancemethodgetclass PROTO((object *)); extern object *instance_convert PROTO((object *, char *)); + +extern int issubclass PROTO((object *, object *)); diff --git a/Include/eval.h b/Include/eval.h index 8ac672f..a7a0ec8 100644 --- a/Include/eval.h +++ b/Include/eval.h @@ -24,4 +24,5 @@ OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. /* Interface to execute compiled code */ -object *eval_code PROTO((codeobject *, object *, object *, object *)); +object *eval_code + PROTO((codeobject *, object *, object *, object *, object *)); diff --git a/Include/frameobject.h b/Include/frameobject.h index d46b454..2056e06 100644 --- a/Include/frameobject.h +++ b/Include/frameobject.h @@ -36,6 +36,7 @@ typedef struct _frame { codeobject *f_code; /* code segment */ object *f_globals; /* global symbol table (dictobject) */ object *f_locals; /* local symbol table (dictobject) */ + object *f_class; /* class context (classobject or NULL) */ object *f_fastlocals; /* fast local variables (listobject) */ object *f_localmap; /* local variable names (dictobject) */ object **f_valuestack; /* malloc'ed array */ @@ -55,7 +56,7 @@ extern typeobject Frametype; #define is_frameobject(op) ((op)->ob_type == &Frametype) frameobject * newframeobject PROTO( - (frameobject *, codeobject *, object *, object *, int, int)); + (frameobject *, codeobject *, object *, object *, object *, int, int)); /* The rest of the interface is specific for frame objects */ 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, "", + 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, "", - fname, cname, (long)a->im_func); + if (self == NULL) + sprintf(buf, "", fcname, fname); + else { + iclassname = self->in_class->cl_name; + if (iclassname != NULL && is_stringobject(iclassname)) + icname = getstringvalue(iclassname); + else + icname = "?"; + sprintf(buf, "", + 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) diff --git a/Python/bltinmodule.c b/Python/bltinmodule.c index 3d9504b..c2c2966 100644 --- a/Python/bltinmodule.c +++ b/Python/bltinmodule.c @@ -212,7 +212,7 @@ exec_eval(v, start) } if (is_codeobject(str)) return eval_code((codeobject *) str, globals, locals, - (object *)NULL); + (object *)NULL, (object *)NULL); s = getstringvalue(str); if (strlen(s) != getstringsize(str)) { err_setstr(ValueError, "embedded '\\0' in string arg"); diff --git a/Python/ceval.c b/Python/ceval.c index 57abda6..39a20d7 100644 --- a/Python/ceval.c +++ b/Python/ceval.c @@ -161,10 +161,11 @@ enum why_code { /* Interpreter main loop */ object * -eval_code(co, globals, locals, arg) +eval_code(co, globals, locals, class, arg) codeobject *co; object *globals; object *locals; + object *class; object *arg; { register unsigned char *next_instr; @@ -244,6 +245,7 @@ eval_code(co, globals, locals, arg) co, /*code*/ globals, /*globals*/ locals, /*locals*/ + class, /*class*/ 50, /*nvalues*/ 20); /*nblocks*/ if (f == NULL) @@ -759,7 +761,7 @@ eval_code(co, globals, locals, arg) v = POP(); u = dict2lookup(f->f_locals, w); if (u != NULL && is_accessobject(u)) { - err = setaccessvalue(u, (object *)NULL, v); + err = setaccessvalue(u, class, v); DECREF(v); break; } @@ -771,7 +773,7 @@ eval_code(co, globals, locals, arg) w = GETNAMEV(oparg); u = dict2lookup(f->f_locals, w); if (u != NULL && is_accessobject(u)) { - err = setaccessvalue(u, (object *)NULL, + err = setaccessvalue(u, class, (object *)NULL); break; } @@ -969,7 +971,7 @@ eval_code(co, globals, locals, arg) v = POP(); u = dict2lookup(f->f_locals, w); if (u != NULL && is_accessobject(u)) { - err = setaccessvalue(u, (object *)NULL, v); + err = setaccessvalue(u, class, v); DECREF(v); break; } @@ -981,7 +983,7 @@ eval_code(co, globals, locals, arg) w = GETNAMEV(oparg); u = dict2lookup(f->f_locals, w); if (u != NULL && is_accessobject(u)) { - err = setaccessvalue(u, (object *)NULL, + err = setaccessvalue(u, class, (object *)NULL); break; } @@ -1012,11 +1014,12 @@ eval_code(co, globals, locals, arg) } } if (is_accessobject(x)) { - x = getaccessvalue(x, (object *)NULL); + x = getaccessvalue(x, class); if (x == NULL) break; } - INCREF(x); + else + INCREF(x); PUSH(x); break; @@ -1033,11 +1036,12 @@ eval_code(co, globals, locals, arg) } } if (is_accessobject(x)) { - x = getaccessvalue(x, (object *)NULL); + x = getaccessvalue(x, class); if (x == NULL) break; } - INCREF(x); + else + INCREF(x); PUSH(x); break; @@ -1049,11 +1053,12 @@ eval_code(co, globals, locals, arg) break; } if (is_accessobject(x)) { - x = getaccessvalue(x, (object *)NULL); + x = getaccessvalue(x, class); if (x == NULL) break; } - INCREF(x); + else + INCREF(x); PUSH(x); break; @@ -1084,11 +1089,12 @@ eval_code(co, globals, locals, arg) break; } if (is_accessobject(x)) { - x = getaccessvalue(x, (object *)NULL); + x = getaccessvalue(x, class); if (x == NULL) break; } - INCREF(x); + else + INCREF(x); PUSH(x); break; @@ -1096,7 +1102,7 @@ eval_code(co, globals, locals, arg) v = POP(); w = GETLISTITEM(fastlocals, oparg); if (w != NULL && is_accessobject(w)) { - err = setaccessvalue(w, (object *)NULL, v); + err = setaccessvalue(w, class, v); DECREF(v); break; } @@ -1112,8 +1118,7 @@ eval_code(co, globals, locals, arg) break; } if (w != NULL && is_accessobject(w)) { - err = setaccessvalue(w, (object *)NULL, - (object *)NULL); + err = setaccessvalue(w, class, (object *)NULL); break; } DECREF(x); @@ -1643,6 +1648,15 @@ getglobals() return current_frame->f_globals; } +object * +getclass() +{ + if (current_frame == NULL) + return NULL; + else + return current_frame->f_class; +} + void printtraceback(f) object *f; @@ -1974,37 +1988,41 @@ call_function(func, arg) { object *newarg = NULL; object *newlocals, *newglobals; + object *class = NULL; object *co, *v; if (is_instancemethodobject(func)) { - int argcount; object *self = instancemethodgetself(func); + class = instancemethodgetclass(func); func = instancemethodgetfunc(func); - if (arg == NULL) - argcount = 0; - else if (is_tupleobject(arg)) - argcount = gettuplesize(arg); - else - argcount = 1; - newarg = newtupleobject(argcount + 1); - if (newarg == NULL) - return NULL; - INCREF(self); - settupleitem(newarg, 0, self); - if (arg != NULL && !is_tupleobject(arg)) { - INCREF(arg); - settupleitem(newarg, 1, arg); - } - else { - int i; - object *v; - for (i = 0; i < argcount; i++) { - v = gettupleitem(arg, i); - XINCREF(v); - settupleitem(newarg, i+1, v); + if (self != NULL) { + int argcount; + if (arg == NULL) + argcount = 0; + else if (is_tupleobject(arg)) + argcount = gettuplesize(arg); + else + argcount = 1; + newarg = newtupleobject(argcount + 1); + if (newarg == NULL) + return NULL; + INCREF(self); + settupleitem(newarg, 0, self); + if (arg != NULL && !is_tupleobject(arg)) { + INCREF(arg); + settupleitem(newarg, 1, arg); + } + else { + int i; + object *v; + for (i = 0; i < argcount; i++) { + v = gettupleitem(arg, i); + XINCREF(v); + settupleitem(newarg, i+1, v); + } } + arg = newarg; } - arg = newarg; } else { if (!is_funcobject(func)) { @@ -2031,7 +2049,7 @@ call_function(func, arg) newglobals = getfuncglobals(func); INCREF(newglobals); - v = eval_code((codeobject *)co, newglobals, newlocals, arg); + v = eval_code((codeobject *)co, newglobals, newlocals, class, arg); DECREF(newlocals); DECREF(newglobals); @@ -2367,10 +2385,10 @@ access_statement(name, mode, f) int mode; frameobject *f; { - object *value; - int i = -1; - object *ac; - int ret; + object *value, *ac; + typeobject *type; + int fastind, ret; + fastind = -1; if (f->f_localmap == NULL) value = dict2lookup(f->f_locals, name); else { @@ -2378,12 +2396,13 @@ access_statement(name, mode, f) if (value == NULL || !is_intobject(value)) value = NULL; else { - i = getintvalue(value); - if (0 <= i && i < getlistsize(f->f_fastlocals)) - value = getlistitem(f->f_fastlocals, i); + fastind = getintvalue(value); + if (0 <= fastind && + fastind < getlistsize(f->f_fastlocals)) + value = getlistitem(f->f_fastlocals, fastind); else { value = NULL; - i = -1; + fastind = -1; } } } @@ -2392,11 +2411,15 @@ access_statement(name, mode, f) return -1; } err_clear(); - ac = newaccessobject(value, (object*)NULL, (typeobject*)NULL, mode); + if (value != NULL && value != None) + type = value->ob_type; + else + type = NULL; + ac = newaccessobject(value, (object*)NULL, type, mode); if (ac == NULL) return -1; - if (i >= 0) - ret = setlistitem(f->f_fastlocals, i, ac); + if (fastind >= 0) + ret = setlistitem(f->f_fastlocals, fastind, ac); else { ret = dict2insert(f->f_locals, name, ac); DECREF(ac); diff --git a/Python/compile.c b/Python/compile.c index d9d661c..a8cd4e9 100644 --- a/Python/compile.c +++ b/Python/compile.c @@ -1429,8 +1429,8 @@ com_access_stmt(c, n) /* Calculate the mode mask */ mode = 0; for (j = i; j < NCH(n); j += 2) { - int r=0,w=0,p=0; - for (k=0; k