-
Notifications
You must be signed in to change notification settings - Fork 760
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
GILPool
is a broken abstraction in presence of gevent
#3668
Comments
As a short-term mitigation, I think we could switch the pool to design to not store the objects in TLS, but directly in the pool itself and only put the currently active pool into TLS. This should avoid pool A freeing objects allocated for pool B in the above. |
Possibly, but I think with just that change the gevent task switching will still confuse the active pool in the TLS, and instead when task A resumes it will start writing new objects into task B's pool. I think that must still necessarily be unsound if task B completes before task A. |
One option is to just |
Ah, of course, gevent switching tasks does not switch TLS which is basically again what this is about...
Is there a hook or something which would allow us to fix up ourselves when gevent decides to switch tasks? |
https://www.gevent.org/api/gevent.local.html - might be able to build something off Alternatively, maybe it's better to go lower-level and interact with Though the API for |
@jamadden sorry for the direct ping; I wonder if you have any advice on making native TLS interact safely with |
(The tl;dr is: maybe
Right, because its greenlets that are switching, not threads.
Not really. The underlying greenlet library can call a function when greenlets are being switched, but that's intended for user-level profiling or debugging; it's not very composable.
Also unfortunately, I don't have much to offer in terms of true native TLS. Greenlets aren't threads, and thus don't do anything with thread-local storage, whether provided by the compiler (.e.g, It sounds like you need greenlet-local values. It is possible to do that with Perhaps you can use contextvars for what you need? These were originally added to CPython to solve similar problems that The nice thing about |
So we would call |
Yes, I think so. It looks like this is not available in abi3 though, so I guess for that we'll have to go via Python calls and just hope that it's good enough. Either way I guess it will be a notable performance degradation, so probably only useful as a mitigation while we get off the pool. I can try to implement this tomorrow 👍 Thanks @jamadden! |
With the release of the Bound API in 0.21, which allows avoiding the GIL Pool, I think we can call this issue resolved. The 0.22 and 0.23 releases will completely phase out the old API and allow us to completely remove the pool. |
From investigation in pydantic/pydantic#7211
I am able to produce a small minimal case which shows that in the presence of
gevent
task switching, theGILPool
is not sound.The fundamentals of the interaction can be summarised as follows:
gevent
task A calls into a PyO3 function, creating aGILPool
we will call poolA
.A
, before running a pure-python callback which allowsgevent
to switch taskgevent
task B calls into the PyO3 function, creating another new poolB
. Due to the currentGILPool
scoping design, this pool is necessarily freed when poolA
is freed.GilPool
B, and then eventually also switches task.A
resumes and finishes its PyO3 function call, freeing poolA
(which also frees the contents of poolB
).B
, which continues PyO3 function execution, reading from the freed poolB
and thus leading to UB.Some quick thoughts:
GILPool
implementation to avoid this.Py2
API work and rip out theGILPool
completely.It's unclear to me whether the root cause is that
GILPool
relies on an invalid assumption regarding nature of Rust scopes in the presence of FFI calls, or thatgevent
is not sound by assuming that it's always safe to switch task. Given the long existence ofgevent
, probably this lesson is for us.The text was updated successfully, but these errors were encountered: