Skip to content

fix(test): stop executable fixtures racing ETXTBSY under parallel tests - #487

Merged
hyperpolymath merged 3 commits into
mainfrom
claude/new-session-th4e9w-etxtbsy-fixture
Nov 9, 2026
Merged

hyperpolymath merged 3 commits into
mainfrom
claude/new-session-th4e9w-etxtbsy-fixture

Conversation

@hyperpolymath

Copy link
Copy Markdown
Owner

Problem

rust-ci / Cargo test failed intermittently with:

provers::chuffed::tests::version_rejects_failed_empty_or_stderr_only_help
Failed to execute fzn-chuffed --help: Text file busy (os error 26)

It failed on #470, whose diff contains no Rust, and earlier in llvm-cov. The cause is a real race, not a flake. Four fixtures (chuffed, faial, gpuverify and version_probe) each write a shell script and execute it at once. If another test thread forks while the write descriptor is still open, the child keeps a copy of it until it reaches exec (Rust opens files close-on-exec). While any writer exists, the kernel refuses to execute the file with ETXTBSY.

Fix

New test-only helper, provers::test_fixture::write_executable (cfg(all(test, unix))). It:

  1. creates the script with mode 0700 and closes it;
  2. runs it with a sentinel argument until the kernel accepts the exec (up to 2 s, then it panics).

After one successful exec, no writer remains and no later fork can inherit one, so the test's own spawn cannot hit ETXTBSY. Every fixture script exits 64 on an unexpected argument, so the probe never runs a fixture body. The four fixtures now use the helper.

The PR also carries #465's rustfmt fix to proof_search.rs, byte-identical to it, so cargo fmt --check is green here as well.

Checks run locally

  • cargo test --lib -- provers::chuffed provers::faial provers::gpuverify provers::version_probe: 58 passed.
  • cargo clippy --lib --tests -- -D warnings: clean.
  • cargo fmt --check: clean.

Once this is open, I'll port it into the open PRs that hit the race (starting with #470).


Generated by Claude Code

`provers::chuffed::tests::version_rejects_failed_empty_or_stderr_only_help`
failed in CI with "Failed to execute fzn-chuffed --help: Text file busy
(os error 26)". The fixtures wrote a script and executed it at once. A fork
on another test thread, taken while the write descriptor was open, keeps
a copy until that child execs, and the kernel refuses to execute a file
with a writer.

New provers::test_fixture::write_executable creates the script with mode
0700, closes it, then runs it with a sentinel argument until the kernel
accepts the exec. After one successful exec no writer remains and no
later fork can inherit one. The chuffed, faial, gpuverify and
version_probe fixtures use it; each fixture exits 64 on an unexpected
argument, so the probe runs no fixture body.

Also carries the rustfmt fix to proof_search.rs from #465, identical to
it, so `cargo fmt --check` is green here.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019a95kk88TZ1iegsBK3kox3
@coderabbitai

coderabbitai Bot commented Nov 9, 2026 •

Copy link
Copy Markdown
Contributor

Explain Change →

No actionable comments were generated in the recent review.

Summary

Summary by CodeRabbit

  • Chores
    • Fixture scripts now have their executable permissions set explicitly. If permissions cannot be updated, the operation reports an error. The existing execution checks and retry behaviour are unchanged. This is an internal reliability update and does not change any user-facing features or behaviour.

The fixture writer now sets the script permissions to 0o700 after writing it. Permission-setting failures panic with make fixture executable. The existing execution probe and retry behaviour are unchanged.

Changes: Executable fixture permissions

Layer / File(s) Summary
Write and set fixture permissions
src/rust/provers/test_fixture.rs
The fixture writer imports PermissionsExt and sets the script permissions to 0o700 after writing it. It panics with make fixture executable if setting permissions fails.

Estimated code review effort: 1 (Trivial) | ~5 minutes

Change: Bug fix

Possibly related PRs

  • hyperpolymath/echidna#455: Adds version-probe tests for Faial and GpuVerify; this PR updates executable fixtures used for those backends.
Merge Risk: Minimal · up to 54c7e

Fixture scripts receive explicit owner-only executable permissions. No material merge risk is evident.

Pre-merge checks: Passed 5

Check name Status Explanation
Title check Passed The title clearly describes the change: preventing ETXTBSY failures in parallel tests that use executable fixtures.
Description check Passed The description explains the problem, fix, and test results. It does not include the template’s RSR Quality Checklist or Screenshots sections, but the main required information is present.
Docstring Coverage Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentat…
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Docstring Coverage

Explanation

Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%. Docstring coverage is scoped to functions touched by this diff with cyclomatic complexity of at least 2. Documentation-only edits and deletions within surviving functions are included; unchanged diff context and fully deleted functions are excluded. Analyzed 1 functions across 1 files.

Finishing Touches

Generate docstrings

  • Commit to this branch
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share

Recent review info

Run configuration

  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: ASSERTIVE
  • Plan: Advanced
  • Run ID: 2f5209be-bb42-42ba-b63f-3eb33024de4a
Commits

Reviewing files that changed from the base of the PR and between 2cb8ceb and 54c7e3f.

Files selected for processing: 1

  • src/rust/provers/test_fixture.rs

Included review availability: This review used your included allowance. Your plan provides up to 1 included review per hour; 0 remain after this review.

Recent review details

