Skip to content

Update Windows exe search order (phase 2) #358

Closed
@ChrisDenton

Description

@ChrisDenton

Proposal

Problem statement

On Windows, the Command program search uses slightly different rules depending on if the environment is inherited or not. To cut a long store short, this is for historical reasons. Way back in pre-1.0 times the intent was to follow our Unix code in searching the child's PATH. However, after several refactorings this became super buggy and only really worked if Command::env was used. In other cases it (unintentionally) fell back to the standard CreateProcess rules.

Awhile back it was decided to remove the current directory from the Windows Command search path. Which I did. At the time I was a bit worried it would affect people. But as it turned out that didn't appear to have that much of an impact. Or at least I've not heard of anyone having serious issues with it.

I did however preserve some of the buggy env behaviour because, I was worried about making too many changes at once.. However, I do think it needs fixing somehow

Motivating examples or use cases

Assuming that there is an app called hello.exe alongside the current application and also a different hello.exe in PATH:

// Spawns `hello.exe` in the applications' directory
Command::new("hello").spawn()
// Spawns `hello.exe` from PATH
Command::new("hello").env("a", "b").spawn()

Background

Windows CreateProcess search order

When using CreateProcess and not setting lpApplicationName, it will attempt to discover the application in the following places (and in this order):

  1. the parent process' directory
  2. the current directory for the parent process.
  3. the system directories
  4. the parent process' PATH

This is the order (or similar) used by most Windows applications and runtimes.

Rust's Unix search order

  1. the child process' PATH

Note: Rather than using execvpe, Rust sets the environment after forking and then uses execvp. See https://github.com/rust-lang/rust/blob/ed49386d3aa3a445a9889707fd405df01723eced/library/std/src/sys/pal/unix/process/process_unix.rs#L395

Rust's Windows search order

  1. the child process' PATH but only if the child environment is not inherited.
  2. the parent process' directory
  3. the system directories
  4. the parent process' PATH

Obviously this leads to some inconsistencies depending on whether Command::env is used or not.
It was originally intended we just do 1.; so this search order was somewhat accidental.

Solution sketch

There is a tension here between being consistent cross-platform and being consistent with non-Rust applications on Windows. We'd also prefer not break existing applications.

Trying to keep everyone happy is difficult, if not impossible but I think we can do better than we currently are. With that in mind, I would like the search order to be consistently:

  1. the parent process' directory
  2. the system directories
  3. the child process' PATH but only if the child environment is not inherited.
  4. the parent process' PATH

This is more or less the same as now except that the parent process' directory and system directories are consistently searched first.

I'd love to only check either the parent's or child's PATH, not both, but I worry that would be too breaking.

Alternatives

  • Keep the status quo
  • Be more consistent with other Windows applications and don't search the child PATH at all.
  • Be more consistent with other Rust platforms and don't search the parent PATH.
  • Be consistent with neither and only search the parent's PATH (i.e. not the application or system directories).
  • Have a new API for resolving applications, that allows at least some degree of control on how the search is performed. Though that would still need the default behaviour figured out.

Links and related work

What happens now?

This issue contains an API change proposal (or ACP) and is part of the libs-api team feature lifecycle. Once this issue is filed, the libs-api team will review open proposals as capability becomes available. Current response times do not have a clear estimate, but may be up to several months.

Possible responses

The libs team may respond in various different ways. First, the team will consider the problem (this doesn't require any concrete solution or alternatives to have been proposed):

  • We think this problem seems worth solving, and the standard library might be the right place to solve it.
  • We think that this probably doesn't belong in the standard library.

Second, if there's a concrete solution:

  • We think this specific solution looks roughly right, approved, you or someone else should implement this. (Further review will still happen on the subsequent implementation PR.)
  • We're not sure this is the right solution, and the alternatives or other materials don't give us enough information to be sure about that. Here are some questions we have that aren't answered, or rough ideas about alternatives we'd want to see discussed.

Metadata

Metadata

Assignees

No one assigned

    Labels

    I-libs-api-nominatedIndicates that an issue has been nominated for discussion during a team meeting.T-libs-apiapi-change-proposalA proposal to add or alter unstable APIs in the standard libraries

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions