From 6be47a6d92d136d121b911d2cd3f15ccb4096c49 Mon Sep 17 00:00:00 2001 From: oech3 <79379754+oech3@users.noreply.github.com> Date: Tue, 16 Jun 2026 23:27:51 +0900 Subject: [PATCH] cmp: remove unsafe & don't open unnecessary /dev/null --- Cargo.lock | 1 + Cargo.toml | 1 + fuzz/Cargo.lock | 36 ++++++++++++++++++++++++++++++++++++ src/cmp.rs | 26 ++++---------------------- 4 files changed, 42 insertions(+), 22 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4d1bf647..1a99af50 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -273,6 +273,7 @@ dependencies = [ "pretty_assertions", "rand", "regex", + "rustix", "same-file", "tempfile", "unicode-width", diff --git a/Cargo.toml b/Cargo.toml index 16738396..2dd8a101 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -19,6 +19,7 @@ chrono = "0.4.38" diff = "0.1.13" itoa = "1.0.11" regex = "1.10.4" +rustix = { version = "1.1.4", features = ["fs"] } same-file = "1.0.6" unicode-width = "0.2.0" diff --git a/fuzz/Cargo.lock b/fuzz/Cargo.lock index 47a03af4..0d4c7a29 100644 --- a/fuzz/Cargo.lock +++ b/fuzz/Cargo.lock @@ -32,6 +32,12 @@ version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" +[[package]] +name = "bitflags" +version = "2.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8" + [[package]] name = "bumpalo" version = "3.20.2" @@ -89,10 +95,21 @@ dependencies = [ "diff", "itoa", "regex", + "rustix", "same-file", "unicode-width", ] +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys", +] + [[package]] name = "find-msvc-tools" version = "0.1.9" @@ -177,6 +194,12 @@ dependencies = [ "cc", ] +[[package]] +name = "linux-raw-sys" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" + [[package]] name = "log" version = "0.4.29" @@ -257,6 +280,19 @@ version = "0.8.10" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" +[[package]] +name = "rustix" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + [[package]] name = "rustversion" version = "1.0.22" diff --git a/src/cmp.rs b/src/cmp.rs index 0175466e..9939604e 100644 --- a/src/cmp.rs +++ b/src/cmp.rs @@ -11,12 +11,6 @@ use std::iter::Peekable; use std::process::ExitCode; use std::{cmp, fs, io}; -#[cfg(unix)] -use std::os::fd::{AsRawFd, FromRawFd}; - -#[cfg(unix)] -use std::os::unix::fs::MetadataExt; - #[cfg(target_os = "windows")] use std::os::windows::fs::MetadataExt; @@ -45,24 +39,12 @@ fn usage_string(executable: &str) -> String { #[cfg(unix)] fn is_stdout_dev_null() -> bool { - let Ok(dev_null) = fs::metadata("/dev/null") else { + let stdout = io::stdout(); + let Ok(stat) = rustix::fs::fstat(stdout) else { return false; }; - - let stdout_fd = io::stdout().lock().as_raw_fd(); - - // SAFETY: we have exclusive access to stdout right now. - let stdout_file = unsafe { fs::File::from_raw_fd(stdout_fd) }; - let Ok(stdout) = stdout_file.metadata() else { - return false; - }; - - let is_dev_null = stdout.dev() == dev_null.dev() && stdout.ino() == dev_null.ino(); - - // Don't let File close the fd. It's unfortunate that File doesn't have a leak_fd(). - std::mem::forget(stdout_file); - - is_dev_null + let dev = stat.st_rdev; + rustix::fs::major(dev) == 1 && rustix::fs::minor(dev) == 3 } #[cfg(not(any(unix, target_os = "windows")))]