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
Binary (windows?) wheels for 3.15 are probably incompatible with newly-released 3.15b4; ~perhaps a 3.15b4 incompatibility in general~ #263
There is some additional information. Even, after I started building CFFI from scratch on mac/linux (pip install --no-binary=:all: cffi), (EDIT: I think I must still have been using the pre-built wheel) I was seeing one crash on 3.15 that appears related to CFFI. That's the only test I had that uses CFFI (the Windows tests all use CFFI), and when I disabled that test, the crashes went away, so I think we can rule out gevent or 3.15b4 itself.
Are you set up to run your tests under a debugger on those platforms? Typically that kind of issue crops up when an application's cffi-allocated variable is not held in the interpreter and the GC collects the buffer while something else is accessing that buffer. It would help if you could cut the failure down to a small reproducer.
I can reproduce one of the smaller crashes I saw locally on macOS (I have no access to Windows). Using the pre-built PyPI wheel on 3.15b4, lldb python -m gevent.tests.test__core crashes like so:
changed the title [-]Binary (windows?) wheels for 3.15 are probably incompatible with newly-released 3.15b4; perhaps a 3.15b4 incompatibility in general[/-][+]Binary (windows?) wheels for 3.15 are probably incompatible with newly-released 3.15b4; ~perhaps a 3.15b4 incompatibility in general~[/+]on Jul 22, 2026
I can take greenlet and most of gevent out of the equation altogether; once again, this crashes with the pre-built wheel and works with the built-from-source wheel.
importgeventgevent.config.loop='libuv-cffi'loop=gevent.get_hub().loop# uses the libuv CFFI interface to libuvio=loop.io(1, 1)
io.start(lambda*_: None)
loop.run() # libuv.uv_run
Interesting that the crash is around the GIL handling. I would expect there to be some difference in the include files that could influence this: some macro or struct change. But $ git diff v3.15.0b4 v3.15.0b3 Include/ did not point out anything obvious except for an additional field in _Py_DebugOffsets, an internal struct that I would be surprised that cffi touches.
Ahh, _PyRun_AnyFile changed, it now returns a PyObject* and not an int. But that does not come from cffi, it comes from somewhere else. So perhaps by using a cffi source build, something else in the build changes?
The PyThreadState (struct _ts) also changed size, it grew uintptr_t last_profiled_frame_seq in 3.15b4 (that's the change you noticed in Py_DebugOffsets as well). But that should be an opaque object, always handled as PyThreadState*, never directly allocated or sizeof() or anything like that, and I don't see anywhere that cffi is reading or writing directly to PyThreadState fields. But because that's the argument to PyEval_RestoreThread I'm suspicious of that change.
If everyone's reasonably confident it's only the ABI change and that just re-spinning the wheels against b4 is sufficient, I can probably do that this morning. I might try to tweak the requires-python constraint to block 3.15.0a0-3.15.0b3, since I'm guessing the offending ABI change could be equally fatal in reverse.
@nitzmahone I think the answer is "no, barring a late-breaking bug that justifies an ABI break". So, hopefully not?
I still think it'd be worth doing a new bugfix release for this to help unblock downstream projects that depend on CFFI who want to set up Python 3.15 testing. But I also understand your time and attention is limited and I very much appreciate you spending time on this.
I still think it'd be worth doing a new bugfix release
Oh, no argument there- I'll be pushing rebuilt wheels for b4+ support regardless. Just wanted to make sure there was reasonable confidence that no code changes are required before I do that.
Thanks for the small standalone repro BTW!
I've hit similar situations before on other projects where it's only a packaging issue with literally zero code change, but it's been awhile. In former lives, I'd just manually publish new wheels as 2.1.0.post1 or something, but with all the supply-chain security bots already looking sideways at us for not using attested publishing (hoping to wait for GHA's lockfile feature to land first), not having a matching upstream release + tag would probably cause more trouble than just shipping a full 2.1.1: "same as 2.1.0, now with less stack corruption in 3.15 wheels!" release 🤷 . That's probably what I'll end up doing.
See #269. There's still one direct PyThreadState access left after that PR but it can't be deleted yet and it's not in a public API so it's less of a problem.
I'll do some CI spot-checks against older Pythons (looks like "oldest-supported" == 3.9 fell out of the PR matrix at some point, which was unintentional), but assuming all's good, I'll merge that and do a 2.1.1 release. I'm always leery about doing late-in-week releases, so might hold up the actual build and push until Monday morning since I'd be unavailable to address any issues until then anyway.
Activity
mattip commentedon Jul 22, 2026
Are you set up to run your tests under a debugger on those platforms? Typically that kind of issue crops up when an application's cffi-allocated variable is not held in the interpreter and the GC collects the buffer while something else is accessing that buffer. It would help if you could cut the failure down to a small reproducer.
jamadden commentedon Jul 22, 2026
I can reproduce one of the smaller crashes I saw locally on macOS (I have no access to Windows). Using the pre-built PyPI wheel on 3.15b4,
lldb python -m gevent.tests.test__corecrashes like so:If I manually build CFFI from source, the test passes fine.
I can boil that test case down to a simpler script:
This too crashes in the same way with the pre-built CFFI wheel, and works correctly with a newly locally built wheel:
I'm happy to try to provide any other helpful information.
[-]Binary (windows?) wheels for 3.15 are probably incompatible with newly-released 3.15b4; perhaps a 3.15b4 incompatibility in general[/-][+]Binary (windows?) wheels for 3.15 are probably incompatible with newly-released 3.15b4; ~perhaps a 3.15b4 incompatibility in general~[/+]jamadden commentedon Jul 22, 2026
I can take greenlet and most of gevent out of the equation altogether; once again, this crashes with the pre-built wheel and works with the built-from-source wheel.
mattip commentedon Jul 22, 2026
Interesting that the crash is around the GIL handling. I would expect there to be some difference in the include files that could influence this: some macro or struct change. But
$ git diff v3.15.0b4 v3.15.0b3 Include/did not point out anything obvious except for an additional field in_Py_DebugOffsets, an internal struct that I would be surprised that cffi touches.mattip commentedon Jul 22, 2026
Ahh,
_PyRun_AnyFilechanged, it now returns aPyObject*and not anint. But that does not come from cffi, it comes from somewhere else. So perhaps by using a cffi source build, something else in the build changes?jamadden commentedon Jul 22, 2026
The
PyThreadState(struct _ts) also changed size, it grewuintptr_t last_profiled_frame_seqin 3.15b4 (that's the change you noticed inPy_DebugOffsetsas well). But that should be an opaque object, always handled asPyThreadState*, never directly allocated orsizeof()or anything like that, and I don't see anywhere that cffi is reading or writing directly toPyThreadStatefields. But because that's the argument toPyEval_RestoreThreadI'm suspicious of that change.ngoldbaum commentedon Jul 28, 2026
There was an ABI break from b3 to b4: python/cpython#152448.
Fixing this probably requires uploading new CFFI wheels for Python 3.15, which might necessitate doing a new release.
Revert "Test Python 3.15 where a beta can say something"
ngoldbaum commentedon Jul 30, 2026
@nitzmahone do you think you'll have time soonish to coordinate a release to help with this? I know @mattip will be away for a while too.
nitzmahone commentedon Jul 30, 2026
If everyone's reasonably confident it's only the ABI change and that just re-spinning the wheels against b4 is sufficient, I can probably do that this morning. I might try to tweak the
requires-pythonconstraint to block 3.15.0a0-3.15.0b3, since I'm guessing the offending ABI change could be equally fatal in reverse.ngoldbaum commentedon Jul 30, 2026
I'll ask about that on the core dev discord
ngoldbaum commentedon Jul 30, 2026
Here's a pure-CFFI reproducer, which crashes for me on 3.15.0b4 using the CFFI wheel on PyPI
ngoldbaum commentedon Jul 30, 2026
@nitzmahone I think the answer is "no, barring a late-breaking bug that justifies an ABI break". So, hopefully not?
I still think it'd be worth doing a new bugfix release for this to help unblock downstream projects that depend on CFFI who want to set up Python 3.15 testing. But I also understand your time and attention is limited and I very much appreciate you spending time on this.
nitzmahone commentedon Jul 30, 2026
Oh, no argument there- I'll be pushing rebuilt wheels for b4+ support regardless. Just wanted to make sure there was reasonable confidence that no code changes are required before I do that.
Thanks for the small standalone repro BTW!
I've hit similar situations before on other projects where it's only a packaging issue with literally zero code change, but it's been awhile. In former lives, I'd just manually publish new wheels as
2.1.0.post1or something, but with all the supply-chain security bots already looking sideways at us for not using attested publishing (hoping to wait for GHA's lockfile feature to land first), not having a matching upstream release + tag would probably cause more trouble than just shipping a full 2.1.1: "same as 2.1.0, now with less stack corruption in 3.15 wheels!" release 🤷 . That's probably what I'll end up doing.ngoldbaum commentedon Jul 30, 2026
I think I actually have a way to use Python C API calls alone to avoid the fragile direct struct access entirely, PR incoming.
ngoldbaum commentedon Jul 30, 2026
See #269. There's still one direct PyThreadState access left after that PR but it can't be deleted yet and it's not in a public API so it's less of a problem.
nitzmahone commentedon Jul 30, 2026
I'll do some CI spot-checks against older Pythons (looks like "oldest-supported" == 3.9 fell out of the PR matrix at some point, which was unintentional), but assuming all's good, I'll merge that and do a 2.1.1 release. I'm always leery about doing late-in-week releases, so might hold up the actual build and push until Monday morning since I'd be unavailable to address any issues until then anyway.
ngoldbaum commentedon Jul 30, 2026
That's fine with me. This is worth fixing but given that 3.15 is still a prerelease it's not a fire or anything like that.
Release 0.7.1: complete the binding surface, the test suite, and the …
A5rocks commentedon Aug 2, 2026
I ran into this on Windows, macOS, Ubuntu. Also, it appears cffi 2.0.0 is immune! Surprising. (For now I'll just stick with cffi 2.0.0...)
nitzmahone commentedon Aug 3, 2026
fixed by #269 in 2.1.1