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

Remove need for mutable reference to static #13705

Merged
merged 1 commit into from
Jan 21, 2025

Conversation

jakelishman
Copy link
Member

Mutable references to static data are inherently unsafe and typically unsound in Rust, because statics are implicitly shared between threads, and the borrow checker can only enforce the shared/exclusive reference limitations within a single thread here.

This just moves the thread-exclusion logic into the individual elements of the static, where the GILOnceCell can correctly handle the runtime exclusion of multiple threads. (The GIL is no longer suitable for thread exclusion if we were doing a freethreaded Python build, but that's a problem we have all over Qiskit, and would need to change to OnceLock or the like.)

Summary

Details and comments

Minor conflict with the update to PyO3 0.23, but only a small syntactic one - the import_bound becomes import. The logic still works.

@jakelishman jakelishman added type: qa Issues and PRs that relate to testing and code quality stable backport potential The bug might be minimal and/or import enough to be port to stable Changelog: None Do not include in changelog Rust This PR or issue is related to Rust code in the repository labels Jan 21, 2025
@jakelishman jakelishman requested a review from a team as a code owner January 21, 2025 14:18
@qiskit-bot
Copy link
Collaborator

One or more of the following people are relevant to this code:

  • @Qiskit/terra-core

@coveralls
Copy link

coveralls commented Jan 21, 2025

Pull Request Test Coverage Report for Build 12891354532

Details

  • 6 of 6 (100.0%) changed or added relevant lines in 2 files are covered.
  • 14 unchanged lines in 3 files lost coverage.
  • Overall coverage decreased (-0.002%) to 88.925%

Files with Coverage Reduction New Missed Lines %
crates/qasm2/src/lex.rs 1 93.48%
crates/accelerate/src/two_qubit_decompose.rs 1 92.06%
crates/qasm2/src/parse.rs 12 97.15%
Totals Coverage Status
Change from base Build 12891072018: -0.002%
Covered Lines: 79444
Relevant Lines: 89338

💛 - Coveralls

Mutable references to static data are inherently unsafe and typically
unsound in Rust, because statics are implicitly shared between threads,
and the borrow checker can only enforce the shared/exclusive reference
limitations within a single thread here.

This just moves the thread-exclusion logic into the individual elements
of the `static`, where the `GILOnceCell` can correctly handle the
runtime exclusion of multiple threads. (The GIL is no longer suitable
for thread exclusion if we were doing a freethreaded Python build, but
that's a problem we have all over Qiskit, and would need to change to
`OnceLock` or the like.)
Copy link
Member

@mtreinish mtreinish left a comment

Choose a reason for hiding this comment

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

This LGTM. I think I found the previous code cleaner but rust 1.84 warns 3 times about this being unsafe, and rust edition 2024 will actually make the mut ref static stuff unsafe. While we won't be using that for 2.x, it's good to remove the mut ref static preemptively.

Comment on lines +258 to +311
static STDGATE_PYTHON_GATES: [GILOnceCell<PyObject>; STANDARD_GATE_SIZE] = [
GILOnceCell::new(),
GILOnceCell::new(),
GILOnceCell::new(),
GILOnceCell::new(),
GILOnceCell::new(),
GILOnceCell::new(),
GILOnceCell::new(),
GILOnceCell::new(),
GILOnceCell::new(),
GILOnceCell::new(),
GILOnceCell::new(),
GILOnceCell::new(),
GILOnceCell::new(),
GILOnceCell::new(),
GILOnceCell::new(),
GILOnceCell::new(),
GILOnceCell::new(),
GILOnceCell::new(),
GILOnceCell::new(),
GILOnceCell::new(),
GILOnceCell::new(),
GILOnceCell::new(),
GILOnceCell::new(),
GILOnceCell::new(),
GILOnceCell::new(),
GILOnceCell::new(),
GILOnceCell::new(),
GILOnceCell::new(),
GILOnceCell::new(),
GILOnceCell::new(),
GILOnceCell::new(),
GILOnceCell::new(),
GILOnceCell::new(),
GILOnceCell::new(),
GILOnceCell::new(),
GILOnceCell::new(),
GILOnceCell::new(),
GILOnceCell::new(),
GILOnceCell::new(),
GILOnceCell::new(),
GILOnceCell::new(),
GILOnceCell::new(),
GILOnceCell::new(),
GILOnceCell::new(),
GILOnceCell::new(),
GILOnceCell::new(),
GILOnceCell::new(),
GILOnceCell::new(),
GILOnceCell::new(),
GILOnceCell::new(),
GILOnceCell::new(),
GILOnceCell::new(),
];
Copy link
Member

Choose a reason for hiding this comment

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

This is pretty ugly. But I don't think there is a syntax that we can use here with GilOnceCell given the constraints defined in: https://doc.rust-lang.org/std/primitive.array.html so this is fine.

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, it's ugly. For anybody from the future looking: the trouble is that there's not enough available in const functions to manage this. The closest I managed to get was

use std::mem::MaybeUninit;
use pyo3::prelude::*;
use pyo3::sync::GILOnceCell;

const STANDARD_GATE_SIZE: usize = 52;

static STDGATE_PYTHON_GATES: [GILOnceCell<Py<PyAny>>; STANDARD_GATE_SIZE] = const {
    let mut out: [MaybeUninit<GILOnceCell<Py<PyAny>>>; STANDARD_GATE_SIZE] =
        [const { MaybeUninit::uninit() }; STANDARD_GATE_SIZE];
    let mut i = 0;
    while i < STANDARD_GATE_SIZE {
        out[i].write(GILOnceCell::new());  // error: `MaybeUninit::write` isn't const stable
        i += 1;
    }
    unsafe { ::std::mem::transmute(out) }
};

@mtreinish mtreinish added this pull request to the merge queue Jan 21, 2025
Merged via the queue into Qiskit:main with commit 7b0b6fc Jan 21, 2025
17 checks passed
mergify bot pushed a commit that referenced this pull request Jan 21, 2025
Mutable references to static data are inherently unsafe and typically
unsound in Rust, because statics are implicitly shared between threads,
and the borrow checker can only enforce the shared/exclusive reference
limitations within a single thread here.

This just moves the thread-exclusion logic into the individual elements
of the `static`, where the `GILOnceCell` can correctly handle the
runtime exclusion of multiple threads. (The GIL is no longer suitable
for thread exclusion if we were doing a freethreaded Python build, but
that's a problem we have all over Qiskit, and would need to change to
`OnceLock` or the like.)

(cherry picked from commit 7b0b6fc)

# Conflicts:
#	crates/circuit/src/imports.rs
@jakelishman jakelishman deleted the no-mutable-static branch January 21, 2025 22:20
github-merge-queue bot pushed a commit that referenced this pull request Jan 22, 2025
* Remove need for mutable reference to static (#13705)

Mutable references to static data are inherently unsafe and typically
unsound in Rust, because statics are implicitly shared between threads,
and the borrow checker can only enforce the shared/exclusive reference
limitations within a single thread here.

This just moves the thread-exclusion logic into the individual elements
of the `static`, where the `GILOnceCell` can correctly handle the
runtime exclusion of multiple threads. (The GIL is no longer suitable
for thread exclusion if we were doing a freethreaded Python build, but
that's a problem we have all over Qiskit, and would need to change to
`OnceLock` or the like.)

(cherry picked from commit 7b0b6fc)

# Conflicts:
#	crates/circuit/src/imports.rs

* Update imports.rs

* Fix for older PyO3

---------

Co-authored-by: Jake Lishman <[email protected]>
Co-authored-by: Elena Peña Tapia <[email protected]>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Changelog: None Do not include in changelog Rust This PR or issue is related to Rust code in the repository stable backport potential The bug might be minimal and/or import enough to be port to stable type: qa Issues and PRs that relate to testing and code quality
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants