Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

tac, tail, dd: detect closed stdin before Rust sanitizes it to /dev/null#9664

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to ourterms of service andprivacy statement. We’ll occasionally send you account related emails.

Already on GitHub?Sign in to your account

Open
ChrisDryden wants to merge1 commit intouutils:main
base:main
Choose a base branch
Loading
fromChrisDryden:fix-stdin-closed-detection

Conversation

@ChrisDryden
Copy link
Contributor

@ChrisDrydenChrisDryden commentedDec 15, 2025
edited
Loading

Using the same approach that was identified for the pipeline signals, we can retrieve the state of stdin and stdout before the rust runtime overrides the fd to /dev/null

This means that we will be able to both preserve the pre-existing behaviour for passing in /dev/null and also allow us to raise the same error message and code when the closed fd is passed to the stdin or stdout as the GNU implementation.

@ChrisDrydenChrisDryden changed the titlefix: detect closed stdin before Rust sanitizes it to /dev/nullWIP fix: detect closed stdin before Rust sanitizes it to /dev/nullDec 15, 2025
@github-actions
Copy link

GNU testsuite comparison:

Skipping an intermittent issue tests/tail/overlay-headers (passes in this run but fails in the 'main' branch)Congrats! The gnu test tests/tac/tac-2-nonseekable is no longer failing!Congrats! The gnu test tests/tail/follow-stdin is no longer failing!

@ChrisDrydenChrisDrydenforce-pushed thefix-stdin-closed-detection branch from32ab405 toe0bafa3CompareDecember 15, 2025 17:04
@ChrisDrydenChrisDryden changed the titleWIP fix: detect closed stdin before Rust sanitizes it to /dev/nulltac, tail: detect closed stdin before Rust sanitizes it to /dev/nullDec 15, 2025
@ChrisDrydenChrisDryden marked this pull request as ready for reviewDecember 15, 2025 17:05
@ChrisDrydenChrisDrydenforce-pushed thefix-stdin-closed-detection branch frome0bafa3 tobfdfe19CompareDecember 15, 2025 17:10
@github-actions
Copy link

GNU testsuite comparison:

Skipping an intermittent issue tests/tail/overlay-headers (passes in this run but fails in the 'main' branch)Congrats! The gnu test tests/tac/tac-2-nonseekable is no longer failing!Congrats! The gnu test tests/tail/follow-stdin is no longer failing!

@anastygnome
Copy link
Contributor

anastygnome commentedDec 15, 2025
edited
Loading

I'm not sure we should do this, the shell shouldn't allow that in the first place, this is not compliant with posix.
@sylvestre should we import such technical debt in our tools?
Seerust-lang/rust#108139 (comment)

@ChrisDryden
Copy link
ContributorAuthor

For tracking this would be the same approach of getting the PIPE signal as here:#9657
also has discussions on:#5906 (comment)

Maybe my understanding of the discussion is not complete,@anastygnome are you saying that this UUTILS implementation is not Posix compliant and that the GNU Coreutils is compliant in regards to this? Or are you saying that both the GNU Coreutils implementation and this implementation are non-compliant and that we should diverge from the GNU Coreutils implementation

@ChrisDrydenChrisDrydenforce-pushed thefix-stdin-closed-detection branch frombfdfe19 tod61c41fCompareDecember 15, 2025 20:27
@ChrisDrydenChrisDryden changed the titletac, tail: detect closed stdin before Rust sanitizes it to /dev/nulltac, tail, dd: detect closed stdin before Rust sanitizes it to /dev/nullDec 15, 2025
@ChrisDrydenChrisDrydenforce-pushed thefix-stdin-closed-detection branch fromd61c41f todfabb4bCompareDecember 15, 2025 20:35
@codspeed-hq
Copy link

codspeed-hqbot commentedDec 15, 2025
edited
Loading

CodSpeed Performance Report

Merging#9664 willimprove performances by 2.17%

