Skip to content

Commit 7c1a25a

Browse files
authored
Merge pull request #9429 from naoNao89/fix/stdbuf-remove-unwrap
Remove unsafe unwrap() calls in stdbuf error handling
2 parents 2a314c7 + e0c7ef7 commit 7c1a25a

2 files changed

Lines changed: 41 additions & 8 deletions

File tree

src/uu/stdbuf/src/stdbuf.rs

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77

88
use clap::{Arg, ArgAction, ArgMatches, Command};
99
use std::ffi::OsString;
10-
use std::os::unix::process::ExitStatusExt;
1110
use std::path::PathBuf;
1211
use std::process;
1312
use tempfile::TempDir;
@@ -188,11 +187,17 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
188187
let options =
189188
ProgramOptions::try_from(&matches).map_err(|e| UUsageError::new(125, e.to_string()))?;
190189

191-
let mut command_values = matches.get_many::<OsString>(options::COMMAND).unwrap();
192-
let mut command = process::Command::new(command_values.next().unwrap());
190+
let mut command_values = matches
191+
.get_many::<OsString>(options::COMMAND)
192+
.ok_or_else(|| UUsageError::new(125, "no command specified".to_string()))?;
193+
let Some(first_command) = command_values.next() else {
194+
return Err(UUsageError::new(125, "no command specified".to_string()));
195+
};
196+
let mut command = process::Command::new(first_command);
193197
let command_params: Vec<&OsString> = command_values.collect();
194198

195-
let tmp_dir = tempdir().unwrap();
199+
let tmp_dir = tempdir()
200+
.map_err(|e| UUsageError::new(125, format!("failed to create temp directory: {e}")))?;
196201
let (preload_env, libstdbuf) = get_preload_env(&tmp_dir)?;
197202
command.env(preload_env, libstdbuf);
198203
set_command_env(&mut command, "_STDBUF_I", &options.stdin);
@@ -229,10 +234,27 @@ pub fn uumain(args: impl uucore::Args) -> UResult<()> {
229234
Err(i.into())
230235
}
231236
}
232-
None => Err(USimpleError::new(
233-
1,
234-
translate!("stdbuf-error-killed-by-signal", "signal" => status.signal().unwrap()),
235-
)),
237+
None => {
238+
#[cfg(unix)]
239+
{
240+
use std::os::unix::process::ExitStatusExt;
241+
let signal_msg = status
242+
.signal()
243+
.map(|s| s.to_string())
244+
.unwrap_or_else(|| "unknown".to_string());
245+
Err(USimpleError::new(
246+
1,
247+
translate!("stdbuf-error-killed-by-signal", "signal" => signal_msg),
248+
))
249+
}
250+
#[cfg(not(unix))]
251+
{
252+
Err(USimpleError::new(
253+
1,
254+
"process terminated abnormally".to_string(),
255+
))
256+
}
257+
}
236258
}
237259
}
238260

tests/by-util/test_stdbuf.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,17 @@ fn test_stdbuf_no_buffer_option_fails() {
8787
.stderr_contains("the following required arguments were not provided:");
8888
}
8989

90+
#[cfg(not(target_os = "windows"))]
91+
#[test]
92+
fn test_stdbuf_no_command_fails_with_125() {
93+
// Test that missing command fails with exit code 125 (stdbuf error)
94+
// This verifies proper error handling without unwrap panic
95+
new_ucmd!()
96+
.args(&["-o1"])
97+
.fails_with_code(125)
98+
.stderr_contains("the following required arguments were not provided:");
99+
}
100+
90101
// Disabled on x86_64-unknown-linux-musl because the cross-rs Docker image for this target
91102
// does not provide musl-compiled system utilities (like tail), leading to dynamic linker errors
92103
// when preloading musl-compiled libstdbuf.so into glibc-compiled binaries. Same thing for FreeBSD.

0 commit comments

Comments
 (0)