Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rollup of 6 pull requests #95100

Closed
wants to merge 24 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
4038ca0
Refactor tests of Write for Cursor<_>
cuviper Jan 8, 2022
a04d553
impl Write for Cursor<[u8; N]>
cuviper Jan 19, 2022
38cef65
Write for Cursor with a custom Allocator
cuviper Jan 20, 2022
6706ab8
keyword_docs: document use of `in` with `pub` keyword
mfrw Feb 6, 2022
d4686c6
Use verbatim paths for `process::Command` if necessary
ChrisDenton Jan 5, 2022
93f627d
Keep the path after `program_exists` succeeds
ChrisDenton Feb 17, 2022
ee02f01
Consistently present absent stdio handles on Windows as NULL handles.
sunfishcode Jan 21, 2022
7dd3246
Fix a compilation error.
sunfishcode Jan 25, 2022
7ddf41c
Remove redundant code for handling NULL handles on Windows.
sunfishcode Mar 2, 2022
7a74d28
fix return values in L4Re networking stub
humenda Jun 18, 2020
11b7176
fix return value of LookupHost::port()
humenda Dec 5, 2018
898f379
drop unused libc imports on L4Re
atopia May 31, 2021
c0dc41f
L4Re does not support sanitizing standard streams
atopia Jun 2, 2021
997dc58
adapt L4Re network interface mock to #87329
atopia Oct 18, 2021
cb013d4
put L4Re specifics into their own platform
atopia Oct 18, 2021
bc199b5
add as_raw() method to L4Re's Socket mock
atopia Jan 14, 2022
7d44316
Bump impl Write for Cursor<[u8; N]> to 1.61
dtolnay Mar 18, 2022
d5fe4ca
add CStr::from_bytes_until_nul
ericseppanen Mar 15, 2022
52061cd
Rollup merge of #92519 - ChrisDenton:command-maybe-verbatim, r=dtolnay
Dylan-DPC Mar 19, 2022
59e51a8
Rollup merge of #92612 - atopia:update-lib-l4re, r=dtolnay
Dylan-DPC Mar 19, 2022
e2cb281
Rollup merge of #92663 - cuviper:generic-write-cursor, r=dtolnay
Dylan-DPC Mar 19, 2022
e7e6f63
Rollup merge of #93263 - sunfishcode:sunfishcode/detatched-console-ha…
Dylan-DPC Mar 19, 2022
c437730
Rollup merge of #93692 - mfrw:mfrw/document-keyword-in, r=dtolnay
Dylan-DPC Mar 19, 2022
79c935a
Rollup merge of #94984 - ericseppanen:cstr_from_bytes, r=Mark-Simulacrum
Dylan-DPC Mar 19, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
69 changes: 69 additions & 0 deletions library/std/src/ffi/c_str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -328,6 +328,27 @@ impl FromVecWithNulError {
}
}

/// An error indicating that no nul byte was present.
///
/// A slice used to create a [`CStr`] must contain a nul byte somewhere
/// within the slice.
///
/// This error is created by the [`CStr::from_bytes_until_nul`] method.
///
#[derive(Clone, PartialEq, Eq, Debug)]
#[unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")]
pub struct FromBytesUntilNulError(());

#[unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")]
impl Error for FromBytesUntilNulError {}

#[unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")]
impl fmt::Display for FromBytesUntilNulError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "data provided does not contain a nul")
}
}

/// An error indicating invalid UTF-8 when converting a [`CString`] into a [`String`].
///
/// `CString` is just a wrapper over a buffer of bytes with a nul terminator;
Expand Down Expand Up @@ -1239,12 +1260,60 @@ impl CStr {
}
}

/// Creates a C string wrapper from a byte slice.
///
/// This method will create a `CStr` from any byte slice that contains at
/// least one nul byte. The caller does not need to know or specify where
/// the nul byte is located.
///
/// If the first byte is a nul character, this method will return an
/// empty `CStr`. If multiple nul characters are present, the `CStr` will
/// end at the first one.
///
/// If the slice only has a single nul byte at the end, this method is
/// equivalent to [`CStr::from_bytes_with_nul`].
///
/// # Examples
/// ```
/// #![feature(cstr_from_bytes_until_nul)]
///
/// use std::ffi::CStr;
///
/// let mut buffer = [0u8; 16];
/// unsafe {
/// // Here we might call an unsafe C function that writes a string
/// // into the buffer.
/// let buf_ptr = buffer.as_mut_ptr();
/// buf_ptr.write_bytes(b'A', 8);
/// }
/// // Attempt to extract a C nul-terminated string from the buffer.
/// let c_str = CStr::from_bytes_until_nul(&buffer[..]).unwrap();
/// assert_eq!(c_str.to_str().unwrap(), "AAAAAAAA");
/// ```
///
#[unstable(feature = "cstr_from_bytes_until_nul", issue = "95027")]
pub fn from_bytes_until_nul(bytes: &[u8]) -> Result<&CStr, FromBytesUntilNulError> {
let nul_pos = memchr::memchr(0, bytes);
match nul_pos {
Some(nul_pos) => {
// SAFETY: We know there is a nul byte at nul_pos, so this slice
// (ending at the nul byte) is a well-formed C string.
let subslice = &bytes[..nul_pos + 1];
Ok(unsafe { CStr::from_bytes_with_nul_unchecked(subslice) })
}
None => Err(FromBytesUntilNulError(())),
}
}

