Skip to content

Commit dbc1dea

Browse files
Rollup merge of rust-lang#120741 - a1phyr:safe_buffer_advance, r=m-ou-se
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.
2 parents 9c78654 + 0a42a54 commit dbc1dea

File tree

14 files changed

+38
-34
lines changed

14 files changed

+38
-34
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/hermit/net.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ impl Socket {
156156
)
157157
})?;
158158
unsafe {
159-
buf.advance(ret as usize);
159+
buf.advance_unchecked(ret as usize);
160160
}
161161
Ok(())
162162
}

library/std/src/sys/pal/solid/fs.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -388,7 +388,7 @@ impl File {
388388

389389
// Safety: `num_bytes_read` bytes were written to the unfilled
390390
// portion of the buffer
391-
cursor.advance(num_bytes_read);
391+
cursor.advance_unchecked(num_bytes_read);
392392

393393
Ok(())
394394
}

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -209,7 +209,7 @@ impl Socket {
209209
netc::recv(self.as_raw_fd(), buf.as_mut().as_mut_ptr().cast(), buf.capacity(), flags)
210210
})?;
211211
unsafe {
212-
buf.advance(ret as usize);
212+
buf.advance_unchecked(ret as usize);
213213
}
214214
Ok(())
215215
}

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
}

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ impl WasiFd {
6060
}];
6161
match wasi::fd_read(self.as_raw_fd() as wasi::Fd, &bufs) {
6262
Ok(n) => {
63-
buf.advance(n);
63+
buf.advance_unchecked(n);
6464
Ok(())
6565
}
6666
Err(e) => Err(err2io(e)),

library/std/src/sys/pal/windows/handle.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,7 @@ impl Handle {
121121
Ok(read) => {
122122
// Safety: `read` bytes were written to the initialized portion of the buffer
123123
unsafe {
124-
cursor.advance(read);
124+
cursor.advance_unchecked(read);
125125
}
126126
Ok(())
127127
}

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

+1-1
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ impl Socket {
234234
}
235235
}
236236
_ => {
237-
unsafe { buf.advance(result as usize) };
237+
unsafe { buf.advance_unchecked(result as usize) };
238238
Ok(())
239239
}
240240
}

library/std/src/sys/pal/windows/pipe.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -273,7 +273,7 @@ impl AnonPipe {
273273
Err(e) => Err(e),
274274
Ok(n) => {
275275
unsafe {
276-
buf.advance(n);
276+
buf.advance_unchecked(n);
277277
}
278278
Ok(())
279279
}

0 commit comments

Comments
 (0)