rust-lang / rust-lang/rustup

Deal with windows file locking rustup.exe + any proxies when they are executed

Open
#2,441 21 comments 10 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

A-concurrency enhancement O-windows
Dominant language
Rust
Stars
7k
Forks
1.1k
Avg merge
22h 40m
Merged PRs (30d)
46

Description

Overview

During self update, rustup needs to replace rustup and the various proxies for cargo, rustc etc.

If it cannot do this, then respectively:

  • future invocations of rustup will be still be running the older version and it will attempt to self-update again
  • any improvements made to the proxy code paths will not be reflected in the live proxies on disk (and conversely any bugs will remain)

However, on Windows, when a binary is executed, it gets a read lock taken out on it. This prevents deleting (or replacing) the file until the process has exited. Renaming seems possible.

Today we have code to spawn a separate process from rustup to perform these replacements, but this will fail if any rust or rustup process is running concurrent with the self-update.

Specifically the following cases cause errors:

  • processes that are already running like rls running under an IDE
  • rust processes started immediately after 'rustup self update' exits

What do these errors look like?

There are two cases:

A) Failed updates of rustup.exe / proxies

error: could not copy file from 'C:\Users\<username>\.cargo\bin\rustup-init.exe' to 'C:\Users\<username>\.cargo\bin\rustup.exe'
info: caused by: Access is denied. (os error 5)

B) Failed removal of the updater binary

error: could not remove 'setup' file: 'C:\Users\<username>\.cargo\bin/rustup-init.exe'
error: caused by: Access is denied. (os error 5)

Design space

We need to cater for processes that are already running - they need to be shut down before the updates in step A can proceed.

We need to cater for processes that start up after parent process exits: short lived ones (e.g. rustc, rustup version) can be allowed to complete, but long running processes (e.g. rls) need to be shut down just like processes that were already running.

We can't prevent the OS starting the processes (not even by renaming, since even a rename may race with that), so its more a matter of tolerating processes that startup and having a way to tell them to exit rapidly. Whatever 'process should exit' mechanism will act to guard against case B.

Finally, we need to cater for file locks coming from other utilities like mcafee or various endpoint security products that may (hopefully temporarily) lock any of these files that we need to manipulate; but the same retry mechanisms should provide some resilience; but possibly having some interface to signal that a given process is holding a lock will be needed: that can be left for a separate ticket though, as it will, unlike this ticket, not be a systemic problem.

Final finally we need to deal with having two instances of the installer executing at once - but perhaps that can be a separate enhancement.

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with rustup's self-update path and the separate updater process on Windows. Reproduce the reported failures with running Rust processes, newly started processes, and locked files, then determine how updates can complete safely. Done means rustup.exe and its proxies are updated without access-denied failures in the described concurrent cases.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
tooling
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Stale
Clarity
Needs clarification
Newbie friendliness
25/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.