Skip to content

Conversation

@Ecordonnier
Copy link
Contributor

No need to use the unsafe libc::execvp(), the standard rust library provides the functionality via the safe function Command::exec().

@oech3

This comment was marked as resolved.

@cakebaker cakebaker changed the title nice: use Command::exec() instead of libc::execvp() env: use Command::exec() instead of libc::execvp() Dec 9, 2025
No need to use the unsafe `libc::execvp()`, the standard rust library provides
the functionality via the safe function `Command::exec()`.

Signed-off-by: Etienne Cordonnier <[email protected]>
@github-actions
Copy link

github-actions bot commented Dec 9, 2025

GNU testsuite comparison:

Skipping an intermittent issue tests/tail/overlay-headers (passes in this run but fails in the 'main' branch)

@cakebaker cakebaker merged commit 2feb6b9 into uutils:main Dec 9, 2025
127 checks passed
@cakebaker
Copy link
Contributor

Thanks!

@Ecordonnier Ecordonnier deleted the eco/env-command-exec branch December 9, 2025 16:43
@collinfunk
Copy link

Does Command::exec() do signal (SIGPIPE, SIGPIPE) like the rest of the standard library before executing a command? If so, it is probably better to use libc::execvp().

@collinfunk
Copy link

It does:

$ strace -e rt_sigaction,execve ./target/debug/env true
execve("./target/debug/env", ["./target/debug/env", "true"], 0x7ffd9354e808 /* 85 vars */) = 0
rt_sigaction(SIGPIPE, {sa_handler=SIG_IGN, sa_mask=[PIPE], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x7f73276bc2c0}, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
rt_sigaction(SIGSEGV, NULL, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
rt_sigaction(SIGSEGV, {sa_handler=0x558ebd8bc5d0, sa_mask=[], sa_flags=SA_RESTORER|SA_ONSTACK|SA_SIGINFO, sa_restorer=0x7f73276bc2c0}, NULL, 8) = 0
rt_sigaction(SIGBUS, NULL, {sa_handler=SIG_DFL, sa_mask=[], sa_flags=0}, 8) = 0
rt_sigaction(SIGBUS, {sa_handler=0x558ebd8bc5d0, sa_mask=[], sa_flags=SA_RESTORER|SA_ONSTACK|SA_SIGINFO, sa_restorer=0x7f73276bc2c0}, NULL, 8) = 0
rt_sigaction(SIGSEGV, {sa_handler=SIG_DFL, sa_mask=~[RTMIN RT_1], sa_flags=SA_RESTORER, sa_restorer=0x7f73276bc2c0}, {sa_handler=0x558ebd8bc5d0, sa_mask=[], sa_flags=SA_RESTORER|SA_ONSTACK|SA_SIGINFO, sa_restorer=0x7f73276bc2c0}, 8) = 0
rt_sigaction(SIGBUS, {sa_handler=SIG_DFL, sa_mask=~[RTMIN RT_1], sa_flags=SA_RESTORER, sa_restorer=0x7f73276bc2c0}, {sa_handler=0x558ebd8bc5d0, sa_mask=[], sa_flags=SA_RESTORER|SA_ONSTACK|SA_SIGINFO, sa_restorer=0x7f73276bc2c0}, 8) = 0
rt_sigaction(SIGPIPE, {sa_handler=SIG_DFL, sa_mask=[PIPE], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x7f73276bc2c0}, {sa_handler=SIG_IGN, sa_mask=[PIPE], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x7f73276bc2c0}, 8) = 0
rt_sigaction(SIGPIPE, {sa_handler=SIG_DFL, sa_mask=[PIPE], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x7f73276bc2c0}, {sa_handler=SIG_DFL, sa_mask=[PIPE], sa_flags=SA_RESTORER|SA_RESTART, sa_restorer=0x7f73276bc2c0}, 8) = 0
execve("/home/collin/.local/bin/true", ["true"], 0x7fffa0931f20 /* 85 vars */) = 0

This causes env --ignore-signal=PIPE to be ineffective. The yes command shouldn't receive a SIGPIPE:

$ ./target/debug/env --ignore-signal=PIPE yes | head -n 1
y
$ echo ${PIPESTATUS[0]} ${PIPESTATUS[1]}
141 0

Here is the correct behavior:

$ env --ignore-signal=PIPE yes | head -n 1
y
yes: standard output: Broken pipe
$ echo ${PIPESTATUS[0]} ${PIPESTATUS[1]}
1 0

@Ecordonnier
Copy link
Contributor Author

Ecordonnier commented Dec 9, 2025

OK, thanks for the feedback that Command::exec() calls signal (SIGPIPE, SIG_DFL). I'll check if there is a solution with Command::exec(). Even if we revert this PR, I'll add a test for this corner-case to make it clear why libc::execvp is used.

@collinfunk
Copy link

No problem. Rust reseting inherited signal handlers annoys me. I hope this project can give Rust some motivation to change some of that behavior. :)

@Ecordonnier
Copy link
Contributor Author

Ecordonnier commented Dec 9, 2025

@collinfunk rust is already in the process of fixing it, but it's not yet stabilized: rust-lang/rust#97889 (comment) / rust-lang/rust#62569

I'll revert this PR and add a test. I don't think there is a solution preserving ignore_signal using Command::exec() with a stable rust compiler version,

@Ecordonnier
Copy link
Contributor Author

Follow-up PR #9618

@ChrisDryden
Copy link
Contributor

We should make some integration tests for this behavior so that it gets locked in. I'll try and implement it tonight. Any chance you have some other examples on how this command stuff could manifest issues?

@Ecordonnier
Copy link
Contributor Author

Ecordonnier commented Dec 9, 2025

I've already added a test in my PR. what do you want to add? The tracking issue is #8919

@ChrisDryden
Copy link
Contributor

I was seeing there were a few PR in different utilities related to this, was thinking one that tests the behavior for all of the commands that expect this behavior

@collinfunk
Copy link

I'm planning to add something to the GNU test suite, but I don't expect a new release soon. So it won't be helpful immediately.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants