Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Ensure in PyType_Ready() that base class of static type is static #66277

Open
serhiy-storchaka opened this issue Jul 26, 2014 · 26 comments
Open
Assignees
Labels
interpreter-core (Objects, Python, Grammar, and Parser dirs) topic-C-API type-feature A feature request or enhancement

Comments

@serhiy-storchaka
Copy link
Member

BPO 22079
Nosy @doko42, @pitrou, @scoder, @vstinner, @alex, @encukou, @serhiy-storchaka, @jdemeyer, @zhangyangyu
Files
  • issue22079.patch
  • issue22079-tp_bases.patch
  • Note: these values reflect the state of the issue at the time it was migrated and might not reflect the current state.

    Show more details

    GitHub fields:

    assignee = 'https://github.com/serhiy-storchaka'
    closed_at = None
    created_at = <Date 2014-07-26.12:36:39.011>
    labels = ['interpreter-core', 'type-feature']
    title = 'Ensure in PyType_Ready() that base class of static type is static'
    updated_at = <Date 2022-01-24.12:23:03.373>
    user = 'https://github.com/serhiy-storchaka'

    bugs.python.org fields:

    activity = <Date 2022-01-24.12:23:03.373>
    actor = 'petr.viktorin'
    assignee = 'serhiy.storchaka'
    closed = False
    closed_date = None
    closer = None
    components = ['Interpreter Core']
    creation = <Date 2014-07-26.12:36:39.011>
    creator = 'serhiy.storchaka'
    dependencies = []
    files = ['37211', '43541']
    hgrepos = []
    issue_num = 22079
    keywords = ['patch', 'needs review']
    message_count = 26.0
    messages = ['224049', '224102', '224103', '224110', '231277', '231579', '234852', '234876', '236807', '236830', '238881', '269188', '269195', '269223', '269247', '269275', '269278', '269279', '269291', '269339', '326321', '368736', '368743', '391446', '391464', '411469']
    nosy_count = 11.0
    nosy_names = ['doko', 'pitrou', 'scoder', 'vstinner', 'Arfrever', 'alex', 'petr.viktorin', 'python-dev', 'serhiy.storchaka', 'jdemeyer', 'xiang.zhang']
    pr_nums = []
    priority = 'normal'
    resolution = None
    stage = 'patch review'
    status = 'open'
    superseder = None
    type = 'enhancement'
    url = 'https://bugs.python.org/issue22079'
    versions = ['Python 2.7', 'Python 3.4', 'Python 3.5']

    @serhiy-storchaka
    Copy link
    Member Author

    It would be good if PyType_Ready() will check that base class of static type is static.

    @serhiy-storchaka serhiy-storchaka added interpreter-core (Objects, Python, Grammar, and Parser dirs) type-feature A feature request or enhancement labels Jul 26, 2014
    @pitrou
    Copy link
    Member

    pitrou commented Jul 27, 2014

    By static, you mean not a heap type?

    @alex
    Copy link
    Member

    alex commented Jul 27, 2014

    Yup.

    @serhiy-storchaka
    Copy link
    Member Author

    By static, you mean not a heap type?

    Yes. Sorry for bad wording.

    @serhiy-storchaka
    Copy link
    Member Author

    Here is a patch.

    @serhiy-storchaka
    Copy link
    Member Author

    Could anyone please make a review?

    @serhiy-storchaka
    Copy link
    Member Author

    Ping.

    @python-dev
    Copy link
    Mannequin

    python-dev mannequin commented Jan 28, 2015

    New changeset c087ac6fc171 by Serhiy Storchaka in branch '2.7':
    Issue bpo-22079: PyType_Ready() now checks that statically allocated type has
    https://hg.python.org/cpython/rev/c087ac6fc171

    New changeset 747855f29b9d by Serhiy Storchaka in branch '3.4':
    Issue bpo-22079: PyType_Ready() now checks that statically allocated type has
    https://hg.python.org/cpython/rev/747855f29b9d

    New changeset eb26255e11f1 by Serhiy Storchaka in branch 'default':
    Issue bpo-22079: PyType_Ready() now checks that statically allocated type has
    https://hg.python.org/cpython/rev/eb26255e11f1

    @doko42
    Copy link
    Member

    doko42 commented Feb 27, 2015

    reopening, this breaks some stuff in several places ...

    https://bugs.launchpad.net/ubuntu/+source/terminator/+bug/1426294

    @doko42 doko42 reopened this Feb 27, 2015
    @serhiy-storchaka
    Copy link
    Member Author

    This restriction was added because bad thing could happen when statically allocated class inherits dynamically allocated class. I don't remember the number of the issue where such example was exposed, may be Alex remember it.

    Likely pygobject creates classes in not safe manner. It would be more correct to create pygobject classes with PyType_FromSpec(), but current code worked for it for years. May be it is not so easy to change pygobject. So may be we should revert changes in 2.7 or convert the error to the deprecation warning.

    Is there similar issue with 3.4? There may be difference due to the difference of the lifetime of types in 2.x and 3.x.

    @python-dev
    Copy link
    Mannequin

    python-dev mannequin commented Mar 22, 2015

    New changeset aa79a04e9bf5 by Serhiy Storchaka in branch '2.7':
    Issue bpo-22079: Py3k warning now is issued in PyType_Ready() instead of
    https://hg.python.org/cpython/rev/aa79a04e9bf5

    New changeset 57a457ea84e4 by Serhiy Storchaka in branch '3.4':
    Issue bpo-22079: Deprecation warning now is issued in PyType_Ready() instead of
    https://hg.python.org/cpython/rev/57a457ea84e4

    @zhangyangyu
    Copy link
    Member

    I think we can start from index 1 instead of 0.

    @serhiy-storchaka
    Copy link
    Member Author

    Can you please explain?

    @zhangyangyu
    Copy link
    Member

    In the mro list I think the first is always the type itself which has already been checked to be a statically allocated type if we can touch the loop. Starting from 0 checks it twice and it's not a base either.

    BTW, I don't receive an email from the tracker. :(

    @serhiy-storchaka
    Copy link
    Member Author

    __bases__ != mro()

    @zhangyangyu
    Copy link
    Member

    Of course, I know it. But doesn't the local variable bases refer to mro[1]?

    [1] https://hg.python.org/cpython/file/tip/Objects/typeobject.c#l4900

    @serhiy-storchaka
    Copy link
    Member Author

    Good point! tp_bases should be iterated instead of tp_mro in this check.

    @zhangyangyu
    Copy link
    Member

    I thought that too at first. But if we use __bases__, can we still guarantee that 'all bases of statically allocated type should be statically allocated'? How about its grand bases? Is it possible that a statically allocated type inherit a dynamic type but does not go through PyType_Ready and then be inherited?

    @serhiy-storchaka
    Copy link
    Member Author

    This is interesting question. It looks that base classes (as well as mro classes) may not go through PyType_Ready. There is no even a check that mro() returns only ancestor classes and contains the initial class itself.

    @zhangyangyu
    Copy link
    Member

    Oh yes. The mro list can be customized so we can not even guarantee the type appears at index 0 and object at index n-1. It seems we should still keep what it is now, iterating the whole mro list.

    Sorry that my previous comments seem to be noise. But maybe we can add one comment to clarify that iterating the whole list is needed.

    @jdemeyer
    Copy link
    Contributor

    It would be good if PyType_Ready() will check that base class of static type is static.

    What's the rationale for this change? It's not explained in this bug report nor in the code.

    @pitrou
    Copy link
    Member

    pitrou commented May 12, 2020

    The workaround that Cython had to added for this (temporarily enable Py_TPFLAGS_HEAPTYPE when calling PyType_Ready()) is fragile. It would be nice to rethink the approach here, or disable the check altogether.

    (or perhaps, expose another C API function - such as PyType_ReadyEx() - that allows disabling the check)

    @scoder
    Copy link
    Contributor

    scoder commented May 12, 2020

    Since it's not clear from this ticket what the original problem was, is there a chance it could have been related to bpo-35810?

    @scoder
    Copy link
    Contributor

    scoder commented Apr 20, 2021

    Coming back to this after a while. I would like to get rid of the work-around (read: huge hack) that we have in Cython for this check and thus would ask for the check to be removed in Py3.10.

    According to the discussion, no-one seemed to remember why it was added in the first place, just that "bad things happened", but not what or how.

    With the fix for bpo-35810 in place since Py3.8, my guess is that the situation that this check is preventing has actually become safe now. Unless someone can motivate that the risks were other than a premature deallocation of the base type.

    @vstinner
    Copy link
    Member

    I recently reworked type_new() and PyType_New() in bpo-43770. I wrote documentation for the type_ready_inherit_as_structs() helper function of PyType_Ready():

    // For static types, inherit tp_as_xxx structures from the base class
    // if it's NULL.
    //
    // For heap types, tp_as_xxx structures are not NULL: they are set to the
    // PyHeapTypeObject.as_xxx fields by type_new_alloc().
    static void
    type_ready_inherit_as_structs(PyTypeObject *type, PyTypeObject *base)

    I hesitated to add assertions to ensure that fields are set if the type is a heap type.

    One issue with static type is that it doesn't have the following fields of PyHeapTypeObject:

    PyAsyncMethods as_async;
    PyNumberMethods as_number;
    PyMappingMethods as_mapping;
    PySequenceMethods as_sequence; /* as_sequence comes after as_mapping,
                                      so that the mapping wins when both
                                      the mapping and the sequence define
                                      a given operator (e.g. __getitem__).
                                      see add_operators() in typeobject.c . */
    PyBufferProcs as_buffer;
    

    Is there a reason to not add these fields to PyTypeObject? PyTypeObject is not part of the stable ABI.

    Type inheritance without these fields make PyType_Ready() weird and more complex.

    @encukou
    Copy link
    Member

    encukou commented Jan 24, 2022

    Is there a reason to not add these fields to PyTypeObject?

    Can't say I haven't thought of that, but AFAIK it would mean breaking the C API substantially. Even if not it'd be a PEP-sized change, IMO.

    @ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Labels
    interpreter-core (Objects, Python, Grammar, and Parser dirs) topic-C-API type-feature A feature request or enhancement
    Projects
    None yet
    Development

    No branches or pull requests

    10 participants