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

[C API] Avoid accessing PyObject and PyVarObject members directly: add Py_SET_TYPE() and Py_IS_TYPE(), disallow Py_TYPE(obj)=type #83754

Closed
vstinner opened this issue Feb 6, 2020 · 96 comments
Labels
3.11 only security fixes topic-C-API

Comments

@vstinner
Copy link
Member

vstinner commented Feb 6, 2020

BPO 39573
Nosy @vstinner
PRs
  • bpo-39573: Use Py_REFCNT() macro #18388
  • bpo-39573: Add Py_SET_REFCNT() function #18389
  • bpo-39573: Use Py_TYPE() in abstract.c #18390
  • bpo-39573: Use Py_TYPE() macro in Python and Include directories #18391
  • bpo-39573: Use Py_TYPE() macro in Objects directory #18392
  • bpo-39573: Use Py_TYPE() macro in Modules directory #18393
  • bpo-39573: Add Py_SET_TYPE() function #18394
  • bpo-39573: Use Py_TYPE() macro in object.c #18398
  • bpo-39573: Add Py_SET_SIZE() function #18400
  • bpo-39573: Use Py_SET_SIZE() function #18402
  • bpo-39573: Use Py_TYPE() macro in ctypes.h #18411
  • bpo-39573: Use Py_SIZE() in s_set() of cfield.c #18419
  • bpo-39573: Add Py_IS_TYPE macro #18488
  • bpo-39573: Fix bad copy-paste in Py_SET_SIZE. #18496
  • bpo-39573: Update clinic to use Py_IS_TYPE macro #18507
  • bpo-39573: Update Include/* to use Py_IS_TYPE #18508
  • bpo-39573: Clean up modules and headers to use Py_IS_TYPE #18521
  • bpo-39573: Finish converting to new Py_IS_TYPE macro. #18601
  • bpo-39573: Use Py_IS_TYPE for type checking #18789
  • bpo-39573: Use Py_IS_TYPE for negative type checks #18798
  • bpo-39573: Make Py_IS_TYPE take const args. Add _PyObject_CAST_CONST. #18799
  • bpo-39873: PyObject_Init() uses PyObject_INIT() #18804
  • bpo-39573: Use Py_IS_TYPE to check for types #18809
  • bpo-39573: Use Py_IS_TYPE to check for types #19882
  • bpo-30459: Cast the result of PyList_SET_ITEM() to void #19975
  • bpo-39573: Convert Py_TYPE() to a static inline function #20290
  • bpo-39573: Fix buildbot failure for tupleobject.c #20391
  • bpo-39573: Convert Py_REFCNT and Py_SIZE to functions #20429
  • bpo-39573: Porting to Python 3.10: Py_SET_SIZE() macro #20610
  • [WIP, DO NOT MERGE] bpo-41188: Prepare CPython for opague PyObject structure. #21262
  • bpo-39573: Use the Py_TYPE() macro #21433
  • bpo-39573: Convert Py_TYPE() and Py_SIZE() back to macros #23366
  • bpo-39573: Remove What's new entry for Py_SIZE() #23375
  • bpo-39573: Py_TYPE becomes a static inline function #26493
  • bpo-11105: use a lower recursion limit for infinite recursion tests #26550
  • bpo-44348: Revert "bpo-39573: Py_TYPE becomes a static inline function (GH-26493)" #26596
  • bpo-39573: Py_TYPE becomes a static inline function #28128
  • 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 = None
    closed_at = <Date 2021-09-08.16:32:15.871>
    created_at = <Date 2020-02-06.23:07:12.131>
    labels = ['expert-C-API', '3.11']
    title = '[C API] Avoid accessing PyObject and PyVarObject members directly: add Py_SET_TYPE() and Py_IS_TYPE(), disallow Py_TYPE(obj)=type'
    updated_at = <Date 2022-01-20.00:24:00.180>
    user = 'https://github.com/vstinner'

    bugs.python.org fields:

    activity = <Date 2022-01-20.00:24:00.180>
    actor = 'vstinner'
    assignee = 'none'
    closed = True
    closed_date = <Date 2021-09-08.16:32:15.871>
    closer = 'vstinner'
    components = ['C API']
    creation = <Date 2020-02-06.23:07:12.131>
    creator = 'vstinner'
    dependencies = []
    files = []
    hgrepos = []
    issue_num = 39573
    keywords = ['patch']
    message_count = 96.0
    messages = ['361513', '361514', '361515', '361516', '361517', '361518', '361519', '361522', '361523', '361526', '361527', '361529', '361531', '361540', '361549', '361555', '361557', '361590', '361593', '361607', '361611', '361626', '361631', '361639', '361904', '361960', '361961', '361963', '361964', '361965', '361971', '361977', '361987', '361988', '362033', '362034', '362133', '362134', '362166', '362212', '362216', '362445', '363345', '363494', '363564', '365690', '366473', '366493', '368047', '369896', '369898', '370074', '370303', '370638', '370663', '370665', '370666', '370671', '370729', '370902', '370932', '372308', '373460', '379675', '379679', '379680', '379757', '379759', '381337', '381345', '381365', '381374', '381403', '381404', '382260', '382534', '382539', '382780', '382781', '382783', '394954', '394971', '395018', '395205', '395206', '395287', '395323', '395536', '401365', '401370', '401378', '401395', '401396', '401399', '403252', '410995']
    nosy_count = 1.0
    nosy_names = ['vstinner']
    pr_nums = ['18388', '18389', '18390', '18391', '18392', '18393', '18394', '18398', '18400', '18402', '18411', '18419', '18488', '18496', '18507', '18508', '18521', '18601', '18789', '18798', '18799', '18804', '18809', '19882', '19975', '20290', '20391', '20429', '20610', '21262', '21433', '23366', '23375', '26493', '26550', '26596', '28128']
    priority = 'normal'
    resolution = 'fixed'
    stage = 'resolved'
    status = 'closed'
    superseder = None
    type = None
    url = 'https://bugs.python.org/issue39573'
    versions = ['Python 3.11']

    Linked PRs

    @vstinner
    Copy link
    Member Author

    vstinner commented Feb 6, 2020

    Today, CPython is leaking too many implementation through its public C API. We cannot easily change the "default" C API, but we can enhance the "limited" C API (when Py_LIMITED_API macro is defined). Example of leaking implementation details: memory allocator, garbage collector, structure layouts, etc.

    Making PyObject an opaque structure would allow in the long term of modify structures to implement more efficient types (ex: list specialized for small integers), and it can prepare CPython to experiment tagged pointers.

    Longer rationale:

    I propose to incremental evolve the existing limited C API towards opaque PyObject, by trying to reduce the risk of breakage.

    We may test changes on PyQt which uses the limited C API.

    Another idea would be to convert some C extensions of the standard library to the limited C API. It would ensure that the limited C API contains enough functions to be useful, but would also notify us directly if the API is broken.

    @vstinner vstinner added 3.9 only security fixes topic-C-API labels Feb 6, 2020
    @vstinner
    Copy link
    Member Author

    vstinner commented Feb 6, 2020

    Another idea would be to convert some C extensions of the standard library to the limited C API. It would ensure that the limited C API contains enough functions to be useful, but would also notify us directly if the API is broken.

    First issues that I met when I tried that:

    • C code generated by Argument Clinic is incompatible the limited C API: METH_FASTCALL, _PyArg_CheckPositional(), static _PyArg_Parser, etc. are excluded from the limited C API.
    • PyTypeObject is opaque and so it's not possible to implement a deallocator function (tp_dealloc) which calls tp_free like:
      Py_TYPE(self)->tp_free((PyObject*)self);
    • _Py_IDENTIFIER() is not part of the limited C API

    @vstinner
    Copy link
    Member Author

    vstinner commented Feb 6, 2020

    New changeset a93c51e by Victor Stinner in branch 'master':
    bpo-39573: Use Py_REFCNT() macro (GH-18388)
    a93c51e

    @vstinner
    Copy link
    Member Author

    vstinner commented Feb 7, 2020

    @vstinner
    Copy link
    Member Author

    vstinner commented Feb 7, 2020

    In the limited C API, Py_REFCNT() should be converted to:

    static inline Py_ssize_t _Py_REFCNT(const PyObject *ob)
    { return ob->ob_refcnt; }
    #define Py_REFCNT(ob) _Py_REFCNT(_PyObject_CAST(ob))

    It would enforce the usage of newly added Py_SET_REFCNT() (PR 18389) and advertise that the object is not modified (const).

    That would only be the first step towards a really opaque Py_REFCNT() function.

    @vstinner
    Copy link
    Member Author

    vstinner commented Feb 7, 2020

    TODO: Add Py_IS_TYPE() macro:

    #define Py_IS_TYPE(ob, tp) (Py_TYPE(ob) == (tp)) 

    For example, replace:

        #define PyBool_Check(x) (Py_TYPE(x) == &PyBool_Type) 

    with:

        #define PyBool_Check(x) Py_IS_TYPE(x, &PyBool_Type)

    IMHO it makes the code more readable.

    nascheme@c156300

    @vstinner
    Copy link
    Member Author

    vstinner commented Feb 7, 2020

    New changeset c86a112 by Victor Stinner in branch 'master':
    bpo-39573: Add Py_SET_REFCNT() function (GH-18389)
    c86a112

    @vstinner
    Copy link
    Member Author

    vstinner commented Feb 7, 2020

    New changeset 0d76d2b by Victor Stinner in branch 'master':
    bpo-39573: Use Py_TYPE() in abstract.c (GH-18390)
    0d76d2b

    @vstinner
    Copy link
    Member Author

    vstinner commented Feb 7, 2020

    Py_TYPE() is commonly used to render the type name in an error message. Example:

    PyErr_Format(PyExc_TypeError,
                 "cannot convert '%.200s' object to bytearray",
                 Py_TYPE(arg)->tp_name);

    This code has multiple issues:

    • It truncates type name to 200 characters: there is no Python exception, not even a marker to indicate that the string has been truncated
    • It's only the short name: the qualified name (tp_qualname) would be more helpful. The best would be to generate the fully qualified name: module + qualname.
    • Py_TYPE() returns a borrowed reference which is causing multiple issues: https://pythoncapi.readthedocs.io/bad_api.html#borrowed-references

    In September 2018, I created bpo-34595: "PyUnicode_FromFormat(): add %T format for an object type name". But there was disagreement, so I rejected my change.

    I started "bpo-34595: How to format a type name?" thread on python-dev:

    I didn't continue this work (until now), since it wasn't my priority.

    @vstinner
    Copy link
    Member Author

    vstinner commented Feb 7, 2020

    New changeset a102ed7 by Victor Stinner in branch 'master':
    bpo-39573: Use Py_TYPE() macro in Python and Include directories (GH-18391)
    a102ed7

    @vstinner
    Copy link
    Member Author

    vstinner commented Feb 7, 2020

    Make PyObject an opaque structure is also a first step towards the more ambitious project "HPy" project which is fully opaque:
    https://github.com/pyhandle/hpy

    This API is written from scratch and currently implemented on top on the existing C API.

    The following article is a nice introduction to the overall idea:
    https://morepypy.blogspot.com/2019/12/hpy-kick-off-sprint-report.html

    From my point of view, the long term goal would be to get better performance on PyPy and having a single API for C extension which would be efficient on all Python implementations (not only CPython).

    Currently, the C API is not only a performance issue to run C extensions on PyPy. It's also an issue in CPython. Because the C API leaks too many implementation details, we cannot experiment optimizations.

    See also: https://pythoncapi.readthedocs.io/rationale.html

    @vstinner
    Copy link
    Member Author

    vstinner commented Feb 7, 2020

    New changeset 58ac700 by Victor Stinner in branch 'master':
    bpo-39573: Use Py_TYPE() macro in Objects directory (GH-18392)
    58ac700

    @vstinner
    Copy link
    Member Author

    vstinner commented Feb 7, 2020

    New changeset daa9756 by Victor Stinner in branch 'master':
    bpo-39573: Use Py_TYPE() macro in Modules directory (GH-18393)
    daa9756

    @vstinner
    Copy link
    Member Author

    vstinner commented Feb 7, 2020

    New changeset d2ec81a by Victor Stinner in branch 'master':
    bpo-39573: Add Py_SET_TYPE() function (GH-18394)
    d2ec81a

    @vstinner
    Copy link
    Member Author

    vstinner commented Feb 7, 2020

    To make PyObject opaque, we would have to convert Py_INCREF() and Py_DECREF() to opaque function calls. Example:

    #define Py_XINCREF(op) Py_IncRef(op)
    #define Py_XDECREF(op) Py_DecRef(op)

    Benchmarks should be run to measure to overhead and balance the advantages and drawbacks.

    @vstinner
    Copy link
    Member Author

    vstinner commented Feb 7, 2020

    Would a Py_TYPE_IS() macro help code readability?

    For example:
        #define Future_CheckExact(obj) (Py_TYPE(obj) == &FutureType)
    would become:
        #define Future_CheckExact(obj) (Py_TYPE_IS(obj, &FutureType))

    Py_TYPE_IS() would be more efficient for tagged pointers.

    I'm not sure about the macro name. Neil used Py_IS_TYPE(obj, type).

    Note: Py_TYPE_EQ(obj, type) name sounds confusing since the first parameter is an object, whereas the second one is a type.

    @vstinner
    Copy link
    Member Author

    vstinner commented Feb 7, 2020

    New changeset c65b320 by Victor Stinner in branch 'master':
    bpo-39573: Use Py_TYPE() macro in object.c (GH-18398)
    c65b320

    @vstinner
    Copy link
    Member Author

    vstinner commented Feb 7, 2020

    New changeset b10dc3e by Victor Stinner in branch 'master':
    bpo-39573: Add Py_SET_SIZE() function (GH-18400)
    b10dc3e

    @serhiy-storchaka
    Copy link
    Member

    You have merged so much PRs today. What they do?

    PyObject cannot just be made an opaque structure. The user code reads and writes its fields directly and via macros. This change would break working code.

    We can encourage the user code to prepare to making PyObject an opaque structure. We need to provide a stable C API for access of PyObject fields for this. Note that there is a performance penalty of using functions instead of direct access, so you should have very good reasons to do this.

    @vstinner
    Copy link
    Member Author

    vstinner commented Feb 7, 2020

    You have merged so much PRs today. What they do?

    I merged changes which prepares CPython code base to make PyObject opaque. I only merged changes which should have no impact on performance, but prepare the API to make the structure opaque.

    Right now, Py_SET_REFNCT() stills access directly to PyObject.ob_refcnt. But it becomes possible to make Py_SET_REFNCT() an opaque function call.

    Do you see any issue with the changes that I already merged? Using PGO+LTO, static inline functions should be as efficient as the previous code using Py_REFCNT() & cie macros.

    PyObject cannot just be made an opaque structure. The user code reads and writes its fields directly and via macros. This change would break working code.

    I'm trying to modifying the limited C API to make it possible: all access to PyObject fields should go through macros or function calls. The question is now how which fields are accessed and how.

    We can encourage the user code to prepare to making PyObject an opaque structure. We need to provide a stable C API for access of PyObject fields for this.

    For the short term, I don't plan to make PyObject opaque, so I don't plan to enforce usage of Py_TYPE(), Py_SET_REFCNT(), etc.

    Note that there is a performance penalty of using functions instead of direct access, so you should have very good reasons to do this.

    Yeah, replacing Py_REFCNT() macro with an opaque function call is likely to have an impact on performance. It should be properly measure, I'm well aware of that, I already wrote it in a previous comment ;-) I don't plan to push change such right now. And I will wait for the review of my peers (like you) for such change ;-)

    @vstinner
    Copy link
    Member Author

    vstinner commented Feb 7, 2020

    New changeset 60ac6ed by Victor Stinner in branch 'master':
    bpo-39573: Use Py_SET_SIZE() function (GH-18402)
    60ac6ed

    @zooba
    Copy link
    Member

    zooba commented Feb 8, 2020

    "static inline" functions are not opaque - as they get inlined into 3rd-party compiled code, we can't change anything they reference, and so the structure layout is still fixed and has to be visible to the user's compiler.

    I'm not totally against the changes, but it's worth pointing out that you aren't achieving what the issue title claims, so it's really just code cleanliness (and/or introducing macro-users to static inline functions ;) ).

    @vstinner
    Copy link
    Member Author

    vstinner commented Feb 8, 2020

    "static inline" functions are not opaque

    I'm well aware of that :-) But once the CPython code base will stop accessing directly PyObject fields directly, it would become possible to experiment changing PyObject layout, at least testing it in CPython.

    First changes are just to prepare the code base to experiment the real change. But as Serhiy pointed out, the second part will have an impact on performance and so should be carefully benchmarked to balance advantages and drawbacks, even if it's only done in the limited C API.

    @vstinner
    Copy link
    Member Author

    vstinner commented Feb 8, 2020

    New changeset 7f6f7ee by Dong-hee Na in branch 'master':
    bpo-39573: Use Py_TYPE() macro in ctypes.h (GH-18411)
    7f6f7ee

    @corona10
    Copy link
    Member

    FYI, I am working on to add Py_IS_TYPE macro. :)

    @shihai1991
    Copy link
    Member

    Hi, guys. Is there value in adding PyNone_Check macro?(_PyNone_Type is not esposed to CAPI directly, so I am not sure about it)
    If the answer is 'yes', i can add it ;)

    @vstinner
    Copy link
    Member Author

    Hi, guys. Is there value in adding PyNone_Check macro?

    "obj == Py_None" is a very common pattern.

    You have check how it is done in HPy: https://github.com/pyhandle/hpy

    See also bpo-39511: "[subinterpreters] Per-interpreter singletons (None, True, False, etc.)".

    @shihai1991
    Copy link
    Member

    "obj == Py_None" is a very common pattern.
    You have check how it is done in HPy: https://github.com/pyhandle/hpy
    See also bpo-39511: "[subinterpreters] Per-interpreter singletons (None, >True, False, etc.)".

    Thanks, I will check it.

    @vstinner
    Copy link
    Member Author

    See also bpo-44378: "Py_IS_TYPE(): cast discards ‘const’ qualifier from pointer target type".

    If Py_TYPE() is converted again to a static inline function which takes a "const PyObject*" type, Py_IS_TYPE() can be modified again at the same time to use Py_TYPE().

    @vstinner
    Copy link
    Member Author

    vstinner commented Sep 8, 2021

    New changeset cb15afc by Victor Stinner in branch 'main':
    bpo-39573: Py_TYPE becomes a static inline function (GH-28128)
    cb15afc

    @vstinner
    Copy link
    Member Author

    vstinner commented Sep 8, 2021

    @vstinner
    Copy link
    Member Author

    vstinner commented Sep 8, 2021

    At commit cb15afc, I am able to rename PyObject members (to make sure that the structure is not accessed directly), I only had to modify header files:

    • Py_REFCNT(), Py_SET_REFCNT()
    • Py_INCREF(), Py_DECREF()
    • Py_TYPE(), Py_SET_TYPE()
    • Py_IS_TYPE()

    And just two more C files which corner cases:

    --

    I did the same with PyVarObject, rename the ob_size member. I had to modify header files:

    • Py_SIZE(), Py_SET_SIZE()

    But I had to modify the following function of the array module:

    static int
    array_buffer_getbuf(arrayobject *self, Py_buffer *view, int flags)
    {
        ...
        if ((flags & PyBUF_ND)==PyBUF_ND) {
            view->shape = &((PyVarObject*)self)->ob_size;
        }
        ...
        return 0;
    }

    I'm not sure how to patch this function.

    --

    This experience doesn't check usage of sizeof(PyObject) and sizeof(PyVarObject) which would break if these structures become opaque. sizeof() issues are listed in previous comments.

    @vstinner
    Copy link
    Member Author

    vstinner commented Sep 8, 2021

    Oh and obviously, it's not possible possible to define structures which *include* PyObject or PyVarObject if PyObject and PyVarObject become opaque. Example:

    typedef struct {
        PyObject ob_base;
        Py_ssize_t ob_size; /* Number of items in variable part */
    } PyVarObject;

    This C code requires the PyObject structure to be fully defined (not being opaque).

    A new C API and ABI where structures *don't* include PyObject or PyVarObject should be designed to allocate their members "before" the PyObject* pointer value. Something like the current PyGC_Head structure which is excluded from PyObject and stored *before* the "PyObject*" pointer.

    Simplified code which allocates memory for an object implementin the GC protocol:

    static PyObject *
    _PyObject_GC_Malloc(size_t basicsize)
    {
        ...
        size_t size = sizeof(PyGC_Head) + basicsize;
        ...
        PyGC_Head *g = (PyGC_Head *)PyObject_Malloc(size);
        ...
        PyObject *op = (PyObject *)(g + 1);
        return op;
    }

    @vstinner
    Copy link
    Member Author

    vstinner commented Sep 8, 2021

    I changed the issue title to restrict its scope: "[C API] Avoid accessing PyObject and PyVarObject members directly: add Py_SET_TYPE() and Py_IS_TYPE(), disallow Py_TYPE(obj)=type".

    Making PyObject and PyVarObject structures opaque is a broader topic which should be splited into sub-issues.

    "Py_TYPE(obj)=type;" is now disallowed. I consider that the work of this issue is now completed and I close the issue.

    Thanks everyone who help to fix these tedious issues!

    You can continue to use this issue if you need my help to adapt your C extensions to Py_SET_TYPE()/Py_SET_SIZE().

    See also the upgrade_pythoncapi.py script of the pythoncapi_compat project which helps to port your C extensions without losing support for old Python versions:
    https://github.com/pythoncapi/pythoncapi_compat

    See also the Py_TYPE() change announcement on the capi-sig list:
    https://mail.python.org/archives/list/[email protected]/thread/WGRLTHTHC32DQTACPPX36TPR2GLJAFRB/

    @vstinner vstinner added 3.11 only security fixes and removed 3.9 only security fixes labels Sep 8, 2021
    @vstinner vstinner closed this as completed Sep 8, 2021
    @vstinner vstinner changed the title [C API] Make PyObject an opaque structure in the limited C API [C API] Avoid accessing PyObject and PyVarObject members directly: add Py_SET_TYPE() and Py_IS_TYPE(), disallow Py_TYPE(obj)=type Sep 8, 2021
    @vstinner
    Copy link
    Member Author

    vstinner commented Oct 5, 2021

    I wrote an article about these changes:
    https://vstinner.github.io/c-api-abstract-pyobject.html

    It elaborates the rationale for making these changes.

    @vstinner
    Copy link
    Member Author

    @victor, git bisect tells me the change f3fa63e caused test_exceptions.ExceptionTests.test_recursion_in_except_handler to stack overflow only on windows debug builds.

    FYI this regression was handled last year in bpo-44348 "test_exceptions.ExceptionTests.test_recursion_in_except_handler stack overflow on Windows debug builds" and fixed at 2021-09-07 by using the trashcan mecanism in the BaseException deallocator function:

    New changeset fb30509 by Victor Stinner in branch 'main':
    bpo-44348: BaseException deallocator uses trashcan (GH-28190)
    fb30509

    @ezio-melotti ezio-melotti transferred this issue from another repository Apr 10, 2022
    clickworkorange added a commit to clickworkorange/pybluez2 that referenced this issue Apr 19, 2023
    Since Py_TYPE() was changed to an inline static function in PEP670, `Py_TYPE(obj) = new_type` must be replaced with the new function `Py_SET_TYPE(obj, new_type)`, available since Python 3.9. For backward compatibility, this macro can be used:
    ````c++
    #if PY_VERSION_HEX < 0x030900A4 && !defined(Py_SET_TYPE)
    static inline void _Py_SET_TYPE(PyObject *ob, PyTypeObject *type)
    { ob->ob_type = type; }
    #define Py_SET_TYPE(ob, type) _Py_SET_TYPE((PyObject*)(ob), type)
    #endif
    ````
    See python/cpython#83754
    vstinner added a commit to vstinner/cpython that referenced this issue Jun 16, 2024
    Don't access directly PyObject.ob_type, but use the Py_TYPE() macro
    instead.
    vstinner added a commit to vstinner/cpython that referenced this issue Jun 16, 2024
    Don't access directly PyObject.ob_type, but use the Py_TYPE() macro
    instead.
    vstinner added a commit that referenced this issue Jun 17, 2024
    Don't access directly PyObject.ob_type, but use the Py_TYPE() macro
    instead.
    mrahtz pushed a commit to mrahtz/cpython that referenced this issue Jun 30, 2024
    Don't access directly PyObject.ob_type, but use the Py_TYPE() macro
    instead.
    noahbkim pushed a commit to hudson-trading/cpython that referenced this issue Jul 11, 2024
    Don't access directly PyObject.ob_type, but use the Py_TYPE() macro
    instead.
    estyxx pushed a commit to estyxx/cpython that referenced this issue Jul 17, 2024
    Don't access directly PyObject.ob_type, but use the Py_TYPE() macro
    instead.
    Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
    Labels
    3.11 only security fixes topic-C-API
    Projects
    None yet
    Development

    No branches or pull requests

    9 participants