Skip to content

blockifier_test_utils: fix ETXTBSY race in cairo package download#13839

Open
avi-starkware wants to merge 1 commit intomain-v0.14.2from
avi/fix-compiler-download-race
Open

blockifier_test_utils: fix ETXTBSY race in cairo package download#13839
avi-starkware wants to merge 1 commit intomain-v0.14.2from
avi/fix-compiler-download-race

Conversation

@avi-starkware
Copy link
Copy Markdown
Collaborator

verify_cairo1_package double-checks cairo1_package_exists — once
without the lock (fast path) and once after acquiring it. The predicate
only tested .exists() on the two binaries, so a concurrent process
could observe the package as "ready" while tar was still mid-write:

  1. Process A holds the download lock, tar is extracting the archive.
  2. tar extracts sequentially: first binary is closed, second binary
    is created (so .exists() is true) and being written to.
  3. Process B calls cairo1_package_exists, sees both files, skips the
    lock.
  4. Process B forks + execs the second binary → Linux returns
    ETXTBSY because the file is still open for writing by tar.

Fix with the same commit-marker pattern used in compile_cache.rs:
write .download_complete after tar finishes, and require it in
cairo1_package_exists. Until the marker exists, concurrent callers
fall through to the lock and wait for the writer.

Co-Authored-By: Claude Opus 4.7 (1M context) noreply@anthropic.com

`verify_cairo1_package` double-checks `cairo1_package_exists` — once
without the lock (fast path) and once after acquiring it. The predicate
only tested `.exists()` on the two binaries, so a concurrent process
could observe the package as "ready" while `tar` was still mid-write:

1. Process A holds the download lock, `tar` is extracting the archive.
2. `tar` extracts sequentially: first binary is closed, second binary
   is created (so `.exists()` is true) and being written to.
3. Process B calls `cairo1_package_exists`, sees both files, skips the
   lock.
4. Process B forks + execs the second binary → Linux returns
   `ETXTBSY` because the file is still open for writing by `tar`.

Fix with the same commit-marker pattern used in `compile_cache.rs`:
write `.download_complete` after `tar` finishes, and require it in
`cairo1_package_exists`. Until the marker exists, concurrent callers
fall through to the lock and wait for the writer.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
@reviewable-StarkWare
Copy link
Copy Markdown

This change is Reviewable

Copy link
Copy Markdown
Collaborator Author

This stack of pull requests is managed by Graphite. Learn more about stacking.

@avi-starkware avi-starkware marked this pull request as ready for review April 20, 2026 18:16
@cursor
Copy link
Copy Markdown

cursor Bot commented Apr 20, 2026

PR Summary

Low Risk
Low risk: small change in test utility download logic that adds an extraction completion marker to avoid concurrent processes executing half-written binaries.

Overview
Prevents a race where concurrent verify_cairo1_package callers could observe the Cairo1 compiler binaries as present while tar was still writing them, leading to ETXTBSY on exec.

This writes a .download_complete marker at the end of download_cairo_package and updates cairo1_package_exists to require that marker in addition to the two compiler binaries.

Reviewed by Cursor Bugbot for commit 6b91163. Bugbot is set up for automated code reviews on this repo. Configure here.

Copy link
Copy Markdown
Collaborator

@dorimedini-starkware dorimedini-starkware left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

:lgtm:

@dorimedini-starkware reviewed 1 file and all commit messages, and made 1 comment.
Reviewable status: :shipit: complete! all files reviewed, all discussions resolved (waiting on avi-starkware).

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.

3 participants