summaryrefslogtreecommitdiffstats
path: root/Objects
diff options
context:
space:
mode:
authorGuido van Rossum <guido@python.org>1993-05-20 14:24:46 (GMT)
committerGuido van Rossum <guido@python.org>1993-05-20 14:24:46 (GMT)
commit81daa32c15cfa9f05eda037916cdbfd5b4323431 (patch)
tree82d67f6db4ff6f1ae1a682f2ec4b01d075f3e405 /Objects
parent25831652fd4c03323066d4cafdc0551c396a993e (diff)
downloadcpython-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.c320
-rw-r--r--Objects/classobject.c258
-rw-r--r--Objects/frameobject.c8
-rw-r--r--Objects/moduleobject.c5
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)