Skip to content

UnixStream doesn't set MSG_NOSIGNAL as UnixDatagram #139956

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

Open
mlowicki opened this issue Apr 17, 2025 · 0 comments
Open

UnixStream doesn't set MSG_NOSIGNAL as UnixDatagram #139956

mlowicki opened this issue Apr 17, 2025 · 0 comments
Labels
A-io Area: `std::io`, `std::fs`, `std::net` and `std::path` C-bug Category: This is a bug. T-libs Relevant to the library team, which will review and decide on the PR/issue.

Comments

@mlowicki
Copy link

mlowicki commented Apr 17, 2025

UnixDatagram sets MSG_NOSIGNAL when sending data (https://doc.rust-lang.org/src/std/os/unix/net/datagram.rs.html#516)

UnixStream doesn't have it.

Why it's important?

https://pubs.opengroup.org/onlinepubs/9699919799/functions/send.html:

[EPIPE]
The socket is shut down for writing, or the socket is connection-mode and is no longer connected. In the latter case, and if the socket is of type SOCK_STREAM or SOCK_SEQPACKET and the MSG_NOSIGNAL flag is not set, the SIGPIPE signal is generated to the calling thread.

So without MSG_NOSIGNAL writing to e.g. closed socket leads to SIGPIPE.

https://pkg.go.dev/os/signal#hdr-Go_programs_that_use_cgo_or_SWIG

If a SIGPIPE signal is received, the Go program will invoke the special handling described above if the SIGPIPE is received on a Go thread. If the SIGPIPE is received on a non-Go thread the signal will be forwarded to the non-Go handler, if any; if there is none the default system handler will cause the program to terminate.

It means Golang programs using Rust library terminate when underlying Rust library doesn't handle disconnected sockets properly (e.g. keep using closed socket).

Discovered problem with 1.83.0 but code for UnixStream doesn't seem to ever pass MSG_NOSIGNAL (so rather not a regression or so).

Apparently old behaviour from #62569 doesn't help neither as Golang runtime doesn't find non-Go signal handler when Rust lib is being used.

MSG_NOSIGNAL doesn't exist everywhere (e.g. not on macOS) so there we could use SO_NOSIGPIPE on a socket but it seems it's already done inside:

pub fn new_raw(fam: c_int, ty: c_int) -> io::Result<Socket> {
unsafe {
cfg_if::cfg_if! {
if #[cfg(any(
target_os = "android",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "illumos",
target_os = "hurd",
target_os = "linux",
target_os = "netbsd",
target_os = "openbsd",
target_os = "cygwin",
target_os = "nto",
target_os = "solaris",
))] {
// On platforms that support it we pass the SOCK_CLOEXEC
// flag to atomically create the socket and set it as
// CLOEXEC. On Linux this was added in 2.6.27.
let fd = cvt(libc::socket(fam, ty | libc::SOCK_CLOEXEC, 0))?;
let socket = Socket(FileDesc::from_raw_fd(fd));
// DragonFlyBSD, FreeBSD and NetBSD use `SO_NOSIGPIPE` as a `setsockopt`
// flag to disable `SIGPIPE` emission on socket.
#[cfg(any(target_os = "freebsd", target_os = "netbsd", target_os = "dragonfly"))]
setsockopt(&socket, libc::SOL_SOCKET, libc::SO_NOSIGPIPE, 1)?;
Ok(socket)
} else {
let fd = cvt(libc::socket(fam, ty, 0))?;
let fd = FileDesc::from_raw_fd(fd);
fd.set_cloexec()?;
let socket = Socket(fd);
// macOS and iOS use `SO_NOSIGPIPE` as a `setsockopt`
// flag to disable `SIGPIPE` emission on socket.
#[cfg(target_vendor = "apple")]
setsockopt(&socket, libc::SOL_SOCKET, libc::SO_NOSIGPIPE, 1)?;
Ok(socket)

Passing MSG_NOSIGNAL is handled for other types:

For UnixStream it's pure write on underlying file descriptor:

@mlowicki mlowicki added the C-bug Category: This is a bug. label Apr 17, 2025
@rustbot rustbot added the needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. label Apr 17, 2025
mlowicki added a commit to mlowicki/rust that referenced this issue Apr 18, 2025
@jieyouxu jieyouxu added T-libs Relevant to the library team, which will review and decide on the PR/issue. A-io Area: `std::io`, `std::fs`, `std::net` and `std::path` and removed needs-triage This issue may need triage. Remove it if it has been sufficiently triaged. labels Apr 18, 2025
mlowicki added a commit to mlowicki/rust that referenced this issue Apr 18, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-io Area: `std::io`, `std::fs`, `std::net` and `std::path` C-bug Category: This is a bug. T-libs Relevant to the library team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

3 participants