You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[3.13] _PyObject_Init() assertion fails with the stable ABI on Python built with assertions (extension built with Python 3.11) #121528
The general impression I get from wjakob/nanobind#500 is that Py_INCREF is part of the limited API but is not explicitly listed due to tooling limitations. As a macro, it does not feature at the ABI level but its implementation does. Prior to 3.12, the implementation modified object reference counts directly. On 3.12 and later, the limited API implementation calls the private function _Py_IncRef.
The general impression I get from wjakob/nanobind#500 is that Py_INCREF is part of the limited API but is not explicitly listed due to tooling limitations. As a macro, it does not feature at the ABI level but its implementation does. Prior to 3.12, the implementation modified object reference counts directly.
Yes, this is implemented as a Limit API/Stable ABI but actually it's not(can't guarantee the behavior and inlined). I'm not sure we should open a new discussion about this.
Without Py_LIMITED_API defined, some C API functions are inlined or replaced by macros. Defining Py_LIMITED_API disables this inlining, allowing stability as Python’s data structures are improved, but possibly reducing performance.
In the limited C API version 3.12 and newer, Py_INCREF() is now implemented as a function call. You can build your C extension with Python 3.12 and the binary should work on Python 3.11 unless you use features specific to Python 3.12. Moreover, the binary (.abi3.so shared library) should work on Python 3.12 and newer.
In the limited C API version 3.12 and newer, Py_INCREF() is now implemented as a function call. You can build your C extension with Python 3.12 and the binary should work on Python 3.11 unless you use features specific to Python 3.12. Moreover, the binary (.abi3.so shared library) should work on Python 3.12 and newer.
Yes, the problem is the code which is using Py_INCREF and is compiled based on the Python < 3.12 for stable ABI can not be loaded in Python 3.13.
But I think here's another core problem we change the way that we treat the object which is not in the heap and is not immortal object(From just check it to refuse the object by crashing process. I'm not sure this is a correct way.
We're building --with-assertions on Gentoo, as noted in the first comment of this thread.
The problem right now is that all current versions of PyO3 produce "broken" extensions, and it will take some time before packages update to the very newest version that fixes this, and every single package published on PyPI before that happens will remain broken.
Reacted by Victor Stinner and Ellen Emilia Anna Zscheile
changed the title [-][3.13] _PyObject_Init() assertion fails on a debug build with the stable ABI (extension built with Python 3.11)[/-][+][3.13] _PyObject_Init() assertion fails with the stable ABI on Python built with assertions (extension built with Python 3.11)[/+]on Jul 13, 2024
Activity
Zheaoli commentedon Jul 9, 2024
The issue is confirmed, I have found the reason, but I'm not sure this is a bug, I prefer its undefined behavior.
It's caused by the
Py_INCREFdifferent behavior between 3.11 and 3.13(or master)TL;DR;
For the 3.11 version of the
Py_INCREF, we add the reference count directly without check FYI https://github.com/python/cpython/blob/3.11/Include/object.h#L491-L504For the 3.13 version of the
Py_INCREF, we add the reference count and check if it exceeds. If it exceeds, this means that this is an immortal object, we do noting except return the function. FYI https://github.com/python/cpython/blob/3.13/Include/object.h#L796-L846And the function is an inline function, which is means we will expand the function into the binary during the compile. So in 3.11 version, the
PyExc_TypeError's reference count is change from 4294967295(the immortal flag) to 4294967296. And the process will fail here https://github.com/python/cpython/pull/116115/files#diff-2a12f738a77b362d74a65949b58c37f2affcd15ba8b1c979b63bd00223b8a456R268We can compare the assemble code to prove it
For 3.11
For 3.13
The patch to fix this issue is simple ,we just the code back
I'm not sure this patch has side effect or not. I may need @markshannon help
Zheaoli commentedon Jul 10, 2024
I setup a new disscussion here https://discuss.python.org/t/disable-the-inline-by-default-for-the-function-api-which-is-included-in-the-stable-abi/57832
Zheaoli commentedon Jul 10, 2024
After dive more deeper, I think maybe its the user code issue.
I think you use
Py_INCREFinstead ofPy_IncRef,Py_INCREFis not part of the stable ABI.If you use the
Py_IncRefI think the code here would be not existeddavidhewitt commentedon Jul 10, 2024
The general impression I get from wjakob/nanobind#500 is that
Py_INCREFis part of the limited API but is not explicitly listed due to tooling limitations. As a macro, it does not feature at the ABI level but its implementation does. Prior to 3.12, the implementation modified object reference counts directly. On 3.12 and later, the limited API implementation calls the private function_Py_IncRef.Zheaoli commentedon Jul 10, 2024
Yes, this is implemented as a Limit API/Stable ABI but actually it's not(can't guarantee the behavior and inlined). I'm not sure we should open a new discussion about this.
https://docs.python.org/3/c-api/stable.html#limited-api-scope-and-performance
Zheaoli commentedon Jul 13, 2024
I think we might need a core to decide this issue should be fixed or not
@vstinner @Fidget-Spinner @markshannon @brettcannon
alex commentedon Jul 13, 2024
It seems like this will break a large number of existing extensions if it's not resolved.
If the decision is not to fix this, then CPython needs to not load abi3 .sos that are impacted.
vstinner commentedon Jul 13, 2024
In the limited C API version 3.12 and newer, Py_INCREF() is now implemented as a function call. You can build your C extension with Python 3.12 and the binary should work on Python 3.11 unless you use features specific to Python 3.12. Moreover, the binary (.abi3.so shared library) should work on Python 3.12 and newer.
Example.
setup.py
Build:
It works on Python 3.11, 3.12, 3.13:
It works even on Python 3.6:
alex commentedon Jul 13, 2024
My concern is primarily for the existing abi3 wheels on PyPI. The whole point is that maintainers could publish them and they'd continue to work.
vstinner commentedon Jul 13, 2024
Zheaoli commentedon Jul 13, 2024
Yes, the problem is the code which is using
Py_INCREFand is compiled based on the Python < 3.12 for stable ABI can not be loaded in Python 3.13.I'm not sure we should fix this or not.
vstinner commentedon Jul 13, 2024
PEP 683 promises to not break the backward compatibility for the stable ABI, but the implementation doesn't seem to be fully compatible.
The problem is that _Py_IsImmortal() checks exactly if ref count is equal to _Py_IMMORTAL_REFCNT (refcnt == _Py_IMMORTAL_REFCNT).
This problem remains me the commit 5f6ac2d of the PR gh-112174.
Zheaoli commentedon Jul 13, 2024
Yes, I have mentioned this at here #121528 (comment)
But I think here's another core problem we change the way that we treat the object which is not in the heap and is not immortal object(From
just check ittorefuse the object by crashing process. I'm not sure this is a correct way.Zheaoli commentedon Jul 13, 2024
Sorry, I'm a little confused about the commit you mentioned because I'm not familiar with free threading. Would you mind give more detail here?
5 remaining items
vstinner commentedon Jul 13, 2024
To check if you're using a debug build, you can check:
I cannot reproduce the issue with a release build.
vstinner commentedon Jul 13, 2024
The following code is a reference leak, you don't have to INCREF the TypeError exception:
You should just:
Zheaoli commentedon Jul 13, 2024
Weird, I can't reproduce this in non-debug build now. Sorry for the previous reply, maybe I mix up something
mgorny commentedon Jul 13, 2024
We're building
--with-assertionson Gentoo, as noted in the first comment of this thread.The problem right now is that all current versions of PyO3 produce "broken" extensions, and it will take some time before packages update to the very newest version that fixes this, and every single package published on PyPI before that happens will remain broken.
[-][3.13] _PyObject_Init() assertion fails on a debug build with the stable ABI (extension built with Python 3.11)[/-][+][3.13] _PyObject_Init() assertion fails with the stable ABI on Python built with assertions (extension built with Python 3.11)[/+]pythongh-121528: Fix _PyObject_Init() assertion for stable ABI
pythongh-121528: Fix _PyObject_Init() assertion for stable ABI
vstinner commentedon Jul 13, 2024
I wrote PR gh-121725 to fix the assertion. I'm not sure if it's correct. It's an heuristic.
pythongh-121528: Fix _PyObject_Init() assertion for stable ABI
gh-121528: Fix _PyObject_Init() assertion for stable ABI (#121725)
pythongh-121528: Fix _PyObject_Init() assertion for stable ABI (pytho…
vstinner commentedon Jul 17, 2024
Fixed by change b826e45 in the main branch. A backport will follow in the 3.13 branch.
Thanks for the bug report @mgorny. Thanks everyone who helped to analyze the root cause.
[3.13] gh-121528: Fix _PyObject_Init() assertion for stable ABI (GH-1…
[3.12] pythongh-121528: Add _Py_IsImmortalLoose() function for assert…