mirror of
https://github.com/RGBCube/uutils-coreutils
synced 2025-07-28 11:37:44 +00:00
Close file descriptors of pipes after use (#2591)
* Close file descriptors of pipes after use * cat: Test file descriptor exhaustion * fixup! cat: Test file descriptor exhaustion
This commit is contained in:
parent
c77115ab51
commit
516c5311f7
3 changed files with 35 additions and 10 deletions
|
@ -2,8 +2,9 @@ use super::{CatResult, InputHandle};
|
||||||
|
|
||||||
use nix::fcntl::{splice, SpliceFFlags};
|
use nix::fcntl::{splice, SpliceFFlags};
|
||||||
use nix::unistd::{self, pipe};
|
use nix::unistd::{self, pipe};
|
||||||
|
use std::fs::File;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::os::unix::io::RawFd;
|
use std::os::unix::io::{FromRawFd, RawFd};
|
||||||
|
|
||||||
const BUF_SIZE: usize = 1024 * 16;
|
const BUF_SIZE: usize = 1024 * 16;
|
||||||
|
|
||||||
|
@ -19,13 +20,11 @@ pub(super) fn write_fast_using_splice<R: Read>(
|
||||||
handle: &mut InputHandle<R>,
|
handle: &mut InputHandle<R>,
|
||||||
write_fd: RawFd,
|
write_fd: RawFd,
|
||||||
) -> CatResult<bool> {
|
) -> CatResult<bool> {
|
||||||
let (pipe_rd, pipe_wr) = match pipe() {
|
let (pipe_rd, pipe_wr) = pipe()?;
|
||||||
Ok(r) => r,
|
|
||||||
Err(_) => {
|
// Ensure the pipe is closed when the function returns.
|
||||||
// It is very rare that creating a pipe fails, but it can happen.
|
// SAFETY: The file descriptors do not have other owners.
|
||||||
return Ok(true);
|
let _handles = unsafe { (File::from_raw_fd(pipe_rd), File::from_raw_fd(pipe_wr)) };
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
match splice(
|
match splice(
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
use super::{WcResult, WordCountable};
|
use super::{WcResult, WordCountable};
|
||||||
|
|
||||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||||
use std::fs::OpenOptions;
|
use std::fs::{File, OpenOptions};
|
||||||
use std::io::ErrorKind;
|
use std::io::ErrorKind;
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
|
@ -9,7 +9,7 @@ use libc::S_IFREG;
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
use nix::sys::stat::fstat;
|
use nix::sys::stat::fstat;
|
||||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||||
use std::os::unix::io::{AsRawFd, RawFd};
|
use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
|
||||||
|
|
||||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||||
use libc::S_IFIFO;
|
use libc::S_IFIFO;
|
||||||
|
@ -47,6 +47,10 @@ fn count_bytes_using_splice(fd: RawFd) -> nix::Result<usize> {
|
||||||
let null = null_file.as_raw_fd();
|
let null = null_file.as_raw_fd();
|
||||||
let (pipe_rd, pipe_wr) = pipe()?;
|
let (pipe_rd, pipe_wr) = pipe()?;
|
||||||
|
|
||||||
|
// Ensure the pipe is closed when the function returns.
|
||||||
|
// SAFETY: The file descriptors do not have other owners.
|
||||||
|
let _handles = unsafe { (File::from_raw_fd(pipe_rd), File::from_raw_fd(pipe_wr)) };
|
||||||
|
|
||||||
let mut byte_count = 0;
|
let mut byte_count = 0;
|
||||||
loop {
|
loop {
|
||||||
let res = splice(fd, None, pipe_wr, None, BUF_SIZE, SpliceFFlags::empty())?;
|
let res = splice(fd, None, pipe_wr, None, BUF_SIZE, SpliceFFlags::empty())?;
|
||||||
|
|
|
@ -1,8 +1,13 @@
|
||||||
|
// spell-checker:ignore NOFILE
|
||||||
|
|
||||||
use crate::common::util::*;
|
use crate::common::util::*;
|
||||||
use std::fs::OpenOptions;
|
use std::fs::OpenOptions;
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
|
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
use rlimit::Resource;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_output_simple() {
|
fn test_output_simple() {
|
||||||
new_ucmd!()
|
new_ucmd!()
|
||||||
|
@ -87,6 +92,23 @@ fn test_fifo_symlink() {
|
||||||
thread.join().unwrap();
|
thread.join().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
#[cfg(target_os = "linux")]
|
||||||
|
fn test_closes_file_descriptors() {
|
||||||
|
// Each file creates a pipe, which has two file descriptors.
|
||||||
|
// If they are not closed then five is certainly too many.
|
||||||
|
new_ucmd!()
|
||||||
|
.args(&[
|
||||||
|
"alpha.txt",
|
||||||
|
"alpha.txt",
|
||||||
|
"alpha.txt",
|
||||||
|
"alpha.txt",
|
||||||
|
"alpha.txt",
|
||||||
|
])
|
||||||
|
.with_limit(Resource::NOFILE, 9, 9)
|
||||||
|
.succeeds();
|
||||||
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
fn test_piped_to_regular_file() {
|
fn test_piped_to_regular_file() {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue