Skip to content

Commit 57b634f

Browse files
committed
Make io::BorrowedCursor::advance safe
This also keeps the old `advance` method under `advance_unchecked` name. This makes pattern like `std::io::default_read_buf` safe to write.
1 parent 0809f78 commit 57b634f

File tree

7 files changed

+31
-27
lines changed

7 files changed

+31
-27
lines changed

library/core/src/io/borrowed_buf.rs

+21-1
Original file line numberDiff line numberDiff line change
@@ -233,6 +233,26 @@ impl<'a> BorrowedCursor<'a> {
233233
&mut self.buf.buf[self.buf.filled..]
234234
}
235235

236+
/// Advance the cursor by asserting that `n` bytes have been filled.
237+
///
238+
/// After advancing, the `n` bytes are no longer accessible via the cursor and can only be
239+
/// accessed via the underlying buffer. I.e., the buffer's filled portion grows by `n` elements
240+
/// and its unfilled portion (and the capacity of this cursor) shrinks by `n` elements.
241+
///
242+
/// If less than `n` bytes initialized (by the cursor's point of view), `set_init` should be
243+
/// called first.
244+
///
245+
/// # Panics
246+
///
247+
/// Panics if there are less than `n` bytes initialized.
248+
#[inline]
249+
pub fn advance(&mut self, n: usize) -> &mut Self {
250+
assert!(self.buf.init >= self.buf.filled + n);
251+
252+
self.buf.filled += n;
253+
self
254+
}
255+
236256
/// Advance the cursor by asserting that `n` bytes have been filled.
237257
///
238258
/// After advancing, the `n` bytes are no longer accessible via the cursor and can only be
@@ -244,7 +264,7 @@ impl<'a> BorrowedCursor<'a> {
244264
/// The caller must ensure that the first `n` bytes of the cursor have been properly
245265
/// initialised.
246266
#[inline]
247-
pub unsafe fn advance(&mut self, n: usize) -> &mut Self {
267+
pub unsafe fn advance_unchecked(&mut self, n: usize) -> &mut Self {
248268
self.buf.filled += n;
249269
self.buf.init = cmp::max(self.buf.init, self.buf.filled);
250270
self

library/core/tests/io/borrowed_buf.rs

+4-12
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,7 @@ fn advance_filled() {
4040
let buf: &mut [_] = &mut [0; 16];
4141
let mut rbuf: BorrowedBuf<'_> = buf.into();
4242

43-
unsafe {
44-
rbuf.unfilled().advance(1);
45-
}
43+
rbuf.unfilled().advance(1);
4644

4745
assert_eq!(rbuf.filled().len(), 1);
4846
assert_eq!(rbuf.unfilled().capacity(), 15);
@@ -53,9 +51,7 @@ fn clear() {
5351
let buf: &mut [_] = &mut [255; 16];
5452
let mut rbuf: BorrowedBuf<'_> = buf.into();
5553

56-
unsafe {
57-
rbuf.unfilled().advance(16);
58-
}
54+
rbuf.unfilled().advance(16);
5955

6056
assert_eq!(rbuf.filled().len(), 16);
6157
assert_eq!(rbuf.unfilled().capacity(), 0);
@@ -79,9 +75,7 @@ fn set_init() {
7975

8076
assert_eq!(rbuf.init_len(), 8);
8177

82-
unsafe {
83-
rbuf.unfilled().advance(4);
84-
}
78+
rbuf.unfilled().advance(4);
8579

8680
unsafe {
8781
rbuf.set_init(2);
@@ -153,9 +147,7 @@ fn cursor_set_init() {
153147
assert_eq!(rbuf.unfilled().uninit_mut().len(), 8);
154148
assert_eq!(unsafe { rbuf.unfilled().as_mut() }.len(), 16);
155149

156-
unsafe {
157-
rbuf.unfilled().advance(4);
158-
}
150+
rbuf.unfilled().advance(4);
159151

160152
unsafe {
161153
rbuf.unfilled().set_init(2);

library/std/src/io/mod.rs

+2-10
Original file line numberDiff line numberDiff line change
@@ -578,15 +578,7 @@ where
578578
F: FnOnce(&mut [u8]) -> Result<usize>,
579579
{
580580
let n = read(cursor.ensure_init().init_mut())?;
581-
assert!(
582-
n <= cursor.capacity(),
583-
"read should not return more bytes than there is capacity for in the read buffer"
584-
);
585-
unsafe {
586-
// SAFETY: we initialised using `ensure_init` so there is no uninit data to advance to
587-
// and we have checked that the read amount is not over capacity (see #120603)
588-
cursor.advance(n);
589-
}
581+
cursor.advance(n);
590582
Ok(())
591583
}
592584

@@ -2915,7 +2907,7 @@ impl<T: Read> Read for Take<T> {
29152907

29162908
unsafe {
29172909
// SAFETY: filled bytes have been filled and therefore initialized
2918-
buf.advance(filled);
2910+
buf.advance_unchecked(filled);
29192911
// SAFETY: new_init bytes of buf's unfilled buffer have been initialized
29202912
buf.set_init(new_init);
29212913
}

library/std/src/io/tests.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -655,7 +655,7 @@ fn bench_take_read_buf(b: &mut test::Bencher) {
655655

656656
// Issue #120603
657657
#[test]
658-
#[should_panic = "read should not return more bytes than there is capacity for in the read buffer"]
658+
#[should_panic]
659659
fn read_buf_broken_read() {
660660
struct MalformedRead;
661661

library/std/src/io/util.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -198,7 +198,7 @@ impl Read for Repeat {
198198

199199
// SAFETY: the entire unfilled portion of buf has been initialized
200200
unsafe {
201-
buf.advance(remaining);
201+
buf.advance_unchecked(remaining);
202202
}
203203

204204
Ok(())

library/std/src/sys/pal/unix/fd.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ impl FileDesc {
161161

162162
// Safety: `ret` bytes were written to the initialized portion of the buffer
163163
unsafe {
164-
cursor.advance(ret as usize);
164+
cursor.advance_unchecked(ret as usize);
165165
}
166166
Ok(())
167167
}

library/std/src/sys/pal/unix/net.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,7 @@ impl Socket {
272272
)
273273
})?;
274274
unsafe {
275-
buf.advance(ret as usize);
275+
buf.advance_unchecked(ret as usize);
276276
}
277277
Ok(())
278278
}

0 commit comments

Comments
 (0)