Context from checks skipped due to timeout: 42

  • GitHub Check: Rust Build — Real Chapel Library (allow-fail, L2.3+ gate)
  • GitHub Check: CodeRabbit
  • GitHub Check: scan / rust-secrets
  • GitHub Check: scan / shell-secrets
  • GitHub Check: Rust Build with Chapel Feature
  • GitHub Check: rust-ci / Cargo check + clippy + fmt
  • GitHub Check: rust-ci / llvm-cov line coverage
  • GitHub Check: governance / UUID v8 conformance
  • GitHub Check: governance / JS runtimes — bun
  • GitHub Check: governance / JS runtimes — environment provisions Bun first
  • GitHub Check: governance / JS runtimes — pnpm
  • GitHub Check: governance / Workflow security linter
  • GitHub Check: governance / Guix packaging policy (Nix retired)
  • GitHub Check: governance / Actions lockfile verify
  • GitHub Check: governance / Code quality + docs
  • GitHub Check: governance / Trusted-base reduction policy
  • GitHub Check: governance / Well-Known (RFC 9116 + RSR)
  • GitHub Check: governance / UUID v7 conformance
  • GitHub Check: governance / Debt ratchet
  • GitHub Check: governance / Live Actions policy (credentialed advisory)
  • GitHub Check: governance / Security policy checks
  • GitHub Check: governance / Licence consistency
  • GitHub Check: governance / JS runtimes — deno
  • GitHub Check: governance / Exemption ratchet
  • GitHub Check: governance / Language / package anti-pattern policy
  • GitHub Check: governance / Check Workflow Staleness
  • GitHub Check: governance / Allowlist Preflight
  • GitHub Check: Validate K9 contracts
  • GitHub Check: Groove manifest check
  • GitHub Check: Empty-linter (invisible characters)
  • GitHub Check: MVP Smoke
  • GitHub Check: Banned-runtime check
  • GitHub Check: Proof safety regressions
  • GitHub Check: T1 / chuffed
  • GitHub Check: T1 / glpk
  • GitHub Check: T1 / eprover
  • GitHub Check: T1 / cvc5
  • GitHub Check: T1 / z3
  • GitHub Check: T1 / vampire
  • GitHub Check: PR (address)
  • GitHub Check: panic-attack assail
  • GitHub Check: Build & verify container image
Additional context used

Code guidelines: 1

CLAUDE.md — auto-discovered
Path-based instructions: 1

Source excerpt: **Version + release history**: [`CHANGELOG.adoc`](CHANGELOG.adoc) (single source of truth; do not duplicate version strings elsewhere) Source excerpt: **License**: re-ruled 2026-10-01 (D262), superseding the 2026-08 AGPL spl...

CodeRabbit inference engine (CLAUDE.md)

Files:

  • src/rust/provers/test_fixture.rs
Additional comments: 2

src/rust/provers/test_fixture.rs: 2

18-18: LGTM!

36-39: LGTM!

@chatgpt-codex-connector

chatgpt-codex-connector Bot commented Nov 9, 2026 •

Copy link
Copy Markdown
Codex Review Summary: ❌ Failed

This comment shows the latest Codex review activity on this pull request.

Review Status Commit Review trigger
📝 Code Review ✅ Completed 2026-11-09T20:56:30.052106Z 54c7e3f New commits
🔒 Security Review ❌ Failed 2026-11-09T20:54:51.305649Z
We couldn’t complete this review. Comment @codex security review to try again.
54c7e3f New commits
ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review" or "@codex security review".

Codex reacts with 👀 while any review is running, comments if it has suggestions, and reacts with 👍 once all reviews finish with no findings.

@chatgpt-codex-connector

Copy link
Copy Markdown

This security review couldn’t start because the paying account has exhausted its Codex allowance and has insufficient available credits. The payer can check their balance and add credits in the Codex usage dashboard, then try again. If you do not manage the paying account, contact this repository's admins.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: 79de6d11f0

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment thread src/rust/provers/test_fixture.rs Resolved
Review on #487: OpenOptions::mode is filtered by the process umask, so a
restrictive umask could leave the fixture non-executable. Restore the
explicit set_permissions(0o700) after closing the writer and before the
readiness probe.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_019a95kk88TZ1iegsBK3kox3
Err(error) if error.kind() == ErrorKind::ExecutableFileBusy => {
std::thread::sleep(Duration::from_millis(10));
},
Err(error) => panic!("fixture executable cannot run: {error}"),
.create_new(true)
.mode(0o700)
.open(path)
.expect("create fixture executable");
Signed-off-by: Jonathan D.A. Jewell <6759885+hyperpolymath@users.noreply.github.com>
@chatgpt-codex-connector

Copy link
Copy Markdown

This security review couldn’t start because the paying account has exhausted its Codex allowance and has insufficient available credits. The payer can check their balance and add credits in the Codex usage dashboard, then try again. If you do not manage the paying account, contact this repository's admins.

@hyperpolymath
hyperpolymath enabled auto-merge (squash) November 9, 2026 20:54
@sonarqubecloud

sonarqubecloud Bot commented Nov 9, 2026

Copy link
Copy Markdown

@hyperpolymath
hyperpolymath merged commit d059264 into main Nov 9, 2026
77 of 80 checks passed
@hyperpolymath
hyperpolymath deleted the claude/new-session-th4e9w-etxtbsy-fixture branch November 9, 2026 21:02
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.

4 participants