Skip to content
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

Fix PyDict issues on free-threaded build #4788

Merged
merged 8 commits into from
Jan 2, 2025

Conversation

ngoldbaum
Copy link
Contributor

@ngoldbaum ngoldbaum commented Dec 10, 2024

This fixes two issues with PyDict on the free-threaded build.

  • We were acquiring an inner critical section in next() in functions where we had already acquired an outer critical section. That is unnecessary. I've renamed DictIterImpl::DictIter::next to next_unchecked, marked it unsafe, and systematically used it in spots where we already had a critical section acquired. In the only spot we didn't, I manually added a critical section. I think having an unsafe next_unchecked is easier to reason about - you need to do the locking yourself.

  • We were accessing dict internals in a thread-unsafe manner, we should go through the C API on the free-threaded build. CPython uses a relaxed atomic load internally.

Also includes some minor doc improvements.

This should probably be backported to the 0.23 branch.

ping @bschoenmaeckers

src/types/dict.rs Show resolved Hide resolved
@@ -470,15 +478,15 @@ impl DictIterImpl {
let mut key: *mut ffi::PyObject = std::ptr::null_mut();
let mut value: *mut ffi::PyObject = std::ptr::null_mut();

if unsafe { ffi::PyDict_Next(dict.as_ptr(), ppos, &mut key, &mut value) } != 0 {
if ffi::PyDict_Next(dict.as_ptr(), ppos, &mut key, &mut value) != 0 {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO we should keep these unsafe blocks. unsafe_op_in_unsafe_fn will be warn be default in the 2024 edition and it makes it easier validate and document the safety invariants.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks! For some reason I thought there was a clippy lint to remove these.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It looks like Rust 1.63 objects:

https://github.com/PyO3/pyo3/actions/runs/12571738722/job/35043025705#step:11:107

Is there a way to keep this with the "unnecessary" unsafes and still compile on older rust?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could add a #[deny(unsafe_op_in_unsafe_fn)] on the function. Not the nicest solution I guess but it should work.

@alex alex added this pull request to the merge queue Dec 24, 2024
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Dec 24, 2024
Copy link
Member

@davidhewitt davidhewitt left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

src/types/dict.rs Show resolved Hide resolved
src/types/dict.rs Show resolved Hide resolved
@davidhewitt davidhewitt enabled auto-merge January 1, 2025 13:55
@davidhewitt davidhewitt added this pull request to the merge queue Jan 1, 2025
@github-merge-queue github-merge-queue bot removed this pull request from the merge queue due to failed status checks Jan 1, 2025
@ngoldbaum ngoldbaum enabled auto-merge January 2, 2025 22:02
@ngoldbaum ngoldbaum added this pull request to the merge queue Jan 2, 2025
Merged via the queue into PyO3:main with commit 93823d2 Jan 2, 2025
46 checks passed
@ngoldbaum ngoldbaum deleted the pydict-locking branch January 2, 2025 22:36
davidhewitt added a commit that referenced this pull request Jan 3, 2025
* clarify safety docs for PyDict API

* get dict size using PyDict_Size on free-threaded build

* avoid unnecessary critical sections in PyDict

* add changelog entry

* fix build error on GIL-enabled build

* address code review comments

* move attribute below doc comment

* ignore unsafe_op_in_unsafe_fn in next_unchecked

---------

Co-authored-by: David Hewitt <[email protected]>
davidhewitt added a commit that referenced this pull request Jan 3, 2025
* clarify safety docs for PyDict API

* get dict size using PyDict_Size on free-threaded build

* avoid unnecessary critical sections in PyDict

* add changelog entry

* fix build error on GIL-enabled build

* address code review comments

* move attribute below doc comment

* ignore unsafe_op_in_unsafe_fn in next_unchecked

---------

Co-authored-by: David Hewitt <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants