[ python-Bugs-975646 ] tp_(get|set)attro? inheritance bug

SourceForge.net noreply at sourceforge.net
Tue Jun 22 05:17:33 EDT 2004


Bugs item #975646, was opened at 2004-06-18 23:04
Message generated for change (Comment added) made by mwh
You can respond by visiting: 
https://sourceforge.net/tracker/?func=detail&atid=105470&aid=975646&group_id=5470

Category: Python Interpreter Core
Group: Python 2.3
Status: Open
Resolution: None
Priority: 5
Submitted By: Gustavo J. A. M. Carneiro (gustavo)
Assigned to: Guido van Rossum (gvanrossum)
Summary: tp_(get|set)attro? inheritance bug

Initial Comment:
 Documentation says, regarding tp_getattr:
«
This field is inherited by subtypes together with
tp_getattro: a subtype inherits both tp_getattr and
tp_getattro from its base type when the subtype's
tp_getattr and tp_getattro are both NULL.
»

  Implementation disagrees, at least in cvs head, but
the effect of the bug (non-inheritance of tp_getattr)
happens in 2.3.3.  Follow with me:

In function type_new (typeobject.c) line 1927:
        /* Special case some slots */
        if (type->tp_dictoffset != 0 || nslots > 0) {
                if (base->tp_getattr == NULL &&
base->tp_getattro == NULL)
                        type->tp_getattro =
PyObject_GenericGetAttr;
                if (base->tp_setattr == NULL &&
base->tp_setattro == NULL)
                        type->tp_setattro =
PyObject_GenericSetAttr;
        }
...later in the same function...

        /* Initialize the rest */
        if (PyType_Ready(type) < 0) {
                Py_DECREF(type);
                return NULL;
        }

Inside PyType_Ready(), line 3208:
        for (i = 1; i < n; i++) {
                PyObject *b = PyTuple_GET_ITEM(bases, i);
                if (PyType_Check(b))
                        inherit_slots(type,
(PyTypeObject *)b);
        }

Inside inherit_slots, line (3056):
        if (type->tp_getattr == NULL &&
type->tp_getattro == NULL) {
                type->tp_getattr = base->tp_getattr;
                type->tp_getattro = base->tp_getattro;
        }
        if (type->tp_setattr == NULL &&
type->tp_setattro == NULL) {
                type->tp_setattr = base->tp_setattr;
                type->tp_setattro = base->tp_setattro;
        }

    So, if you have followed through, you'll notice
that type_new first sets tp_getattro = GenericGetAttr,
in case 'base' has neither tp_getattr nor tp_getattro.

    So, you are thinking that there is no problem.  If
base has tp_getattr, that code path won't be execute. 
The problem is with multiple inheritance.  In type_new,
'base' is determined by calling best_base().  But the
selected base may not have tp_getattr, while
another might have.  In this case, setting tp_getattro
based on information from the wrong base precludes the
slot from being inherited from the right base.  This is
happening in pygtk, unfortunately.

    One possible solution would be to move the first
code block to after the PyType_Ready() call.


----------------------------------------------------------------------

>Comment By: Michael Hudson (mwh)
Date: 2004-06-22 10:17

Message:
Logged In: YES 
user_id=6656

Without wanting to think about this terribly hard, wouldn't a 
workaround be for pygtk to implement tp_getattro and not 
tp_getattr?  IMO, this is a good idea anyway...

----------------------------------------------------------------------

Comment By: Martin v. Löwis (loewis)
Date: 2004-06-21 06:05

Message:
Logged In: YES 
user_id=21627

Guido, is this a bug?

----------------------------------------------------------------------

You can respond by visiting: 
https://sourceforge.net/tracker/?func=detail&atid=105470&aid=975646&group_id=5470



More information about the Python-bugs-list mailing list