/// Creates a C string wrapper from a byte slice.
///
/// This function will cast the provided `bytes` to a `CStr`
/// wrapper after ensuring that the byte slice is nul-terminated
/// and does not contain any interior nul bytes.
///
/// If the nul byte may not be at the end,
/// [`CStr::from_bytes_until_nul`] can be used instead.
///
/// # Examples
///
/// ```
Expand Down
37 changes: 37 additions & 0 deletions library/std/src/ffi/c_str/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,43 @@ fn from_bytes_with_nul_interior() {
assert!(cstr.is_err());
}

#[test]
fn cstr_from_bytes_until_nul() {
// Test an empty slice. This should fail because it
// does not contain a nul byte.
let b = b"";
assert_eq!(CStr::from_bytes_until_nul(&b[..]), Err(FromBytesUntilNulError(())));

// Test a non-empty slice, that does not contain a nul byte.
let b = b"hello";
assert_eq!(CStr::from_bytes_until_nul(&b[..]), Err(FromBytesUntilNulError(())));

// Test an empty nul-terminated string
let b = b"\0";
let r = CStr::from_bytes_until_nul(&b[..]).unwrap();
assert_eq!(r.to_bytes(), b"");

// Test a slice with the nul byte in the middle
let b = b"hello\0world!";
let r = CStr::from_bytes_until_nul(&b[..]).unwrap();
assert_eq!(r.to_bytes(), b"hello");

// Test a slice with the nul byte at the end
let b = b"hello\0";
let r = CStr::from_bytes_until_nul(&b[..]).unwrap();
assert_eq!(r.to_bytes(), b"hello");

// Test a slice with two nul bytes at the end
let b = b"hello\0\0";
let r = CStr::from_bytes_until_nul(&b[..]).unwrap();
assert_eq!(r.to_bytes(), b"hello");

// Test a slice containing lots of nul bytes
let b = b"\0\0\0\0";
let r = CStr::from_bytes_until_nul(&b[..]).unwrap();
assert_eq!(r.to_bytes(), b"");
}

