-
Notifications
You must be signed in to change notification settings - Fork 788
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
Close soundness hole with acquire_gil #893
Conversation
I have a mixed feeling about this PR. I can understand we can avoid what you call 'dangling' by this trick. I feel this demerit surpasses the merit it offers. let gil = Python::acquire_gil();
let py = gil.python();
let obj;
{
let gil2 = Python::acquire_gil();
obj = py.eval("object()", None, None).unwrap();
println!("Count before gil2 drop {}", unsafe { ffi::Py_REFCNT(obj.as_ptr()) });
} |
This is not true - users can still control timing of the release, just they must now use the unsafe I think it is very important we make the manual memory control an unsafe API. Because if we continue to tell people to use |
Idea: we could perhaps make a safe API similar to // The below sample would fail to pass the borrow checker because returning a reference to py
let obj: &PyAny = pyo3::with_memory_pool(|py| {
// py comes from the new GILPool we create, so no objects can accidentally be made
// with too long lifetime
py.eval("object()", None, None).unwrap()
});
// The below sample would compile successfully
let obj: PyObject = pyo3::with_memory_pool(|py| {
py.eval("object()", None, None).unwrap().to_object(py)
}); Like Not sure what I think of the name |
Hmm 🤔 As an experiment, I created #894 witch uses So..., since (now) we cannot find a better solution than this PR, now I feel it OK to delay the object release. |
If you like, as part of this PR I can later today add more documentation to address #311 |
How about adding impl Python {
unsafe fn acruiqe_gil_with_memorypool(self) -> GILGuard {
GILGuard::acquie_with_gil_pool() // name your own
}
} ? |
One thing I dislike about this PR is the lifetime But it results in 1.2x slowdown... 😰 |
Pushed some more docs, and I want to push some more docs to |
I am unsure if #913 will show a better way to solve this problem? Not sure yet, I haven't thought too hard, feel like there might be a way but haven't seen one yet. |
ff9e8e3
to
35a96d3
Compare
Okay, I've had another go at this. I also added some documentation to Based on the feedback you gave, I moved the function to This function still returns I'm happy to keep tweaking this PR until we find something which feels good though. So let me know what you think of this version 😄 |
/// after the `GILPool` is dropped, unless they are converted to `Py<T>` *before* the pool | ||
/// is dropped. | ||
#[inline] | ||
pub unsafe fn new_pool(self) -> GILPool { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
I like the new |
Yes I wondered about this too. If we add an extra safety note to And I guess this requirement is true anyway, else when the |
35a96d3
to
8ffe8c5
Compare
I've made |
Thank you! |
After thinking on #864 some more, I realised we now have an easy route to make this API sound.
If a
GILPool
already exists whenPython::acquire_gil()
is called, we should not create anotherGILPool
.This ensures that users cannot in safe code accidentally create a
GILPool
and allow references to outlast it. For those that still really want to clear memory manually, they can still useGILPool::new()
and drop that pool when they want.Fixes #864
Fixes #311