-
-
Notifications
You must be signed in to change notification settings - Fork 30.6k
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
Bug in generator if the generator in created in a temporary C thread #58637
Comments
We have a crash in our product when tracing is enabled by
To reproduce the crash, unpack the attached python setup.py build and then run: PYTHONPATH=$(ls -d build/lib*/) python test.py (or just "python test.py if you installed the _test module). Calling the generator should update its reference to the Python state |
Here's the patch ;-) |
The proposed fix sounds reasonable to me. Would it be possible to work something into test_capi to actually test it? |
It may not even have to specifically test the crash - any operation that accessed the tstate on the frame and could be shown to be accessing the wrong thread state when called from another thread could demonstrate the problem. |
For what it's worth, I think I've seen this bug in 2.6 and 2.5, using generators created in python threads, while profiling not tracing. I'm creating generators in one python thread and storing them in a variable. In a different python thread I overwrite the variable, which garbage collects the generator. Sometimes it causes an interpreter crash. Other times, it seems to trigger a return event in the profiler, but it's associated with an incorrect thread. The thread in question is often (always?) in the profiler code, so it looks like the profiler is profiling itself. |
Rather than ensuring that f_tstate always points to the current frame, Patch attached |
I think I've tripped over a variation on this theme using pyqt and 2.7: When working in a QThread, the PyGILState_Ensure call when transitioning control from Qt to python will frequently allocate a new thread state - because every time control returns to the Qt event loop, gilstate_counter is likely to become zero. If a generator is kept around longer than this, it becomes quite likely to have an older thread state in f_tstate. This happens all the time. The access that blows up on me is PyEval_GetRestricted, since PyFrame_IsRestricted checks f_tstate. Annoyingly this debris is still called on the possibly-restricted operations even when restricted execution is nowhere in sight. Hence, any use of open() in a long-lived generator in a QThread is probably going to crash. Patch against 2.7? |
ping? (for myself :-)) |
Updated patch for Python 3.4:
It's really hard to reproduce the crash. I tried with my old tarball and I failed. I also tried with my unit test and I failed. I'm pretty sure that the crash can only be reproduced when Python is compiled is release mode. I reproduced the crash once with the unit test on an unpatched Python 3.4. For Python 2.7 and 3.3, what do you think of applying generator.patch? It looks simple and obvious. I don't know the impact on performances, but it should be very low. |
It would be interesting to fix the issue in Python 2.7 and 3.3: |
New changeset d2560fd8a008 by Victor Stinner in branch 'default': |
New changeset 0875e5bbe5f0 by Victor Stinner in branch '3.3': New changeset 55dd094a2b01 by Victor Stinner in branch 'default': |
New changeset 2f975036cf39 by Victor Stinner in branch '3.3': New changeset 9852637f05c3 by Victor Stinner in branch 'default': |
New changeset aa324af42c0e by Victor Stinner in branch '2.7': |
Thanks Mark Shannon for your patch. Sorry, I forgot to mention your name if the changesets :-/ I didn't remember the whole story of this issue. It should now be fixed. |
I agree that this is an improvement, but isn't it a bit late for removing a public field from a public header file in 3.4, without any preceding deprecation? |
Unfortunately Stefan has a point - what's the migration path for C API |
The header is not public, it is private. The structure in not If you rely on such implement detail (PyFrameObject field), you have Do you know applications relying on the field? How don't see how you would like to deprecate the field since it's |
2013/12/13 Victor Stinner <victor.stinner@gmail.com>:
Hum, I'm not clear. frameobject.h is not included in Python.h, so the |
New changeset 278dd7eb2f2b by Victor Stinner in branch 'default': |
Depends on how you use it, I guess. In many cases (at least for Cython and likely some other low-level tools), it could be as simple as #if PY_VERSION_HEX < 0x030400B2
// set "f_tstate" here
#endif My guess is that some (most?) code that sets this field only does so because CPython previously depended on it being set. (Stackless comes to mind, not sure if that's supposed to work with 3.x...) Read access is an entirely different thing, though. No idea what other tools might be using it for. I'm sure there are debugging/tracing tools out there that make use of the frame internals. Would it be correct for them to just use the current thread state instead? E.g. from a signal handler that analysis the current threads? On a quick look through Ohloh's code search I only found a couple of other occurrences outside of CPython so far. http://code.ohloh.net/search?s=%22f_tstate%22&fe=c&filterChecked=true Disclaimer: it's easy to fix for me with the above conditional, so I won't argue much about keeping up compatibility here. I'm merely raising the issue because there is evidently code that this change breaks. |
"Stable ABI", not API. That said, I agree the field should have been private anyway. |
Why would you set f_tstate field? Frame constructor (PyFrame_New) and Cython does touch this field? Stackless Python supports Python 3 (3.4)? If something relies on f_tstate, it's easy to avoid this field.
The faulthandler has different low-level C signal handlers and it I was surprised that it was so easy to modify ceval.c: in most cases, |
Ah, right. I keep misremembering that, because in order to do anything non-trivial with frames you'll eventually end up importing that header file, so it feels "almost public". I think it's reasonable to expect low-level tools to adapt manually to this kind of changes (or at least recompile for a specific CPython version), and it's unlikely that there's much other code that would make use of this field specifically. So, no objection to keeping the change in 3.4 as it is (and I see that you already documented it). |
Ah, I always forget that frameobject.h isn't included from python.h |
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:
bugs.python.org fields:
The text was updated successfully, but these errors were encountered: