-
Notifications
You must be signed in to change notification settings - Fork 12.9k
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 our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[WIP] Add size-limited command interface #74549
Conversation
Thanks for the pull request, and welcome! The Rust team is excited to review your changes, and you should hear from @LukasKalbertodt (or someone else) soon. If any changes to this PR are deemed necessary, please add them as extra commits. This ensures that the reviewer can see what has changed since they last reviewed the code. Due to the way GitHub handles out-of-date commits, this should also make it reasonably obvious what issues have or haven't been addressed. Large or tricky changes may require several passes of review and changes. Please see the contribution instructions for more information. |
☔ The latest upstream changes (presumably #74667) made this pull request unmergeable. Please resolve the merge conflicts. |
Hi @Artoria2e5 and thanks for the PR so far. Would you like to have a review/feedback of the state so far? Or are you still actively working on it? In any case, just let me know! |
☔ The latest upstream changes (presumably #73265) made this pull request unmergeable. Please resolve the merge conflicts. |
A few rebases may happen given the recent change in file layout, so I think I am not ready yet. |
Sure. Just let me know if you need any help or if I should take a look at the changes. |
I still need to come up witth a place for the trait to go. Honestly I don't know where to put the file yet. This thing being quadratic is a problem too. I guess I will make a little struct with the current length and argc in it to keep track. (And yeah it only works as long as envp is unchanged.)
It looks like I really can't get away with the whole storing error thing as they don't have Copy. Maybe I will end up using the ugly problem enum thing like I did with Unix too. Grrr...
@LukasKalbertodt I think I can ask for a very early review now. Most of my questions are in the commit messages, but generic The main problem I have seems to be I really don't know where to put the trait. I am bad at this... |
pub fn get_size(&mut self) -> io::Result<usize> { | ||
use crate::mem; | ||
let argv = &self.argv.0; | ||
let argv_size: usize = argv.iter().map(|x| unsafe { strlen(*x) + 1 }).sum::<usize>() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh great I forgot that the last element is a nullptr!
But seriously I should this without strlen
... like accumulating a length in add
when it's still an OsStr
.
let program = rprogram.as_ref().unwrap_or(&self.program); | ||
|
||
// Prepare and terminate the application name and the cmdline | ||
// XXX: this won't work for 16-bit, might be preferable to do a extend_from_slice |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Better do an append to the cmdline in new()
. Oh I forgot it won't work because of the PATH resolving above. Gotta leave it for now...
it wants tight lines!
sys::os::set_errno(0); | ||
let limit = libc::sysconf(libc::_SC_ARG_MAX); | ||
let errno = sys::os::errno(); | ||
sys::os::set_errno(old_errno); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not necessary, right? I think it is expected that any function in libstd that interacts with the OS in some way can clobber errno
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hmm, I didn't know that!
@@ -75,11 +76,14 @@ pub struct Command { | |||
args: Vec<CString>, | |||
argv: Argv, | |||
env: CommandEnv, | |||
env_size: Option<usize>, | |||
arg_max: Option<isize>, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can arg_max
possibly be Some(0)
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It wouldn't make sense to be that. Are you suggesting a naked isize?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Either that or NonZero
types.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That looks cool. Let me get it changed.
self.arg_max = limit.try_into().ok(); | ||
} | ||
} | ||
Ok(self.arg_max.unwrap() < 0 || self.get_size()? < (self.arg_max.unwrap() as usize)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't arg_max
be usize
so it won't be less than zero?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, a negative value indicates that the arg size is unlimited. If my reading of POSIX is right, that is.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IIRC -0
of usize
is still -1
for unlimited.
let old_errno = sys::os::errno(); | ||
sys::os::set_errno(0); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why should we clear existing errno
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think the no-error case automatically clears errno. Does it?
r? @Amanieu |
☔ The latest upstream changes (presumably #77029) made this pull request unmergeable. Please resolve the merge conflicts. Note that reviewers usually do not review pull requests until merge conflicts are resolved! Once you resolve the conflicts, you should change the labels applied by bors to indicate that your PR is ready for review. Post this as a comment to change the labels:
|
I don't really understand why it's trying to compile a Windows thing for Unix… |
@Artoria2e5 any updates on this? |
☔ The latest upstream changes (presumably #77666) made this pull request unmergeable. Please resolve the merge conflicts. Note that reviewers usually do not review pull requests until merge conflicts are resolved! Once you resolve the conflicts, you should change the labels applied by bors to indicate that your PR is ready for review. Post this as a comment to change the labels:
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
error[E0432]: unresolved imports `crate::sys::process::Arg`, `crate::sys::process::Problem`, `crate::sys::process::RawArg`
--> library/std/src/sys/windows/ext/process.rs:11:31
|
11 | pub use crate::sys::process::{Arg, Problem, RawArg};
| ^^^ ^^^^^^^ ^^^^^^ no `RawArg` in `sys::unix::process`
| | |
| | no `Problem` in `sys::unix::process`
| no `Arg` in `sys::unix::process`
I don't really understand why it's trying to compile a Windows thing for Unix…
@Artoria2e5 the documentation for the standard library has a very cursed build system and shows all platforms even though the host is linux: #43348.
// FIXME: This really should be somewhere else, since it will be duplicated for unix. sys_common? I have no idea.
// The implementations should apply to unix, but describing it to the type system is another thing.
That sounds about right. The approach I would take is to have CommandSized
in sys_common
, but make the trait implementations specific to the OS.
/// Build many commands. | ||
fn xargs<I, S, A>(program: S, args: I, before: Vec<A>, after: Vec<A>) -> io::Result<Vec<Self>> | ||
where | ||
I: IntoIterator<Item = A>, | ||
S: AsRef<OsStr> + Copy, | ||
A: Arg; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What does this do that maybe_args
doesn't?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Like its namesake, xargs
is supposed to create a new command to fit in additional parameters when there's too many of them. As a result it returns possibly many commands.
It can still fail from a single oversized parameter being impossible to fit.
pub enum Problem { | ||
SawNul, | ||
Oversized, | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'd make the name of the error more descriptive.
pub enum Problem { | |
SawNul, | |
Oversized, | |
} | |
pub enum ArgumentError { | |
SawNul, | |
Oversized, | |
} |
fn append_to(&self, cmd: &mut Vec<u16>, force_quotes: bool) -> Result<usize, Problem>; | ||
#[unstable(feature = "command_sized", issue = "74549")] | ||
fn arg_size(&self, force_quotes: bool) -> Result<usize, Problem>; | ||
fn to_os_string(&self) -> OsString; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The other functions need annotations too, I think.
@@ -133,6 +190,13 @@ impl Command { | |||
pub fn creation_flags(&mut self, flags: u32) { | |||
self.flags = flags; | |||
} | |||
#[allow(dead_code)] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is this for?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There seem to be a lot of these, some pre-existing 🤷
I can't seem to get the nonzero stuff working: I got hit with E0423 where I want to construct it.
I think I can get away with that. The unix version can call the normal |
@Artoria2e5 yes, the Arg trait is going to be the same, but moved into one place so we can be sure it's not different between platforms. |
@Artoria2e5 thanks for taking the time to contribute. I have to close this due to inactivity. If you wish and you have the time you can open a new PR with these changes and we'll take it from there. Thanks |
As described in #40384, most systems put an upper limit to the size of commands. The
std::process::Command
interface should therefore be updated to handle this problem and detect when the OS finds the command-line too big.Progress on this stuff:
xargs
like interfacexargs(program: S, stuff: impl IntoIterator<Item=S>, before: Vec[S], after: Vec[S]) -> Vec[Command]