Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions crates/pecos-foreign/src/discovery.rs
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,9 @@ pub fn load_plugin(path: &Path) -> Result<LoadedPlugin, PluginError> {

// Wrap decoder if provided.
let decoder = if !desc.decoder_handle.is_null() && !desc.decoder_vtable.is_null() {
// SAFETY: `decoder_vtable` was just null-checked; the plugin protocol
// requires `init_fn` to populate it with a `*const DecoderVTable` that
// points to a vtable owned by the loaded plugin for the plugin's lifetime.
let vtable_copy = unsafe { *desc.decoder_vtable };
unsafe { ForeignDecoder::new(desc.decoder_handle, vtable_copy) }
} else {
Expand All @@ -165,6 +168,9 @@ pub fn load_plugin(path: &Path) -> Result<LoadedPlugin, PluginError> {

// Wrap simulator if provided.
let simulator = if !desc.simulator_handle.is_null() && !desc.simulator_vtable.is_null() {
// SAFETY: `simulator_vtable` was just null-checked; per plugin protocol,
// `init_fn` populates it with a `*const SimulatorVTable` owned by the
// loaded plugin for the plugin's lifetime.
let vtable_copy = unsafe { *desc.simulator_vtable };
unsafe {
ForeignSimulator::new(
Expand Down
37 changes: 37 additions & 0 deletions crates/pecos-foreign/src/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,13 @@ pub unsafe extern "C" fn pecos_engine_process(
output_ptr: *mut *mut u8,
output_len: *mut usize,
) -> i32 {
if engine.is_null() {
return -1;
}
// SAFETY: null-checked above; per `# Safety` doc, no other reference exists
// for this call (single-threaded FFI contract), so `&mut` aliasing is unique.
let eng = unsafe { &mut *engine };
// SAFETY: per `# Safety` doc, `input_ptr` is valid for `input_len` bytes.
let input_bytes = unsafe { std::slice::from_raw_parts(input_ptr, input_len) };
let input = ByteMessage::new(input_bytes);

Expand Down Expand Up @@ -185,6 +191,10 @@ pub unsafe extern "C" fn pecos_engine_process(
/// `engine` must be a valid pointer from `pecos_engine_create`.
#[unsafe(no_mangle)]
pub unsafe extern "C" fn pecos_engine_reset(engine: *mut PecosEngine) -> i32 {
if engine.is_null() {
return -1;
}
// SAFETY: null-checked above; per `# Safety` doc, exclusively owned for this call.
let eng = unsafe { &mut *engine };
match eng.inner.reset() {
Ok(()) => 0,
Expand Down Expand Up @@ -488,3 +498,30 @@ pub unsafe extern "C" fn pecos_free_outcomes(ptr: *mut u32, len: usize) {
}
}
}

#[cfg(test)]
mod tests {
use super::*;

#[test]
fn process_returns_minus_one_on_null_engine() {
let mut out_ptr: *mut u8 = std::ptr::null_mut();
let mut out_len: usize = 0;
let rc = unsafe {
pecos_engine_process(
std::ptr::null_mut(),
std::ptr::null(),
0,
&raw mut out_ptr,
&raw mut out_len,
)
};
assert_eq!(rc, -1);
}

#[test]
fn reset_returns_minus_one_on_null_engine() {
let rc = unsafe { pecos_engine_reset(std::ptr::null_mut()) };
assert_eq!(rc, -1);
}
}
3 changes: 2 additions & 1 deletion crates/pecos-qis-ffi/src/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1570,7 +1570,8 @@ mod tests {
let ptr = unsafe { heap_alloc(100) };
assert!(!ptr.is_null());

// Write to the memory to verify it's valid
// SAFETY: `ptr` was just allocated by `heap_alloc(100)` and asserted non-null
// above; the test scope owns it exclusively until `heap_free` below.
unsafe {
std::ptr::write(ptr, 42u8);
assert_eq!(std::ptr::read(ptr), 42u8);
Expand Down
9 changes: 8 additions & 1 deletion crates/pecos-qis-ffi/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1048,7 +1048,8 @@ mod tests {
let ptr = pecos_get_pending_operations();
assert!(!ptr.is_null());

// Verify operations
// SAFETY: `pecos_get_pending_operations` returns a fresh leaked Box;
// non-null asserted above; the test scope owns it until `pecos_free_operations`.
let collector = unsafe { &*ptr };
assert_eq!(collector.operations.len(), 2);

Expand Down Expand Up @@ -1341,6 +1342,8 @@ mod tests {
// Verify operations were exported
let ops_ptr = pecos_get_pending_operations();
assert!(!ops_ptr.is_null());
// SAFETY: `pecos_get_pending_operations` returns a fresh leaked Box;
// non-null asserted above; freed below via `pecos_free_operations`.
let ops = unsafe { &*ops_ptr };
assert_eq!(ops.operations.len(), 2);
unsafe { pecos_free_operations(ops_ptr) };
Expand Down Expand Up @@ -1407,6 +1410,8 @@ mod tests {
assert_eq!(needed_id, 0);
let ops_ptr = pecos_get_pending_operations();
assert!(!ops_ptr.is_null());
// SAFETY: `pecos_get_pending_operations` returns a fresh leaked Box;
// non-null asserted above; freed below via `pecos_free_operations`.
let ops = unsafe { &*ops_ptr };
assert_eq!(ops.operations, vec![Operation::AllocateQubit { id: 0 }]);
unsafe { pecos_free_operations(ops_ptr) };
Expand All @@ -1416,6 +1421,8 @@ mod tests {
assert_eq!(needed_id, 1);
let ops_ptr = pecos_get_pending_operations();
assert!(!ops_ptr.is_null());
// SAFETY: `pecos_get_pending_operations` returns a fresh leaked Box;
// non-null asserted above; freed below via `pecos_free_operations`.
let ops = unsafe { &*ops_ptr };
assert_eq!(ops.operations, vec![Operation::Quantum(QuantumOp::H(0))]);
unsafe { pecos_free_operations(ops_ptr) };
Expand Down
1 change: 1 addition & 0 deletions docs/requirements.txt
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,4 @@ mkdocstrings>=0.24.0
mkdocstrings-python>=1.7.4
markdown-exec>=1.10.3
pymdown-extensions>=10.21.3
idna>=3.15 # CVE-2026-45409 (re-fix of CVE-2024-3651): idna.encode() DoS on crafted long inputs
67 changes: 67 additions & 0 deletions osv-scanner.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
# OSV-Scanner configuration for the PECOS workspace.
#
# Ignore list policy:
# - Only include entries we cannot fix from this repo (transitive, blocked on
# an upstream release).
# - Each entry must record (a) the offending crate@version, (b) the chain that
# pulls it in, and (c) the upstream that owns the fix.
# - Real CVEs on first-party deps are NEVER ignored here -- pin and fix them
# in the manifest instead (see docs/requirements.txt for the idna pin).
# - Periodically review this list when bumping hugr/tket, fusion-blossom, or
# mwpf and drop entries that the new upstream version eliminates.

[[IgnoredVulns]]
id = "RUSTSEC-2025-0057"
# fxhash@0.2.1 -- unmaintained.
# Chain: hugr-passes -> hugr -> tket -> pecos-hugr.
# Upstream owner: https://github.com/CQCL/hugr (awaiting rustc-hash/ahash swap).
reason = "Transitive via hugr/tket; unmaintained-crate warning, no exploit path in PECOS."

[[IgnoredVulns]]
id = "RUSTSEC-2024-0436"
# paste@1.0.15 -- unmaintained proc-macro.
# Chain: hugr-passes/ascent and mwpf both pull it in.
# Upstream owners: https://github.com/CQCL/hugr and https://github.com/yuewuo/mwpf.
reason = "Transitive via hugr/tket and mwpf; unmaintained-crate warning, no runtime impact (proc-macro)."

[[IgnoredVulns]]
id = "RUSTSEC-2024-0388"
# derivative@2.2.0 -- unmaintained proc-macro.
# Chain: fusion-blossom and mwpf both pull it in.
# Upstream owners: https://github.com/yuewuo/fusion-blossom and https://github.com/yuewuo/mwpf.
reason = "Transitive via fusion-blossom and mwpf; unmaintained-crate warning, no runtime impact (proc-macro)."

[[IgnoredVulns]]
id = "RUSTSEC-2024-0384"
# instant@0.1.13 -- unmaintained; replaced by web-time.
# Chain: hugr-passes/ascent -> ... -> pecos-hugr.
# Upstream owner: https://github.com/CQCL/hugr (ascent is a transitive build-graph helper).
reason = "Transitive via hugr-passes/ascent; unmaintained-crate warning, no Wasm target."

[[IgnoredVulns]]
id = "RUSTSEC-2024-0375"
# atty@0.2.14 -- unmaintained (clap 4.x dropped it).
# Chain: mwpf -> slp -> structopt 0.3 -> clap 2.34.
# Upstream owner: https://github.com/yuewuo/mwpf (awaiting clap 4 / pico-args migration in slp).
reason = "Transitive via mwpf -> slp (clap2-era CLI helper); CLI tty-detect path not exercised by PECOS."

[[IgnoredVulns]]
id = "RUSTSEC-2024-0370"
# proc-macro-error@1.0.4 -- unmaintained; proc-macro-error2 is the maintained fork.
# Chain: mwpf -> slp -> structopt-derive (compile-time only).
# Upstream owner: https://github.com/yuewuo/mwpf.
reason = "Transitive via mwpf -> slp -> structopt-derive; compile-time proc-macro only, no runtime impact."

[[IgnoredVulns]]
id = "RUSTSEC-2021-0145"
# atty@0.2.14 -- potential unaligned read on Windows custom allocators.
# Chain: mwpf -> slp -> structopt 0.3 -> clap 2.34.
# Upstream owner: https://github.com/yuewuo/mwpf.
reason = "Transitive via mwpf -> slp -> clap2; PECOS does not invoke slp's CLI tty-detection at runtime."

[[IgnoredVulns]]
id = "RUSTSEC-2021-0139"
# ansi_term@0.12.1 -- unmaintained.
# Chain: mwpf -> slp -> structopt 0.3 -> clap 2.34.
# Upstream owner: https://github.com/yuewuo/mwpf.
reason = "Transitive via mwpf -> slp -> clap2; unmaintained-crate warning, terminal-color path unused."
3 changes: 2 additions & 1 deletion python/quantum-pecos/docs/requirements.txt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
matplotlib==3.9.2
pillow>=11.3.0 # security floor: Pillow is transitive via matplotlib; avoid known-vulnerable old releases
pillow>=11.3.0 # CVE-2023-50447 + libwebp; transitive via matplotlib
idna>=3.15 # CVE-2026-45409 (re-fix of CVE-2024-3651): idna.encode() DoS on crafted long inputs
networkx==3.3
numpy==1.26.4
scipy==1.14.1
Expand Down
8 changes: 8 additions & 0 deletions scripts/native_bench/bench_pecos/osv-scanner.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# OSV-Scanner configuration for the native_bench/bench_pecos workspace.
# See root osv-scanner.toml for policy.

[[IgnoredVulns]]
id = "RUSTSEC-2024-0436"
# paste@1.0.15 -- unmaintained proc-macro; same chain as workspace root.
# Upstream owner: https://github.com/CQCL/hugr and https://github.com/yuewuo/mwpf.
reason = "Transitive via bench dependencies; unmaintained-crate warning, no runtime impact (proc-macro)."
Loading