From a94c3257b1720fa395474df9cdbf32b322ea62fc Mon Sep 17 00:00:00 2001 From: "Jeong, YunWon" Date: Mon, 3 Aug 2026 19:17:13 +0900 Subject: [PATCH] socket: accept a filesystem-encoded hostname in sethostname MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `socket.sethostname` took `PyUtf8StrRef`, so it rejected `bytes` outright and refused a `str` carrying a surrogate escape. `socketmodule.c socket_sethostname` accepts a bytes object directly, falls back to `PyUnicode_FSConverter` for anything else, and hands the syscall the resulting buffer and its length — the name is never required to be UTF-8. Take `FsPath`, the converter `if_nametoindex` in this same module already uses, and pass its bytes down. `host_env::socket::sethostname` correspondingly takes `&[u8]` and builds the `OsStr` from them; `nix::unistd::sethostname` accepts `AsRef` and passes pointer and length to the syscall, so nothing on the path needs a NUL terminator or valid UTF-8. `Lib/test/test_socket.py test_sethostname` covers this: it calls `socket.sethostname(b'bar')` and asserts the hostname changed. The test is skipped unless run as root, which is why the gap went unnoticed. Assisted-by: Claude --- crates/host_env/src/socket.rs | 10 ++++++++-- crates/stdlib/src/socket.rs | 4 ++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/crates/host_env/src/socket.rs b/crates/host_env/src/socket.rs index af4af2717cd..542031e6fa8 100644 --- a/crates/host_env/src/socket.rs +++ b/crates/host_env/src/socket.rs @@ -44,9 +44,15 @@ pub use libc::{AF_ALG, AF_CAN}; #[cfg(target_os = "linux")] pub use libc::{sockaddr_alg, sockaddr_can}; +/// Set the system's hostname from its filesystem-encoded bytes. +/// +/// `socketmodule.c socket_sethostname` reads the argument as a buffer and +/// passes `buf.buf`/`buf.len` straight to the syscall, so a name is not +/// required to be UTF-8; taking `&[u8]` keeps that true here as well. #[cfg(all(unix, not(target_os = "redox")))] -pub fn sethostname(hostname: &str) -> io::Result<()> { - nix::unistd::sethostname(hostname).map_err(io::Error::from) +pub fn sethostname(hostname: &[u8]) -> io::Result<()> { + use std::os::unix::ffi::OsStrExt; + nix::unistd::sethostname(std::ffi::OsStr::from_bytes(hostname)).map_err(io::Error::from) } #[cfg(unix)] diff --git a/crates/stdlib/src/socket.rs b/crates/stdlib/src/socket.rs index 968399ca782..e4f7a491658 100644 --- a/crates/stdlib/src/socket.rs +++ b/crates/stdlib/src/socket.rs @@ -2325,8 +2325,8 @@ mod _socket { #[cfg(all(unix, not(any(target_os = "redox", target_os = "android"))))] #[pyfunction] - fn sethostname(hostname: PyUtf8StrRef) -> std::io::Result<()> { - host_socket::sethostname(hostname.as_str()) + fn sethostname(hostname: FsPath) -> std::io::Result<()> { + host_socket::sethostname(hostname.as_bytes()) } #[pyfunction]