Skip to content

Restrict unsafe blocks to single statements where possible.#15806

Open
Cryoris wants to merge 6 commits intoQiskit:mainfrom
Cryoris:unsafe-surgeon-mode
Open

Restrict unsafe blocks to single statements where possible.#15806
Cryoris wants to merge 6 commits intoQiskit:mainfrom
Cryoris:unsafe-surgeon-mode

Conversation

@Cryoris
Copy link
Copy Markdown
Collaborator

@Cryoris Cryoris commented Mar 13, 2026

Summary

Following up on #15106 (comment) by reducing the sizes of unsafe statements in the codebase.

Details and comments

To see which part of the code is unsafe, it is good to restrict unsafe blocks to the smallest sensible code unit. Clippy also has a feature to check this, cargo clippy -- -W clippy::multiple_unsafe_ops_per_block. This commit reduces some pretty large unsafe blocks to smaller ones to improve our code structure. Clippy actually flags any snippet that has more than a single statement, but I left unsafe blocks in place where every single statement was actually unsafe.

To see which part of the code is unsafe, it is good to restrict `unsafe` blocks to the smallest sensible code unit. Clippy also has a feature to check this, `cargo clippy -- -W clippy::multiple_unsafe_ops_per_block`. This commit reduces some pretty large unsafe blocks to smaller ones to improve our code structure. Clippy actually flags _any_ snippet that has more than a single statement, but I left unsafe blocks in place where every single statement was actually unsafe.
@Cryoris Cryoris added this to the 2.5.0 milestone Mar 13, 2026
@Cryoris Cryoris requested a review from a team as a code owner March 13, 2026 12:52
@Cryoris Cryoris added type: qa Issues and PRs that relate to testing and code quality Changelog: None Do not include in the GitHub Release changelog. labels Mar 13, 2026
@qiskit-bot
Copy link
Copy Markdown
Collaborator

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

  • @Qiskit/terra-core

Copy link
Copy Markdown
Contributor

@gadial gadial left a comment

Choose a reason for hiding this comment

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

Overall looks good to me. Left minor comments.

@@ -1569,26 +1568,22 @@ pub unsafe extern "C" fn qk_target_op_clear(op: *mut CTargetOp) {

// SAFETY: As per documentation, data from pointers contained in CTargetOp
// originates from rust code and are constructed internally with vecs and CStrings.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Does this cover the mut_ptr_as_ref(op) operation?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

It does not! Let me adjust 🙂

Comment thread crates/cext/src/dag.rs
};
new_node.index() as u32
}
// SAFETY: Per the documentation the qubits pointer is an arrays of num_qubits() elements
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Suggested change
// SAFETY: Per the documentation the qubits pointer is an arrays of num_qubits() elements
// SAFETY: Per the documentation the qubits pointer is an array of num_qubits() elements

@coveralls
Copy link
Copy Markdown

Coverage Report for CI Build 25101306270

Coverage increased (+0.02%) to 87.509%

Details

  • Coverage increased (+0.02%) from the base build.
  • Patch coverage: 26 uncovered changes across 2 files (115 of 141 lines covered, 81.56%).
  • 20 coverage regressions across 4 files.

Uncovered Changes

File Changed Covered %
crates/cext/src/transpiler/transpile_function.rs 24 0 0.0%
crates/cext/src/dag.rs 23 21 91.3%

Coverage Regressions

20 previously-covered lines in 4 files lost coverage.

File Lines Losing Coverage Coverage
crates/qasm2/src/parse.rs 12 97.15%
crates/qasm2/src/lex.rs 6 91.0%
crates/cext/src/transpiler/target.rs 1 89.44%
crates/circuit/src/parameter/parameter_expression.rs 1 90.53%

Coverage Stats

Coverage Status
Relevant Lines: 119958
Covered Lines: 104974
Line Coverage: 87.51%
Coverage Strength: 978272.86 hits per line

💛 - Coveralls

let _ = unsafe { CString::from_raw(inst.name) };
inst.name = std::ptr::null_mut();
}
inst.name = std::ptr::null_mut();
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Isn't this causing a memory leak now because we're no longer dropping the existing string pointer? Don't we need rust to take ownership of the string again so it frees the allocation?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Oh this looks like a merge gone wrong, I didn't mean to remove that... thanks for catching that!

let target = if target.is_null() {
None
} else {
Some(unsafe { const_ptr_as_ref(target) })
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

On the other places you moved the safety comment inside the else body to be with the reduced scope unsafe calls.

pub unsafe extern "C" fn qk_neighbors_is_all_to_all(neighbors: *const CNeighbors) -> bool {
// SAFETY: per documentation, `neighbors` points to a valid initialized `CNeighbors`.
unsafe { (*neighbors).neighbors.is_null() && (*neighbors).partition.is_null() }
let neighbors = unsafe { const_ptr_as_ref(neighbors) };
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

Doesn't this change the requirements for neighbors? This function asserts alignment while it is not documented as being required for this function.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

Hmm.. isn't that an oversight from before, though? I thought that the pointer needed to be aligned to be dereferenced safely.

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 the GitHub Release changelog. type: qa Issues and PRs that relate to testing and code quality

Projects

Status: Ready

Development

Successfully merging this pull request may close these issues.

6 participants