about summary refs log tree commit diff
path: root/library/std/src
diff options
context:
space:
mode:
Diffstat (limited to 'library/std/src')
-rw-r--r--library/std/src/ffi/c_str.rs6
-rw-r--r--library/std/src/ffi/c_str/tests.rs16
-rw-r--r--library/std/src/sys/unix/ext/net/ancillary.rs57
3 files changed, 54 insertions, 25 deletions
diff --git a/library/std/src/ffi/c_str.rs b/library/std/src/ffi/c_str.rs
index 687ed61b959..ed4950c57a6 100644
--- a/library/std/src/ffi/c_str.rs
+++ b/library/std/src/ffi/c_str.rs
@@ -613,7 +613,8 @@ impl CString {
     #[inline]
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn as_bytes(&self) -> &[u8] {
-        &self.inner[..self.inner.len() - 1]
+        // SAFETY: CString has a length at least 1
+        unsafe { self.inner.get_unchecked(..self.inner.len() - 1) }
     }
 
     /// Equivalent to [`CString::as_bytes()`] except that the
@@ -1322,7 +1323,8 @@ impl CStr {
     #[stable(feature = "rust1", since = "1.0.0")]
     pub fn to_bytes(&self) -> &[u8] {
         let bytes = self.to_bytes_with_nul();
-        &bytes[..bytes.len() - 1]
+        // SAFETY: to_bytes_with_nul returns slice with length at least 1
+        unsafe { bytes.get_unchecked(..bytes.len() - 1) }
     }
 
     /// Converts this C string to a byte slice containing the trailing 0 byte.
diff --git a/library/std/src/ffi/c_str/tests.rs b/library/std/src/ffi/c_str/tests.rs
index 4dff3df63a8..4f7ba9ad437 100644
--- a/library/std/src/ffi/c_str/tests.rs
+++ b/library/std/src/ffi/c_str/tests.rs
@@ -193,3 +193,19 @@ fn cstr_index_from_empty() {
     let cstr = CStr::from_bytes_with_nul(original).unwrap();
     let _ = &cstr[original.len()..];
 }
+
+#[test]
+fn c_string_from_empty_string() {
+    let original = "";
+    let cstring = CString::new(original).unwrap();
+    assert_eq!(original.as_bytes(), cstring.as_bytes());
+    assert_eq!([b'\0'], cstring.as_bytes_with_nul());
+}
+
+#[test]
+fn c_str_from_empty_string() {
+    let original = b"\0";
+    let cstr = CStr::from_bytes_with_nul(original).unwrap();
+    assert_eq!([] as [u8; 0], cstr.to_bytes());
+    assert_eq!([b'\0'], cstr.to_bytes_with_nul());
+}
diff --git a/library/std/src/sys/unix/ext/net/ancillary.rs b/library/std/src/sys/unix/ext/net/ancillary.rs
index 33d6a39af07..011ae643f87 100644
--- a/library/std/src/sys/unix/ext/net/ancillary.rs
+++ b/library/std/src/sys/unix/ext/net/ancillary.rs
@@ -5,9 +5,7 @@ use crate::marker::PhantomData;
 use crate::mem::{size_of, zeroed};
 use crate::os::unix::io::RawFd;
 use crate::path::Path;
-#[cfg(target_os = "android")]
-use crate::ptr::eq;
-use crate::ptr::read_unaligned;
+use crate::ptr::{eq, read_unaligned};
 use crate::slice::from_raw_parts;
 use crate::sys::net::Socket;
 
@@ -30,12 +28,10 @@ pub(super) fn recv_vectored_with_ancillary_from(
 ) -> io::Result<(usize, bool, io::Result<SocketAddr>)> {
     unsafe {
         let mut msg_name: libc::sockaddr_un = zeroed();
-
         let mut msg: libc::msghdr = zeroed();
         msg.msg_name = &mut msg_name as *mut _ as *mut _;
         msg.msg_namelen = size_of::<libc::sockaddr_un>() as libc::socklen_t;
         msg.msg_iov = bufs.as_mut_ptr().cast();
-        msg.msg_control = ancillary.buffer.as_mut_ptr().cast();
         cfg_if::cfg_if! {
             if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] {
                 msg.msg_iovlen = bufs.len() as libc::size_t;
@@ -45,6 +41,7 @@ pub(super) fn recv_vectored_with_ancillary_from(
                           target_os = "emscripten",
                           target_os = "freebsd",
                           all(target_os = "linux", target_env = "musl",),
+                          target_os = "macos",
                           target_os = "netbsd",
                           target_os = "openbsd",
                       ))] {
@@ -52,6 +49,10 @@ pub(super) fn recv_vectored_with_ancillary_from(
                 msg.msg_controllen = ancillary.buffer.len() as libc::socklen_t;
             }
         }
+        // macos requires that the control pointer is NULL when the len is 0.
+        if msg.msg_controllen > 0 {
+            msg.msg_control = ancillary.buffer.as_mut_ptr().cast();
+        }
 
         let count = socket.recv_msg(&mut msg)?;
 
@@ -79,7 +80,6 @@ pub(super) fn send_vectored_with_ancillary_to(
         msg.msg_name = &mut msg_name as *mut _ as *mut _;
         msg.msg_namelen = msg_namelen;
         msg.msg_iov = bufs.as_ptr() as *mut _;
-        msg.msg_control = ancillary.buffer.as_mut_ptr().cast();
         cfg_if::cfg_if! {
             if #[cfg(any(target_os = "android", all(target_os = "linux", target_env = "gnu")))] {
                 msg.msg_iovlen = bufs.len() as libc::size_t;
@@ -89,6 +89,7 @@ pub(super) fn send_vectored_with_ancillary_to(
                           target_os = "emscripten",
                           target_os = "freebsd",
                           all(target_os = "linux", target_env = "musl",),
+                          target_os = "macos",
                           target_os = "netbsd",
                           target_os = "openbsd",
                       ))] {
@@ -96,6 +97,10 @@ pub(super) fn send_vectored_with_ancillary_to(
                 msg.msg_controllen = ancillary.length as libc::socklen_t;
             }
         }
+        // macos requires that the control pointer is NULL when the len is 0.
+        if msg.msg_controllen > 0 {
+            msg.msg_control = ancillary.buffer.as_mut_ptr().cast();
+        }
 
         ancillary.truncated = false;
 
@@ -147,6 +152,7 @@ fn add_to_ancillary_data<T>(
                           target_os = "emscripten",
                           target_os = "freebsd",
                           all(target_os = "linux", target_env = "musl",),
+                          target_os = "macos",
                           target_os = "netbsd",
                           target_os = "openbsd",
                       ))] {
@@ -159,14 +165,12 @@ fn add_to_ancillary_data<T>(
         while !cmsg.is_null() {
             previous_cmsg = cmsg;
             cmsg = libc::CMSG_NXTHDR(&msg, cmsg);
-            cfg_if::cfg_if! {
-                // Android return the same pointer if it is the last cmsg.
-                // Therefore, check it if the previous pointer is the same as the current one.
-                if #[cfg(target_os = "android")] {
-                    if cmsg == previous_cmsg {
-                        break;
-                    }
-                }
+
+            // Most operating systems, but not Linux or emscripten, return the previous pointer
+            // when its length is zero. Therefore, check if the previous pointer is the same as
+            // the current one.
+            if eq(cmsg, previous_cmsg) {
+                break;
             }
         }
 
@@ -184,6 +188,7 @@ fn add_to_ancillary_data<T>(
                           target_os = "emscripten",
                           target_os = "freebsd",
                           all(target_os = "linux", target_env = "musl",),
+                          target_os = "macos",
                           target_os = "netbsd",
                           target_os = "openbsd",
                       ))] {
@@ -371,6 +376,7 @@ impl<'a> AncillaryData<'a> {
                               target_os = "emscripten",
                               target_os = "freebsd",
                               all(target_os = "linux", target_env = "musl",),
+                              target_os = "macos",
                               target_os = "netbsd",
                               target_os = "openbsd",
                           ))] {
@@ -421,6 +427,7 @@ impl<'a> Iterator for Messages<'a> {
                               target_os = "emscripten",
                               target_os = "freebsd",
                               all(target_os = "linux", target_env = "musl",),
+                              target_os = "macos",
                               target_os = "netbsd",
                               target_os = "openbsd",
                           ))] {
@@ -435,15 +442,13 @@ impl<'a> Iterator for Messages<'a> {
             };
 
             let cmsg = cmsg.as_ref()?;
-            cfg_if::cfg_if! {
-                // Android return the same pointer if it is the last cmsg.
-                // Therefore, check it if the previous pointer is the same as the current one.
-                if #[cfg(target_os = "android")] {
-                    if let Some(current) = self.current {
-                        if eq(current, cmsg) {
-                            return None;
-                        }
-                    }
+
+            // Most operating systems, but not Linux or emscripten, return the previous pointer
+            // when its length is zero. Therefore, check if the previous pointer is the same as
+            // the current one.
+            if let Some(current) = self.current {
+                if eq(current, cmsg) {
+                    return None;
                 }
             }
 
@@ -514,6 +519,12 @@ impl<'a> SocketAncillary<'a> {
         self.buffer.len()
     }
 
+    /// Returns `true` if the ancillary data is empty.
+    #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
+    pub fn is_empty(&self) -> bool {
+        self.length == 0
+    }
+
     /// Returns the number of used bytes.
     #[unstable(feature = "unix_socket_ancillary_data", issue = "76915")]
     pub fn len(&self) -> usize {