From 33467213654bb349a335bc6363e877b225988c17 Mon Sep 17 00:00:00 2001 From: Robert Zieba Date: Thu, 18 Jun 2026 11:35:37 -0700 Subject: [PATCH] Manually cast `heapless::Vec` to slice for `select_slice` The current implementation of `pin!` automatically does type coercion with references. We rely on this when using `select_slice`. However, this behavior is unsound because there's no guarantee that the result of this coercion is actually pinned. Pre-emptively Use `map_unchecked_mut` to manually perform this cast since it is safe in our case and because this fix will eventually land on main (currently present on nightly 1.97). See https://github.com/rust-lang/rust/issues/153438 and https://github.com/rust-lang/rust/pull/153457. --- power-policy-service/src/charger.rs | 5 ++++- power-policy-service/src/psu.rs | 5 ++++- type-c-service/src/service/event_receiver.rs | 5 ++++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/power-policy-service/src/charger.rs b/power-policy-service/src/charger.rs index 98ddcca1d..97a63088d 100644 --- a/power-policy-service/src/charger.rs +++ b/power-policy-service/src/charger.rs @@ -35,7 +35,10 @@ where // Push will never fail since the number of receivers is the same as the capacity of the vector let _ = futures.push(async move { (receiver.wait_next().await, psu) }); } - select_slice(pin!(&mut futures)).await + // Pin the futures and deference to a slice + let pinned = pin!(futures); + // Safety: The backing buffer is contained within the heapless::Vec so it won't be moved either. + select_slice(unsafe { pinned.map_unchecked_mut(|f| f.as_mut()) }).await }; Event { charger, event } diff --git a/power-policy-service/src/psu.rs b/power-policy-service/src/psu.rs index 99b72cf61..e731ed069 100644 --- a/power-policy-service/src/psu.rs +++ b/power-policy-service/src/psu.rs @@ -32,7 +32,10 @@ where // Push will never fail since the number of receivers is the same as the capacity of the vector let _ = futures.push(async move { (receiver.wait_next().await, psu) }); } - select_slice(pin!(&mut futures)).await + // Pin the futures and deference to a slice + let pinned = pin!(futures); + // Safety: The backing buffer is contained within the heapless::Vec so it won't be moved either. + select_slice(unsafe { pinned.map_unchecked_mut(|f| f.as_mut()) }).await }; Event { psu, event } diff --git a/type-c-service/src/service/event_receiver.rs b/type-c-service/src/service/event_receiver.rs index b048fc9a6..eb2e669bc 100644 --- a/type-c-service/src/service/event_receiver.rs +++ b/type-c-service/src/service/event_receiver.rs @@ -42,7 +42,10 @@ impl< // Push will never fail since the number of receivers is the same as the capacity of the vector let _ = futures.push(async move { (receiver.wait_next().await, psu) }); } - select_slice(pin!(&mut futures)).await + // Pin the futures and deference to a slice + let pinned = pin!(futures); + // Safety: The backing buffer is contained within the heapless::Vec so it won't be moved either. + select_slice(unsafe { pinned.map_unchecked_mut(|f| f.as_mut()) }).await }; Event::PortEvent(PortEvent { port: *port, event })