Skip to content

Commit 85ae008

Browse files
authored
Merge pull request #54 from Allen-Webb/crash
Do not panic when pty closes
2 parents de6760a + b5b515e commit 85ae008

File tree

2 files changed

+73
-2
lines changed

2 files changed

+73
-2
lines changed

src/lib.rs

+4-2
Original file line numberDiff line numberDiff line change
@@ -325,10 +325,11 @@ impl Log for StdErrLog {
325325
Level::Trace => Color::Blue,
326326
};
327327
{
328+
// A failure here indicates the stream closed. Do not panic.
328329
writer
329330
.get_mut()
330331
.set_color(ColorSpec::new().set_fg(Some(color)))
331-
.expect("failed to set color");
332+
.ok();
332333
}
333334

334335
if self.show_module_names {
@@ -359,7 +360,8 @@ impl Log for StdErrLog {
359360
}
360361
let _ = writeln!(writer, "{}", record.args());
361362
{
362-
writer.get_mut().reset().expect("failed to reset the color");
363+
// A failure here indicates the stream closed. Do not panic.
364+
writer.get_mut().reset().ok();
363365
}
364366
}
365367

tests/pty_closed.rs

+69
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,69 @@
1+
#[cfg(unix)]
2+
mod unix {
3+
use std::fs::File;
4+
use std::io::Error;
5+
use std::os::unix::io::{AsRawFd, FromRawFd};
6+
7+
use log::info;
8+
9+
fn check_ret(ret: libc::c_int, err_msg: &str) {
10+
if ret < 0 {
11+
panic!("{}: {}", err_msg, Error::last_os_error());
12+
}
13+
}
14+
15+
fn wrap_fd(fd: libc::c_int, err_msg: &str) -> File {
16+
check_ret(fd, err_msg);
17+
// Use File as a owned fd.
18+
unsafe { File::from_raw_fd(fd) }
19+
}
20+
21+
#[test]
22+
fn log_after_pty_close() {
23+
let pt = wrap_fd(unsafe { libc::getpt() }, "getpt");
24+
check_ret(unsafe { libc::grantpt(pt.as_raw_fd()) }, "grantpt");
25+
check_ret(unsafe { libc::unlockpt(pt.as_raw_fd()) }, "unlockpt");
26+
27+
let name = unsafe { libc::ptsname(pt.as_raw_fd()) };
28+
if name.is_null() {
29+
panic!("ptsname: {}", Error::last_os_error());
30+
}
31+
32+
let client = wrap_fd(unsafe { libc::open(name, libc::O_RDWR) }, "open client pty");
33+
34+
// Back up stderr
35+
let dup_stderr = wrap_fd(unsafe { libc::dup(2) }, "dup stderr");
36+
let dup_stderr_panic = wrap_fd(unsafe { libc::dup(2) }, "dup stderr");
37+
38+
// Set up the panic handler to restore stderr.
39+
let default_panic = std::panic::take_hook();
40+
std::panic::set_hook(Box::new(move |info| {
41+
check_ret(
42+
unsafe { libc::dup2(dup_stderr_panic.as_raw_fd(), 2) },
43+
"dup2 restore stderr",
44+
);
45+
default_panic(info);
46+
}));
47+
48+
// Replace stderr with pty
49+
check_ret(
50+
unsafe { libc::dup2(client.as_raw_fd(), 2) },
51+
"dup2 restore stderr",
52+
);
53+
54+
stderrlog::new().verbosity(50).init().unwrap();
55+
info!("This should work.");
56+
57+
println!("Closing PTY");
58+
drop(pt);
59+
60+
println!("Sending log after PTY closed");
61+
info!("This should trigger an EIO.");
62+
63+
// Restore stderr
64+
check_ret(
65+
unsafe { libc::dup2(dup_stderr.as_raw_fd(), 2) },
66+
"dup2 restore stderr",
67+
);
68+
}
69+
}

0 commit comments

Comments
 (0)