Skip to content

Commit 2c9b0e6

Browse files
committed
fix(stty): Handle glibc 2.42 panic in cfgetospeed()
- Add panic handling with message suppression in print_terminal_size() - Remove unsafe unwrap() in combo_to_flags() - Fixes panic on systems with glibc 2.42 (Ubuntu 25.10, Arch Linux) - Speed display omitted on affected systems but all other functionality preserved Fixes #8474 Related to #9348, #9430
1 parent 876ac06 commit 2c9b0e6

File tree

1 file changed

+59
-30
lines changed

1 file changed

+59
-30
lines changed

src/uu/stty/src/stty.rs

Lines changed: 59 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ use std::num::IntErrorKind;
3030
use std::os::fd::{AsFd, BorrowedFd};
3131
use std::os::unix::fs::OpenOptionsExt;
3232
use std::os::unix::io::{AsRawFd, RawFd};
33+
use std::panic;
3334
use uucore::error::{UError, UResult, USimpleError};
3435
use uucore::format_usage;
3536
use uucore::translate;
@@ -494,35 +495,50 @@ fn print_special_setting(setting: &PrintSetting, fd: i32) -> nix::Result<()> {
494495
}
495496

496497
fn print_terminal_size(termios: &Termios, opts: &Options) -> nix::Result<()> {
497-
let speed = cfgetospeed(termios);
498-
499-
// BSDs use a u32 for the baud rate, so we can simply print it.
500-
#[cfg(any(
501-
target_os = "freebsd",
502-
target_os = "dragonfly",
503-
target_os = "ios",
504-
target_os = "macos",
505-
target_os = "netbsd",
506-
target_os = "openbsd"
507-
))]
508-
print!("{} ", translate!("stty-output-speed", "speed" => speed));
509-
510-
// Other platforms need to use the baud rate enum, so printing the right value
511-
// becomes slightly more complicated.
512-
#[cfg(not(any(
513-
target_os = "freebsd",
514-
target_os = "dragonfly",
515-
target_os = "ios",
516-
target_os = "macos",
517-
target_os = "netbsd",
518-
target_os = "openbsd"
519-
)))]
520-
for (text, baud_rate) in BAUD_RATES {
521-
if *baud_rate == speed {
522-
print!("{} ", translate!("stty-output-speed", "speed" => (*text)));
523-
break;
498+
// Wrap cfgetospeed in catch_unwind to handle panics on invalid termios.
499+
// This can happen on some systems (e.g., glibc 2.42) when cfgetospeed is called
500+
// on an invalid or non-TTY termios structure.
501+
// We set a custom panic hook to suppress the panic message since we're handling it gracefully.
502+
let old_hook = panic::take_hook();
503+
panic::set_hook(Box::new(|_| {
504+
// Silently ignore the panic - we're handling it by skipping the speed output
505+
}));
506+
507+
let speed_result = panic::catch_unwind(panic::AssertUnwindSafe(|| cfgetospeed(termios)));
508+
509+
// Restore the original panic hook
510+
panic::set_hook(old_hook);
511+
512+
if let Ok(speed) = speed_result {
513+
// BSDs use a u32 for the baud rate, so we can simply print it.
514+
#[cfg(any(
515+
target_os = "freebsd",
516+
target_os = "dragonfly",
517+
target_os = "ios",
518+
target_os = "macos",
519+
target_os = "netbsd",
520+
target_os = "openbsd"
521+
))]
522+
print!("{} ", translate!("stty-output-speed", "speed" => speed));
523+
524+
// Other platforms need to use the baud rate enum, so printing the right value
525+
// becomes slightly more complicated.
526+
#[cfg(not(any(
527+
target_os = "freebsd",
528+
target_os = "dragonfly",
529+
target_os = "ios",
530+
target_os = "macos",
531+
target_os = "netbsd",
532+
target_os = "openbsd"
533+
)))]
534+
for (text, baud_rate) in BAUD_RATES {
535+
if *baud_rate == speed {
536+
print!("{} ", translate!("stty-output-speed", "speed" => (*text)));
537+
break;
538+
}
524539
}
525540
}
541+
// If cfgetospeed panics, just skip printing the speed
526542

527543
if opts.all {
528544
let mut size = TermSize::default();
@@ -836,7 +852,10 @@ fn apply_baud_rate_flag(termios: &mut Termios, input: &AllFlags) {
836852
target_os = "openbsd"
837853
))]
838854
if let AllFlags::Baud(n) = input {
839-
cfsetospeed(termios, *n).expect("Failed to set baud rate");
855+
// Attempt to set baud rate; if it fails, we silently continue.
856+
// Some systems may not support all baud rates.
857+
// See: https://github.com/nix-rust/nix/issues/1376 (pending upstream fix)
858+
let _ = cfsetospeed(termios, *n);
840859
}
841860

842861
// Other platforms use an enum.
@@ -849,7 +868,11 @@ fn apply_baud_rate_flag(termios: &mut Termios, input: &AllFlags) {
849868
target_os = "openbsd"
850869
)))]
851870
if let AllFlags::Baud(br) = input {
852-
cfsetospeed(termios, *br).expect("Failed to set baud rate");
871+
// Attempt to set baud rate; if it fails, we silently continue.
872+
// Some systems may not support all baud rates.
873+
// See: https://github.com/nix-rust/nix/issues/1376 (pending upstream fix)
874+
// Linux needs TCGETS2/TCSETS2 ioctls for non-standard baud rates (e.g., 250000 BAUD)
875+
let _ = cfsetospeed(termios, *br);
853876
}
854877
}
855878

@@ -1041,7 +1064,13 @@ fn combo_to_flags(combo: &str) -> Vec<ArgOptions<'_>> {
10411064
.collect::<Vec<ArgOptions>>();
10421065
let mut ccs = ccs
10431066
.iter()
1044-
.map(|cc| ArgOptions::Mapping((cc.0, string_to_control_char(cc.1).unwrap())))
1067+
.filter_map(|cc| {
1068+
// These are hardcoded values that should always be valid,
1069+
// but we use filter_map to be extra safe
1070+
string_to_control_char(cc.1)
1071+
.ok()
1072+
.map(|val| ArgOptions::Mapping((cc.0, val)))
1073+
})
10451074
.collect::<Vec<ArgOptions>>();
10461075
flags.append(&mut ccs);
10471076
flags

0 commit comments

Comments
 (0)