-
Notifications
You must be signed in to change notification settings - Fork 794
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
Segfaults when iterating a PyDict with > 262141 keys #159
Comments
I have created a minimum repro : https://github.com/palad1/pyo3/commit/d0ec218ed8bf0a30cfd7f58cac9ed27e3fa2a6e2 I will try to isolate further on https://github.com/palad1/pyo3/tree/master/examples/test_dict - let me know if you'd rather have me create a PR so the repro is in the main pyo3 tree. Thanks for your help. |
Here's the gdb trace (vs python-3.5.2) form my system.
|
Only happens on linux - OS X and Window are not affected |
This seems to be an issue with pointers being moved when the POOL.borrowed vector grows. In my test, the PyDictIterator.dict field is zeroed when exiting py.from_borrowed_prt(key) grows the POOL.borrowed vector. (See the above linked repro). Apologies for the formatting. I am on a. Mobile |
I believe there is a soundness issue with the borrowed pool. What is happening in my test case is the following:
You can see the smoking gun in GDB by setting a watchpoint to TL;DR: We need to stop sending references to pointers contained in the POOL.borrow vector as some OSes will free/zero the old memory block. Repro test case and forked repo: https://github.com/fdoyon/pyo3/tree/master/examples/test_dict @konstin, @fafhrd91 - this looks like a big change in the way the pool and pointers are being handed-around... |
Thanks for tracking this problem! |
I won't get into fixing this myself, but I'm happy to review and help with a pull request tackling this. |
I agree, this looks like a real hard soundness issue. Fixing this might just entail curtailing the use of pointers in the library to a bare minimum... I will give it a shot now that I have found a way to constantly reproduce the issue. |
Ah but I think just pub struct PyDictIterator<'py> {
dict: PyObject,
pos: isize,
__marker: PhantomData<'py ()>,
} works fine, though I haven't test it yet. |
Thanks @kngwyu, but this is not working as this is an issue with PyObject.0 being zeroed-out by the C memory allocator, not the iterator being dropped, it's still there and valid. The root of the problem is that Pyo3 is sharing pointers from a block of memory that is moved by the C allocator. Smoking gun: (with phantomdata added) |
I think it works since |
I really can't understand why this bug only happens in extension. |
Fix PyDictIterator's segfault(for #159)
@kngwyu I believe this is still broken even with these changes. You just need a larger dictionary. |
Yes, I guess this has moved to #271 |
@yamadapc
Hmm it looks 262141 is the limit size in my PC 🤔 (EDITED: with Python 3.7+Arch Linux) |
I tried to debug with python 3.8 debug build in my PC, but amazingly it works in python 3.8 😭 |
I disagree, the issue is occurring when the You can see the manpage here:
If your system doesn't crash with Python 3.8 that is because the memory layout of your process is different and for some reason you have access to a larger segment. Also some oses do not |
See #268 (comment) for the reason why I think it's not related to ReleasePool. |
Thanks to the the investigation done here, this is fixed in 0.5.1 🎉 |
I think the number of keys is irrelevant but more to do with the object size.
Create a dict with 127 keys and values, rust iteration segfaults by passing a null dict (po) to Pydict_Next on Linux. Will send a repro tomorrow. I am on mobile.
The text was updated successfully, but these errors were encountered: