Skip to content

Commit f1c3678

Browse files
ejmounttaiki-e
andcommitted
Correcting overly restrictive lifetimes in vectored IO (#2484)
Co-authored-by: Taiki Endo <[email protected]>
1 parent 6633d23 commit f1c3678

File tree

5 files changed

+69
-40
lines changed

5 files changed

+69
-40
lines changed

futures-util/src/io/mod.rs

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,10 @@ pub trait AsyncReadExt: AsyncRead {
217217
///
218218
/// The returned future will resolve to the number of bytes read once the read
219219
/// operation is completed.
220-
fn read_vectored<'a>(&'a mut self, bufs: &'a mut [IoSliceMut<'a>]) -> ReadVectored<'a, Self>
220+
fn read_vectored<'a, 'b>(
221+
&'a mut self,
222+
bufs: &'a mut [IoSliceMut<'b>],
223+
) -> ReadVectored<'a, 'b, Self>
221224
where
222225
Self: Unpin,
223226
{
@@ -456,7 +459,7 @@ pub trait AsyncWriteExt: AsyncWrite {
456459
///
457460
/// The returned future will resolve to the number of bytes written once the write
458461
/// operation is completed.
459-
fn write_vectored<'a>(&'a mut self, bufs: &'a [IoSlice<'a>]) -> WriteVectored<'a, Self>
462+
fn write_vectored<'a, 'b>(&'a mut self, bufs: &'a [IoSlice<'b>]) -> WriteVectored<'a, 'b, Self>
460463
where
461464
Self: Unpin,
462465
{
@@ -535,10 +538,10 @@ pub trait AsyncWriteExt: AsyncWrite {
535538
/// # Ok::<(), Box<dyn std::error::Error>>(()) }).unwrap();
536539
/// ```
537540
#[cfg(feature = "write-all-vectored")]
538-
fn write_all_vectored<'a>(
541+
fn write_all_vectored<'a, 'b>(
539542
&'a mut self,
540-
bufs: &'a mut [IoSlice<'a>],
541-
) -> WriteAllVectored<'a, Self>
543+
bufs: &'a mut [IoSlice<'b>],
544+
) -> WriteAllVectored<'a, 'b, Self>
542545
where
543546
Self: Unpin,
544547
{

futures-util/src/io/read_vectored.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,20 @@ use std::pin::Pin;
77
/// Future for the [`read_vectored`](super::AsyncReadExt::read_vectored) method.
88
#[derive(Debug)]
99
#[must_use = "futures do nothing unless you `.await` or poll them"]
10-
pub struct ReadVectored<'a, R: ?Sized> {
10+
pub struct ReadVectored<'a, 'b, R: ?Sized> {
1111
reader: &'a mut R,
12-
bufs: &'a mut [IoSliceMut<'a>],
12+
bufs: &'a mut [IoSliceMut<'b>],
1313
}
1414

15-
impl<R: ?Sized + Unpin> Unpin for ReadVectored<'_, R> {}
15+
impl<R: ?Sized + Unpin> Unpin for ReadVectored<'_, '_, R> {}
1616

