diff --git a/library/std/src/os/unix/net/addr.rs b/library/std/src/os/unix/net/addr.rs index e13f44d6fc9bd..92f30ae4605cb 100644 --- a/library/std/src/os/unix/net/addr.rs +++ b/library/std/src/os/unix/net/addr.rs @@ -255,12 +255,10 @@ impl SocketAddr { } else if self.addr.sun_path[0] == 0 { AddressKind::Abstract(ByteStr::from_bytes(&path[1..len])) } else { - // the value returned by getsockname(2) and similar on QNX7.1 and - // QNX8 does not count the NUL byte terminator of the path string, - // which matches the behavior of the SUN_LEN macro in libc, but - // other OSes do count the NUL byte so adjust accordingly - let end = - if cfg!(any(target_os = "qnx", target_env = "nto71")) { len } else { len - 1 }; + // linux adds a trailing NUL and counts it in the length, freebsd, netbsd + // and qnx do not, and a caller may bind(2) without one either. unix(7) + // gives the portable rule: strnlen(sun_path, len - offsetof(sun_path)) + let end = core::slice::memchr::memchr(0, &path[..len]).unwrap_or(len); AddressKind::Pathname(OsStr::from_bytes(&path[..end]).as_ref()) } } diff --git a/library/std/src/os/unix/net/tests.rs b/library/std/src/os/unix/net/tests.rs index 3ba4b44d2f1ef..9c3119e787b33 100644 --- a/library/std/src/os/unix/net/tests.rs +++ b/library/std/src/os/unix/net/tests.rs @@ -29,6 +29,29 @@ fn sock_addr_from_pathname() { assert_eq!(address.as_pathname(), Some(Path::new("/path/to/socket"))); } +// the trailing NUL is not counted in the reported length on freebsd, netbsd +// and qnx, and a caller may bind(2) without one anywhere +#[test] +fn sock_addr_without_trailing_nul() { + const PATH: &[u8] = b"/path/to/socket"; + + // SAFETY: all zeros is a valid representation for `sockaddr_un`. + let mut addr: libc::sockaddr_un = unsafe { crate::mem::zeroed() }; + addr.sun_family = libc::AF_UNIX as libc::sa_family_t; + for (dst, &src) in addr.sun_path.iter_mut().zip(PATH) { + *dst = src as _; + } + let offset = crate::mem::offset_of!(libc::sockaddr_un, sun_path); + + // length excluding the NUL, as reported by freebsd, netbsd and qnx + let address = or_panic!(SocketAddr::from_parts(addr, (offset + PATH.len()) as _)); + assert_eq!(address.as_pathname(), Some(Path::new("/path/to/socket"))); + + // length including the NUL, as reported by linux + let address = or_panic!(SocketAddr::from_parts(addr, (offset + PATH.len() + 1) as _)); + assert_eq!(address.as_pathname(), Some(Path::new("/path/to/socket"))); +} + #[test] #[cfg_attr(target_os = "android", ignore)] // Android SELinux rules prevent creating Unix sockets #[cfg_attr(target_os = "vxworks", ignore = "Unix sockets are not implemented in VxWorks")]