leanprover / leanprover/lean4

Race condition in `lean_save_module_data` with concurrent `lean` processes

Open
#5,084 3 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

bug P-low
Dominant language
Lean
Stars
9.2k
Forks
990
Avg merge
1d 17h
Merged PRs (30d)
175

Description

Prerequisites

Please put an X between the brackets as you perform the following steps:

Description

When there are multiple concurrent lean processes and both are running lean_save_module_data for the same file simultaneously, because the name of the tempfile is always the same, the rename operation here can fail if another process has already renamed the file, such that there is no longer a file at olean_tmp_fn.

Context

I initially ran into this issue when using the language server. I'm using it via Helix so when I modify a dependency of one of the open files, I restart the language server using the :lsp-restart command. This seems to lead to a situation where multiple lean processes are being invoked for the same file simultaneously (I don't know the details of why this happens), which often causes the error above to occur.

Steps to Reproduce
  1. Clone https://github.com/mtoohey31/lean-race-condition-repro
  2. Run lake build Repro to ensure it builds successfully with just a single instance.
  3. Run lake clean.
  4. Run lake build Repro & lake build Repro (the single & is intentional cause we need at least two concurrent instances to cause the issue). This may be somewhat scheduler/platform dependent since it's a concurrency issue (though it occurs quite consistently for me). If it doesn't reproduce on the first try on your machine, repeat step 3 before retrying 4 to ensure the files actually get rebuilt. (For some reason the issue doesn't reproduce if I fully delete .lake before running this step, so I'd recommend sticking to lake clean.)

Expected behavior: Both lake processes should succeed without error.

Actual behavior: One process succeeds, but the other fails with the following output:

✖ [2/5] Building Repro.World
trace: .> LEAN_PATH=././.lake/build/lib LD_LIBRARY_PATH= .../.elan/toolchains/nightly/bin/lean ././././Repro/World.lean -R ./././. -o ././.lake/build/lib/Repro/World.olean -i ././.lake/build/lib/Repro/World.ilean -c ././.lake/build/ir/Repro/World.c --json
info: stderr:
failed to write '././.lake/build/lib/Repro/World.olean': 2 No such file or directory
error: Lean exited with code 1
Some required builds logged failures:
- Repro.World
error: build failed
Versions

"4.12.0-nightly-2024-08-17"

$ cat /etc/lsb-release
DISTRIB_CODENAME=vicuna
DISTRIB_DESCRIPTION="NixOS 24.11 (Vicuna)"
DISTRIB_ID=nixos
DISTRIB_RELEASE="24.11"
LSB_VERSION="24.11 (Vicuna)"
$ uname -r
6.6.44
Additional Information

I think in order to fix this (and avoid other related issues) we should make the following two changes to how the tempfile is chosen/opened:

  1. We should add a random component to the filename.
  2. We should open it with some method that sets the O_EXCL flag to ensure no other process uses the same file. We can include retry logic to decrease failures in the unlikely case of the random components matching.

I'd be happy to implement this fix if maintainers agree that this is the right solution.

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 src/library/module.cpp, especially the tempfile creation and rename locations linked in the issue. Reproduce the race with the lean-race-condition-repro project using concurrent lake build Repro commands after lake clean. Done means both concurrent builds complete successfully without the missing-file error.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp
Domain
compilers
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Clearly specified
Newbie friendliness
45/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.