17-
impl<'a, R: AsyncRead + ?Sized + Unpin> ReadVectored<'a, R> {
18-
pub(super) fn new(reader: &'a mut R, bufs: &'a mut [IoSliceMut<'a>]) -> Self {
17+
impl<'a, 'b, R: AsyncRead + ?Sized + Unpin> ReadVectored<'a, 'b, R> {
18+
pub(super) fn new(reader: &'a mut R, bufs: &'a mut [IoSliceMut<'b>]) -> Self {
1919
Self { reader, bufs }
2020
}
2121
}
2222

23-
impl<R: AsyncRead + ?Sized + Unpin> Future for ReadVectored<'_, R> {
23+
impl<R: AsyncRead + ?Sized + Unpin> Future for ReadVectored<'_, '_, R> {
2424
type Output = io::Result<usize>;
2525

2626
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {

futures-util/src/io/write_all_vectored.rs

Lines changed: 32 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,21 @@ use std::pin::Pin;
1010
/// [`write_all_vectored`](super::AsyncWriteExt::write_all_vectored) method.
1111
#[derive(Debug)]
1212
#[must_use = "futures do nothing unless you `.await` or poll them"]
13-
pub struct WriteAllVectored<'a, W: ?Sized + Unpin> {
13+
pub struct WriteAllVectored<'a, 'b, W: ?Sized + Unpin> {
1414
writer: &'a mut W,
15-
bufs: &'a mut [IoSlice<'a>],
15+
bufs: &'a mut [IoSlice<'b>],
1616
}
1717

18-
impl<W: ?Sized + Unpin> Unpin for WriteAllVectored<'_, W> {}
18+
impl<W: ?Sized + Unpin> Unpin for WriteAllVectored<'_, '_, W> {}
1919

20-
impl<'a, W: AsyncWrite + ?Sized + Unpin> WriteAllVectored<'a, W> {
21-
pub(super) fn new(writer: &'a mut W, mut bufs: &'a mut [IoSlice<'a>]) -> Self {
20+
impl<'a, 'b, W: AsyncWrite + ?Sized + Unpin> WriteAllVectored<'a, 'b, W> {
21+
pub(super) fn new(writer: &'a mut W, mut bufs: &'a mut [IoSlice<'b>]) -> Self {
2222
IoSlice::advance_slices(&mut bufs, 0);
2323
Self { writer, bufs }
2424
}
2525
}
2626

27-
impl<W: AsyncWrite + ?Sized + Unpin> Future for WriteAllVectored<'_, W> {
27+
impl<W: AsyncWrite + ?Sized + Unpin> Future for WriteAllVectored<'_, '_, W> {
2828
type Output = io::Result<()>;
2929

3030
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<io::Result<()>> {
@@ -190,4 +190,30 @@ mod tests {
190190
assert_eq!(&*dst.written, &*wanted);
191191
}
192192
}
193+
194+
#[test]
195+
fn test_write_all_vectored_distinct_lifetimes() {
196+
struct WrapVec<T>(Vec<T>);
197+
impl<T> Drop for WrapVec<T> {
198+
fn drop(&mut self) {}
199+
}
200+
201+
let waker = noop_waker();
202+
let mut cx = Context::from_waker(&waker);
203+
let mut dst = test_writer(2, 2);
204+
205+
{
206+
// Force the lifetimes of the underlying data and IOSlice to be unequal
207+
let data = vec![1, 2, 3, 4];
208+
{
209+
let mut slices = WrapVec(data.chunks(2).map(IoSlice::new).collect());
210+
let mut future = dst.write_all_vectored(&mut *slices.0);
211+
match Pin::new(&mut future).poll(&mut cx) {
212+
Poll::Ready(Ok(())) => {}
213+
other => panic!("unexpected result polling future: {:?}", other),
214+
}
215+
}
216+
assert_eq!(&*dst.written, &*data);
217+
}
218+
}
193219
}

futures-util/src/io/write_vectored.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,20 +7,20 @@ use std::pin::Pin;
77
/// Future for the [`write_vectored`](super::AsyncWriteExt::write_vectored) method.
88
#[derive(Debug)]
99
#[must_use = "futures do nothing unless you `.await` or poll them"]
10-
pub struct WriteVectored<'a, W: ?Sized> {
10+
pub struct WriteVectored<'a, 'b, W: ?Sized> {
1111
writer: &'a mut W,
12-
bufs: &'a [IoSlice<'a>],
12+
bufs: &'a [IoSlice<'b>],
1313
}
1414

15-
impl<W: ?Sized + Unpin> Unpin for WriteVectored<'_, W> {}
15+
impl<W: ?Sized + Unpin> Unpin for WriteVectored<'_, '_, W> {}
1616

17-
impl<'a, W: AsyncWrite + ?Sized + Unpin> WriteVectored<'a, W> {
18-
pub(super) fn new(writer: &'a mut W, bufs: &'a [IoSlice<'a>]) -> Self {
17+
impl<'a, 'b, W: AsyncWrite + ?Sized + Unpin> WriteVectored<'a, 'b, W> {
18+
pub(super) fn new(writer: &'a mut W, bufs: &'a [IoSlice<'b>]) -> Self {
1919
Self { writer, bufs }
2020
}
2121
}
2222

23-
impl<W: AsyncWrite + ?Sized + Unpin> Future for WriteVectored<'_, W> {
23+
impl<W: AsyncWrite + ?Sized + Unpin> Future for WriteVectored<'_, '_, W> {
2424
type Output = io::Result<usize>;
2525

2626
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {

futures/tests/auto_traits.rs

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -793,12 +793,12 @@ pub mod io {
793793
assert_impl!(ReadUntil<'_, ()>: Unpin);
794794
assert_not_impl!(ReadUntil<'_, PhantomPinned>: Unpin);
795795

796-
assert_impl!(ReadVectored<'_, ()>: Send);
797-
assert_not_impl!(ReadVectored<'_, *const ()>: Send);
798-
assert_impl!(ReadVectored<'_, ()>: Sync);
799-
assert_not_impl!(ReadVectored<'_, *const ()>: Sync);
800-
assert_impl!(ReadVectored<'_, ()>: Unpin);
801-
assert_not_impl!(ReadVectored<'_, PhantomPinned>: Unpin);
796+
assert_impl!(ReadVectored<'_, '_, ()>: Send);
797+
assert_not_impl!(ReadVectored<'_, '_, *const ()>: Send);
798+
assert_impl!(ReadVectored<'_, '_, ()>: Sync);
799+
assert_not_impl!(ReadVectored<'_, '_, *const ()>: Sync);
800+
assert_impl!(ReadVectored<'_, '_, ()>: Unpin);
801+
assert_not_impl!(ReadVectored<'_, '_, PhantomPinned>: Unpin);
802802

803803
assert_impl!(Repeat: Send);
804804
assert_impl!(Repeat: Sync);
@@ -856,15 +856,15 @@ pub mod io {
856856
assert_not_impl!(WriteAll<'_, PhantomPinned>: Unpin);
857857

858858
#[cfg(feature = "write-all-vectored")]
859-
assert_impl!(WriteAllVectored<'_, ()>: Send);
859+
assert_impl!(WriteAllVectored<'_, '_, ()>: Send);
860860
#[cfg(feature = "write-all-vectored")]
861-
assert_not_impl!(WriteAllVectored<'_, *const ()>: Send);
861+
assert_not_impl!(WriteAllVectored<'_, '_, *const ()>: Send);
862862
#[cfg(feature = "write-all-vectored")]
863-
assert_impl!(WriteAllVectored<'_, ()>: Sync);
863+
assert_impl!(WriteAllVectored<'_, '_, ()>: Sync);
864864
#[cfg(feature = "write-all-vectored")]
865-
assert_not_impl!(WriteAllVectored<'_, *const ()>: Sync);
865+
assert_not_impl!(WriteAllVectored<'_, '_, *const ()>: Sync);
866866
#[cfg(feature = "write-all-vectored")]
867-
assert_impl!(WriteAllVectored<'_, ()>: Unpin);
867+
assert_impl!(WriteAllVectored<'_, '_, ()>: Unpin);
868868
// WriteAllVectored requires `W: Unpin`
869869
// #[cfg(feature = "write-all-vectored")]
870870
// assert_not_impl!(WriteAllVectored<'_, PhantomPinned>: Unpin);
@@ -875,12 +875,12 @@ pub mod io {
875875
assert_not_impl!(WriteHalf<*const ()>: Sync);
876876
assert_impl!(WriteHalf<PhantomPinned>: Unpin);
877877

878-
assert_impl!(WriteVectored<'_, ()>: Send);
879-
assert_not_impl!(WriteVectored<'_, *const ()>: Send);
880-
assert_impl!(WriteVectored<'_, ()>: Sync);
881-
assert_not_impl!(WriteVectored<'_, *const ()>: Sync);
882-
assert_impl!(WriteVectored<'_, ()>: Unpin);
883-
assert_not_impl!(WriteVectored<'_, PhantomPinned>: Unpin);
878+
assert_impl!(WriteVectored<'_, '_, ()>: Send);
879+
assert_not_impl!(WriteVectored<'_, '_, *const ()>: Send);
880+
assert_impl!(WriteVectored<'_, '_, ()>: Sync);
881+
assert_not_impl!(WriteVectored<'_, '_, *const ()>: Sync);
882+
assert_impl!(WriteVectored<'_, '_, ()>: Unpin);
883+
assert_not_impl!(WriteVectored<'_, '_, PhantomPinned>: Unpin);
884884
}
885885

886886
/// Assert Send/Sync/Unpin for all public types in `futures::lock`.

0 commit comments

Comments
 (0)