ComparingChrisDryden:fix-stdin-closed-detection (d61c41f) withmain (06d843f)

Summary

⚡ 1 improvement
✅ 94 untouched
⏩ 38 skipped1

Benchmarks breakdown

BenchmarkBASEHEADChange
du_summarize_balanced_tree[(5, 4, 10)]8.5 ms8.3 ms+2.17%

Footnotes

  1. 38 benchmarks were skipped, so the baseline results were used instead. If they were deleted from the codebase,click here and archive them to remove them from the performance reports.

@github-actions
Copy link

GNU testsuite comparison:

Congrats! The gnu test tests/dd/stderr is no longer failing!Congrats! The gnu test tests/tac/tac-2-nonseekable is no longer failing!Congrats! The gnu test tests/tail/follow-stdin is no longer failing!

@sylvestre
Copy link
Contributor

GNU testsuite comparison:

Congrats! The gnu test tests/dd/stderr is no longer failing!Congrats! The gnu test tests/tac/tac-2-nonseekable is no longer failing!Congrats! The gnu test tests/tail/follow-stdin is no longer failing!

impressive!

@collinfunk
Copy link

I'm not sure we should do this, the shell shouldn't allow that in the first place, this is not compliant with posix.
@sylvestre should we import such technical debt in our tools?

Where does POSIX disallowsh from closing file descriptors?

This behavior has been supported the Bourne shell for ages. Even Solaris/bin/sh supports it:

$ gyes >&-gyes: standard output: Bad file numbergyes: write error: Bad file number

My personal opinion is that Rust really should have a way to disable the messing around it does with signal actions and file descriptors beforemain().

@ChrisDrydenChrisDrydenforce-pushed thefix-stdin-closed-detection branch fromdfabb4b to2c10c5fCompareDecember 15, 2025 21:02
@github-actions
Copy link

GNU testsuite comparison:

Skipping an intermittent issue tests/tail/overlay-headers (passes in this run but fails in the 'main' branch)Congrats! The gnu test tests/dd/stderr is no longer failing!Congrats! The gnu test tests/tac/tac-2-nonseekable is no longer failing!Congrats! The gnu test tests/tail/follow-stdin is no longer failing!

@anastygnome
Copy link
Contributor

anastygnome commentedDec 15, 2025
edited
Loading

For tracking this would be the same approach of getting the PIPE signal as here:#9657 also has discussions on:#5906 (comment)

Maybe my understanding of the discussion is not complete,@anastygnome are you saying that this UUTILS implementation is not Posix compliant and that the GNU Coreutils is compliant in regards to this? Or are you saying that both the GNU Coreutils implementation and this implementation are non-compliant and that we should diverge from the GNU Coreutils implementation

So, to recap the issue

Basically this point of the posix standard was ambiguous before 2017.
Which is why the shell supports it, and gnu coreutils had to work around it

Since 2017, the posix standard says that if any of the 3 standards file descriptiors are closed, we are not in a posix compliant environment.
Rust works around that by reopening said file descriptors on /dev/null.

So the question is :

Do we consider posix post 2017 as the new norm, or do we add this check as a continuing workaround ?

I'll quote the posix standard later but it has been there on older issues.

Comment on lines +440 to +458
#[cfg(unix)]
#[allow(clippy::missing_safety_doc)]
pubunsafeextern"C"fncapture_stdio_state(){
use nix::libc;
unsafe{
STDIN_WAS_CLOSED.store(
libc::fcntl(libc::STDIN_FILENO, libc::F_GETFD) == -1,
Ordering::Relaxed,
);
STDOUT_WAS_CLOSED.store(
libc::fcntl(libc::STDOUT_FILENO, libc::F_GETFD) == -1,
Ordering::Relaxed,
);
STDERR_WAS_CLOSED.store(
libc::fcntl(libc::STDERR_FILENO, libc::F_GETFD) == -1,
Ordering::Relaxed,
);
}
}
Copy link
Contributor

