aboutsummaryrefslogtreecommitdiff
path: root/embassy-futures/src
diff options
context:
space:
mode:
authorOleksandr Babak <[email protected]>2024-09-11 10:42:46 +0200
committerOleksandr Babak <[email protected]>2024-09-11 10:46:28 +0200
commit29932c295c44cea1a2ab5ad94c5d0bd16c07243d (patch)
tree6dc51dbcc45b88e0ed7e1d5e5188f3c718cdf584 /embassy-futures/src
parentdc98d865ff5a25e33da58fe6090c786ca06500b0 (diff)
fix: `select_slice` is unsound. fixes #3320
Diffstat (limited to 'embassy-futures/src')
-rw-r--r--embassy-futures/src/select.rs35
1 files changed, 15 insertions, 20 deletions
diff --git a/embassy-futures/src/select.rs b/embassy-futures/src/select.rs
index 97a81a86d..57f0cb41f 100644
--- a/embassy-futures/src/select.rs
+++ b/embassy-futures/src/select.rs
@@ -237,7 +237,7 @@ impl<Fut: Future, const N: usize> Future for SelectArray<Fut, N> {
237#[derive(Debug)] 237#[derive(Debug)]
238#[must_use = "futures do nothing unless you `.await` or poll them"] 238#[must_use = "futures do nothing unless you `.await` or poll them"]
239pub struct SelectSlice<'a, Fut> { 239pub struct SelectSlice<'a, Fut> {
240 inner: &'a mut [Fut], 240 inner: Pin<&'a mut [Fut]>,
241} 241}
242 242
243/// Creates a new future which will select over a slice of futures. 243/// Creates a new future which will select over a slice of futures.
@@ -247,31 +247,26 @@ pub struct SelectSlice<'a, Fut> {
247/// future that was ready. 247/// future that was ready.
248/// 248///
249/// If the slice is empty, the resulting future will be Pending forever. 249/// If the slice is empty, the resulting future will be Pending forever.
250pub fn select_slice<'a, Fut: Future>(slice: &'a mut [Fut]) -> SelectSlice<'a, Fut> { 250pub fn select_slice<'a, Fut: Future>(slice: Pin<&'a mut [Fut]>) -> SelectSlice<'a, Fut> {
251 SelectSlice { inner: slice } 251 SelectSlice { inner: slice }
252} 252}
253 253
254impl<'a, Fut: Future> Future for SelectSlice<'a, Fut> { 254impl<'a, Fut: Future> Future for SelectSlice<'a, Fut> {
255 type Output = (Fut::Output, usize); 255 type Output = (Fut::Output, usize);
256 256
257 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { 257 fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
258 // Safety: Since `self` is pinned, `inner` cannot move. Since `inner` cannot move, 258 // Safety: refer to
259 // its elements also cannot move. Therefore it is safe to access `inner` and pin 259 // https://users.rust-lang.org/t/working-with-pinned-slices-are-there-any-structurally-pinning-vec-like-collection-types/50634/2
260 // references to the contained futures. 260 #[inline(always)]
261 let item = unsafe { 261 fn pin_iter<T>(slice: Pin<&mut [T]>) -> impl Iterator<Item = Pin<&mut T>> {
262 self.get_unchecked_mut() 262 unsafe { slice.get_unchecked_mut().iter_mut().map(|v| Pin::new_unchecked(v)) }
263 .inner 263 }
264 .iter_mut() 264 for (i, fut) in pin_iter(self.inner.as_mut()).enumerate() {
265 .enumerate() 265 if let Poll::Ready(res) = fut.poll(cx) {
266 .find_map(|(i, f)| match Pin::new_unchecked(f).poll(cx) { 266 return Poll::Ready((res, i));
267 Poll::Pending => None, 267 }
268 Poll::Ready(e) => Some((i, e)),
269 })
270 };
271
272 match item {
273 Some((idx, res)) => Poll::Ready((res, idx)),
274 None => Poll::Pending,
275 } 268 }
269
270 Poll::Pending
276 } 271 }
277} 272}