Skip to content

Commit 172e1d9

Browse files
committed
fix: prevent panic in cfgetospeed/cfgetispeed on glibc 2.42
Replace .unwrap() with .unwrap_or(BaudRate::B0) to gracefully handle conversion errors on glibc 2.42+. Fixes #2672 and uutils/coreutils#8474. - src/sys/termios.rs: cfgetospeed() and cfgetispeed() - test/sys/test_termios.rs: 4 new integration tests
1 parent 41e2f81 commit 172e1d9

File tree

2 files changed

+81
-2
lines changed

2 files changed

+81
-2
lines changed

src/sys/termios.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -753,18 +753,26 @@ cfg_if! {
753753
/// [cfgetispeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetispeed.html)).
754754
///
755755
/// `cfgetispeed()` extracts the input baud rate from the given `Termios` structure.
756+
///
757+
/// On glibc 2.42+, returns `BaudRate::B0` if the actual baud rate cannot be determined.
756758
pub fn cfgetispeed(termios: &Termios) -> BaudRate {
757759
let inner_termios = termios.get_libc_termios();
758-
unsafe { libc::cfgetispeed(&*inner_termios) }.try_into().unwrap()
760+
unsafe { libc::cfgetispeed(&*inner_termios) }
761+
.try_into()
762+
.unwrap_or(BaudRate::B0)
759763
}
760764

761765
/// Get output baud rate (see
762766
/// [cfgetospeed(3p)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/cfgetospeed.html)).
763767
///
764768
/// `cfgetospeed()` extracts the output baud rate from the given `Termios` structure.
769+
///
770+
/// On glibc 2.42+, returns `BaudRate::B0` if the actual baud rate cannot be determined.
765771
pub fn cfgetospeed(termios: &Termios) -> BaudRate {
766772
let inner_termios = termios.get_libc_termios();
767-
unsafe { libc::cfgetospeed(&*inner_termios) }.try_into().unwrap()
773+
unsafe { libc::cfgetospeed(&*inner_termios) }
774+
.try_into()
775+
.unwrap_or(BaudRate::B0)
768776
}
769777

770778
/// Set input baud rate (see

test/sys/test_termios.rs

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,3 +115,74 @@ fn test_local_flags() {
115115
let read = read(&pty.master, &mut buf).unwrap_err();
116116
assert_eq!(read, Errno::EAGAIN);
117117
}
118+
119+
// Test for glibc 2.42 compatibility - cfgetospeed should never panic
120+
// Reproduces issue from nix-rust/nix#2672
121+
#[test]
122+
fn test_cfgetospeed_never_panics() {
123+
use nix::sys::termios::{cfgetospeed, Termios};
124+
125+
// Test with zeroed termios (may be invalid on glibc 2.42)
126+
let termios: Termios = unsafe { std::mem::zeroed() };
127+
128+
// This should not panic, even on glibc 2.42
129+
// Before fix: panicked at src/sys/termios.rs:767 with EINVAL
130+
let _speed = cfgetospeed(&termios);
131+
132+
// If we get here, no panic occurred - test passes
133+
}
134+
135+
// Test for glibc 2.42 compatibility - cfgetispeed should never panic
136+
#[test]
137+
fn test_cfgetispeed_never_panics() {
138+
use nix::sys::termios::{cfgetispeed, Termios};
139+
140+
// Test with zeroed termios (may be invalid on glibc 2.42)
141+
let termios: Termios = unsafe { std::mem::zeroed() };
142+
143+
// This should not panic, even on glibc 2.42
144+
let _speed = cfgetispeed(&termios);
145+
146+
// If we get here, no panic occurred - test passes
147+
}
148+
149+
// Test exact reproducer from issue #2672
150+
#[test]
151+
fn test_issue_2672_cfgetospeed_with_pty() {
152+
use nix::sys::termios::cfgetospeed;
153+
154+
// openpty uses ptname(3) internally
155+
let _m = crate::PTSNAME_MTX.lock();
156+
157+
let pty = openpty(None, None).expect("openpty failed");
158+
let termios = tcgetattr(&pty.slave).expect("tcgetattr failed");
159+
160+
// This exact call panicked on glibc 2.42 before the fix
161+
let speed = cfgetospeed(&termios);
162+
163+
// Should return some valid BaudRate (or B0 on error)
164+
// The key is: NO PANIC
165+
let _ = speed;
166+
}
167+
168+
// Test baud rate roundtrip with actual pty
169+
#[test]
170+
fn test_baudrate_roundtrip_with_pty() {
171+
use nix::sys::termios::{cfgetospeed, cfsetspeed};
172+
173+
// openpty uses ptname(3) internally
174+
let _m = crate::PTSNAME_MTX.lock();
175+
176+
let pty = openpty(None, None).expect("openpty failed");
177+
let mut termios = tcgetattr(&pty.slave).expect("tcgetattr failed");
178+
179+
// Set a known baud rate
180+
cfsetspeed(&mut termios, BaudRate::B9600).expect("cfsetspeed failed");
181+
182+
// Get it back - should not panic
183+
let speed = cfgetospeed(&termios);
184+
185+
// On most systems this equals B9600, but on glibc 2.42 might be B0 if conversion fails
186+
// Either way, NO PANIC is the requirement
187+
let _ = speed;
188+
}

0 commit comments

Comments
 (0)