@anastygnomeanastygnomeDec 16, 2025
edited
Loading

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others.Learn more.

For efficiency we should do something similar to the fastpath shown inthis function. It is the function that reopens the FDs in the standard library.

how about this

Suggested change
#[cfg(unix)]
#[allow(clippy::missing_safety_doc)]
pubunsafeextern"C"fn capture_stdio_state(){
use nix::libc;
unsafe{
STDIN_WAS_CLOSED.store(
libc::fcntl(libc::STDIN_FILENO, libc::F_GETFD) == -1,
Ordering::Relaxed,
);
STDOUT_WAS_CLOSED.store(
libc::fcntl(libc::STDOUT_FILENO, libc::F_GETFD) == -1,
Ordering::Relaxed,
);
STDERR_WAS_CLOSED.store(
libc::fcntl(libc::STDERR_FILENO, libc::F_GETFD) == -1,
Ordering::Relaxed,
);
}
}
/// # Safety
///
/// Must be called very early in process startup, before the runtime may reopen
/// closed standard file descriptors. Uses low-level libc APIs.
/// This code is just checking the state of the three standard fds and has no side-effects.
#[cfg(unix)]
pubunsafeextern"C"fn capture_stdio_state(){
use nix::libc;
// Prefer poll() where it reliably reports POLLNVAL
#[cfg(not(any(
miri,
target_os ="emscripten",
target_os ="fuchsia",
target_os ="vxworks",
target_os ="macos",
target_os ="ios",
target_os ="watchos",
target_os ="redox",
target_os ="l4re",
target_os ="horizon",
)))]
{
unsafe{
letmut pfds =[
libc::pollfd{
fd: libc::STDIN_FILENO,
events:0,
revents:0,
},
libc::pollfd{
fd: libc::STDOUT_FILENO,
events:0,
revents:0,
},
libc::pollfd{
fd: libc::STDERR_FILENO,
events:0,
revents:0,
},
];
let ok =loop{
match libc::poll(pfds.as_mut_ptr(), pfds.len()as_,0){
-1 =>match*libc::__errno_location(){
libc::EINTR =>continue,
libc::EINVAL | libc::ENOMEM | libc::EAGAIN =>breakfalse,
_ => libc::abort(),
},
_ =>breaktrue,
}
};
if ok{
STDIN_WAS_CLOSED.store(pfds[0].revents& libc::POLLNVAL !=0,Ordering::Relaxed);
STDOUT_WAS_CLOSED.store(pfds[1].revents& libc::POLLNVAL !=0,Ordering::Relaxed);
STDERR_WAS_CLOSED.store(pfds[2].revents& libc::POLLNVAL !=0,Ordering::Relaxed);
return;
}
}
}
// Fallback: fcntl()
unsafe{
STDIN_WAS_CLOSED.store(
libc::fcntl(libc::STDIN_FILENO, libc::F_GETFD) == -1,
Ordering::Relaxed,
);
STDOUT_WAS_CLOSED.store(
libc::fcntl(libc::STDOUT_FILENO, libc::F_GETFD) == -1,
Ordering::Relaxed,
);
STDERR_WAS_CLOSED.store(
libc::fcntl(libc::STDERR_FILENO, libc::F_GETFD) == -1,
Ordering::Relaxed,
);
}
}

@anastygnome
Copy link
Contributor

Also should be done for cat ;)

@ChrisDryden
Copy link
ContributorAuthor

I'm open either way to the approach, was hoping to get a maintainers opinion on which approach they'd be interested in?

Sign up for freeto join this conversation on GitHub. Already have an account?Sign in to comment

Reviewers

1 more reviewer

@anastygnomeanastygnomeanastygnome requested changes

Reviewers whose approvals may not affect merge requirements

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

4 participants

@ChrisDryden@anastygnome@sylvestre@collinfunk

[8]ページ先頭

©2009-2025 Movatter.jp