mirror of
https://github.com/asciinema/asciinema.git
synced 2025-12-16 11:48:13 +01:00
fix: avoid closing pty master fd twice
The pty master fd is closed twice, once when dropping OwnedFd in `fn exec` and
once when dropping File constructed with unsafe code in `fn copy`.
This causes IO Safety violation[1] and should be avoided.
It becomes a crash in debug build[2].
[1]: 1ba00d9cb2
[2]: https://github.com/zed-industries/zed/issues/12114
This commit is contained in:
16
src/pty.rs
16
src/pty.rs
@@ -10,12 +10,13 @@ use nix::{libc, pty};
|
|||||||
use signal_hook::consts::{SIGALRM, SIGCHLD, SIGHUP, SIGINT, SIGQUIT, SIGTERM, SIGWINCH};
|
use signal_hook::consts::{SIGALRM, SIGCHLD, SIGHUP, SIGINT, SIGQUIT, SIGTERM, SIGWINCH};
|
||||||
use signal_hook::SigId;
|
use signal_hook::SigId;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
use std::env;
|
||||||
use std::ffi::{CString, NulError};
|
use std::ffi::{CString, NulError};
|
||||||
|
use std::fs::File;
|
||||||
use std::io::{self, ErrorKind, Read, Write};
|
use std::io::{self, ErrorKind, Read, Write};
|
||||||
use std::os::fd::{AsFd, RawFd};
|
use std::os::fd::AsFd;
|
||||||
use std::os::fd::{BorrowedFd, OwnedFd};
|
use std::os::fd::{BorrowedFd, OwnedFd};
|
||||||
use std::os::unix::io::{AsRawFd, FromRawFd};
|
use std::os::unix::io::{AsRawFd, FromRawFd};
|
||||||
use std::{env, fs};
|
|
||||||
|
|
||||||
type ExtraEnv = HashMap<String, String>;
|
type ExtraEnv = HashMap<String, String>;
|
||||||
|
|
||||||
@@ -37,9 +38,7 @@ pub fn exec<S: AsRef<str>, T: Tty + ?Sized, H: Handler>(
|
|||||||
let result = unsafe { pty::forkpty(Some(&winsize), None) }?;
|
let result = unsafe { pty::forkpty(Some(&winsize), None) }?;
|
||||||
|
|
||||||
match result.fork_result {
|
match result.fork_result {
|
||||||
ForkResult::Parent { child } => {
|
ForkResult::Parent { child } => handle_parent(result.master, child, tty, handler),
|
||||||
handle_parent(result.master.as_raw_fd(), child, tty, handler)
|
|
||||||
}
|
|
||||||
|
|
||||||
ForkResult::Child => {
|
ForkResult::Child => {
|
||||||
handle_child(command, extra_env)?;
|
handle_child(command, extra_env)?;
|
||||||
@@ -49,7 +48,7 @@ pub fn exec<S: AsRef<str>, T: Tty + ?Sized, H: Handler>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn handle_parent<T: Tty + ?Sized, H: Handler>(
|
fn handle_parent<T: Tty + ?Sized, H: Handler>(
|
||||||
master_fd: RawFd,
|
master_fd: OwnedFd,
|
||||||
child: unistd::Pid,
|
child: unistd::Pid,
|
||||||
tty: &mut T,
|
tty: &mut T,
|
||||||
handler: &mut H,
|
handler: &mut H,
|
||||||
@@ -75,12 +74,13 @@ fn handle_parent<T: Tty + ?Sized, H: Handler>(
|
|||||||
const BUF_SIZE: usize = 128 * 1024;
|
const BUF_SIZE: usize = 128 * 1024;
|
||||||
|
|
||||||
fn copy<T: Tty + ?Sized, H: Handler>(
|
fn copy<T: Tty + ?Sized, H: Handler>(
|
||||||
master_raw_fd: RawFd,
|
master_fd: OwnedFd,
|
||||||
child: unistd::Pid,
|
child: unistd::Pid,
|
||||||
tty: &mut T,
|
tty: &mut T,
|
||||||
handler: &mut H,
|
handler: &mut H,
|
||||||
) -> Result<Option<WaitStatus>> {
|
) -> Result<Option<WaitStatus>> {
|
||||||
let mut master = unsafe { fs::File::from_raw_fd(master_raw_fd) };
|
let mut master = File::from(master_fd);
|
||||||
|
let master_raw_fd = master.as_raw_fd();
|
||||||
let mut buf = [0u8; BUF_SIZE];
|
let mut buf = [0u8; BUF_SIZE];
|
||||||
let mut input: Vec<u8> = Vec::with_capacity(BUF_SIZE);
|
let mut input: Vec<u8> = Vec::with_capacity(BUF_SIZE);
|
||||||
let mut output: Vec<u8> = Vec::with_capacity(BUF_SIZE);
|
let mut output: Vec<u8> = Vec::with_capacity(BUF_SIZE);
|
||||||
|
|||||||
Reference in New Issue
Block a user