#[test]
fn into_boxed() {
let orig: &[u8] = b"Hello, world!\0";
Expand Down
53 changes: 46 additions & 7 deletions library/std/src/io/cursor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ mod tests;

use crate::io::prelude::*;

use crate::alloc::Allocator;
use crate::cmp;
use crate::io::{self, ErrorKind, IoSlice, IoSliceMut, ReadBuf, SeekFrom};

Expand Down Expand Up @@ -398,7 +399,10 @@ fn slice_write_vectored(
}

// Resizing write implementation
fn vec_write(pos_mut: &mut u64, vec: &mut Vec<u8>, buf: &[u8]) -> io::Result<usize> {
fn vec_write<A>(pos_mut: &mut u64, vec: &mut Vec<u8, A>, buf: &[u8]) -> io::Result<usize>
where
A: Allocator,
{
let pos: usize = (*pos_mut).try_into().map_err(|_| {
io::const_io_error!(
ErrorKind::InvalidInput,
Expand Down Expand Up @@ -426,11 +430,14 @@ fn vec_write(pos_mut: &mut u64, vec: &mut Vec<u8>, buf: &[u8]) -> io::Result<usi
Ok(buf.len())
}

fn vec_write_vectored(
fn vec_write_vectored<A>(
pos_mut: &mut u64,
vec: &mut Vec<u8>,
vec: &mut Vec<u8, A>,
bufs: &[IoSlice<'_>],
) -> io::Result<usize> {
) -> io::Result<usize>
where
A: Allocator,
{
let mut nwritten = 0;
for buf in bufs {
nwritten += vec_write(pos_mut, vec, buf)?;
Expand Down Expand Up @@ -462,7 +469,10 @@ impl Write for Cursor<&mut [u8]> {
}

#[stable(feature = "cursor_mut_vec", since = "1.25.0")]
impl Write for Cursor<&mut Vec<u8>> {
impl<A> Write for Cursor<&mut Vec<u8, A>>
where
A: Allocator,
{
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
vec_write(&mut self.pos, self.inner, buf)
}
Expand All @@ -483,7 +493,10 @@ impl Write for Cursor<&mut Vec<u8>> {
}

#[stable(feature = "rust1", since = "1.0.0")]
impl Write for Cursor<Vec<u8>> {
impl<A> Write for Cursor<Vec<u8, A>>
where
A: Allocator,
{
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
vec_write(&mut self.pos, &mut self.inner, buf)
}
Expand All @@ -504,7 +517,33 @@ impl Write for Cursor<Vec<u8>> {
}

#[stable(feature = "cursor_box_slice", since = "1.5.0")]
impl Write for Cursor<Box<[u8]>> {
impl<A> Write for Cursor<Box<[u8], A>>
where
A: Allocator,
{
#[inline]
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
slice_write(&mut self.pos, &mut self.inner, buf)
}

#[inline]
fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
slice_write_vectored(&mut self.pos, &mut self.inner, bufs)
}

#[inline]
fn is_write_vectored(&self) -> bool {
true
}

#[inline]
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}

#[stable(feature = "cursor_array", since = "1.61.0")]
impl<const N: usize> Write for Cursor<[u8; N]> {
#[inline]
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
slice_write(&mut self.pos, &mut self.inner, buf)
Expand Down
84 changes: 40 additions & 44 deletions library/std/src/io/cursor/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,9 +50,11 @@ fn test_mem_mut_writer() {
assert_eq!(&writer.get_ref()[..], b);
}

#[test]
fn test_box_slice_writer() {
let mut writer = Cursor::new(vec![0u8; 9].into_boxed_slice());
fn test_slice_writer<T>(writer: &mut Cursor<T>)
where
T: AsRef<[u8]>,
Cursor<T>: Write,
{
assert_eq!(writer.position(), 0);
assert_eq!(writer.write(&[0]).unwrap(), 1);
assert_eq!(writer.position(), 1);
Expand All @@ -65,12 +67,14 @@ fn test_box_slice_writer() {
assert_eq!(writer.write(&[8, 9]).unwrap(), 1);
assert_eq!(writer.write(&[10]).unwrap(), 0);
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8];
assert_eq!(&**writer.get_ref(), b);
assert_eq!(writer.get_ref().as_ref(), b);
}

#[test]
fn test_box_slice_writer_vectored() {
let mut writer = Cursor::new(vec![0u8; 9].into_boxed_slice());
fn test_slice_writer_vectored<T>(writer: &mut Cursor<T>)
where
T: AsRef<[u8]>,
Cursor<T>: Write,
{
assert_eq!(writer.position(), 0);
assert_eq!(writer.write_vectored(&[IoSlice::new(&[0])]).unwrap(), 1);
assert_eq!(writer.position(), 1);
Expand All @@ -85,53 +89,45 @@ fn test_box_slice_writer_vectored() {
assert_eq!(writer.write_vectored(&[IoSlice::new(&[8, 9])]).unwrap(), 1);
assert_eq!(writer.write_vectored(&[IoSlice::new(&[10])]).unwrap(), 0);
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8];
assert_eq!(&**writer.get_ref(), b);
assert_eq!(writer.get_ref().as_ref(), b);
}

#[test]
fn test_box_slice_writer() {
let mut writer = Cursor::new(vec![0u8; 9].into_boxed_slice());
test_slice_writer(&mut writer);
}

#[test]
fn test_box_slice_writer_vectored() {
let mut writer = Cursor::new(vec![0u8; 9].into_boxed_slice());
test_slice_writer_vectored(&mut writer);
}

#[test]
fn test_array_writer() {
let mut writer = Cursor::new([0u8; 9]);
test_slice_writer(&mut writer);
}

#[test]
fn test_array_writer_vectored() {
let mut writer = Cursor::new([0u8; 9]);
test_slice_writer_vectored(&mut writer);
}

#[test]
fn test_buf_writer() {
let mut buf = [0 as u8; 9];
{
let mut writer = Cursor::new(&mut buf[..]);
assert_eq!(writer.position(), 0);
assert_eq!(writer.write(&[0]).unwrap(), 1);
assert_eq!(writer.position(), 1);
assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3);
assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4);
assert_eq!(writer.position(), 8);
assert_eq!(writer.write(&[]).unwrap(), 0);
assert_eq!(writer.position(), 8);

assert_eq!(writer.write(&[8, 9]).unwrap(), 1);
assert_eq!(writer.write(&[10]).unwrap(), 0);
}
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8];
assert_eq!(buf, b);
let mut writer = Cursor::new(&mut buf[..]);
test_slice_writer(&mut writer);
}

#[test]
fn test_buf_writer_vectored() {
let mut buf = [0 as u8; 9];
{
let mut writer = Cursor::new(&mut buf[..]);
assert_eq!(writer.position(), 0);
assert_eq!(writer.write_vectored(&[IoSlice::new(&[0])]).unwrap(), 1);
assert_eq!(writer.position(), 1);
assert_eq!(
writer
.write_vectored(&[IoSlice::new(&[1, 2, 3]), IoSlice::new(&[4, 5, 6, 7])],)
.unwrap(),
7,
);
assert_eq!(writer.position(), 8);
assert_eq!(writer.write_vectored(&[]).unwrap(), 0);
assert_eq!(writer.position(), 8);

assert_eq!(writer.write_vectored(&[IoSlice::new(&[8, 9])]).unwrap(), 1);
assert_eq!(writer.write_vectored(&[IoSlice::new(&[10])]).unwrap(), 0);
}
let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8];
assert_eq!(buf, b);
let mut writer = Cursor::new(&mut buf[..]);
test_slice_writer_vectored(&mut writer);
}

#[test]
Expand Down
Loading