GV

GeezerVison

The World Wide Web, restored to 800 pixels of glory.

Home|About|Gaming cabinet|Archives|How it works|Starter sites

On this site

  • Sign in
  • ActionsCI/CD and automation
  • CodespacesCloud development environments
  • All Features
  • Documentation
  • Training
  • Certifications
  • Build with Copilot
  • Customize Copilot
  • Integrations
  • Trending repos
  • GitHub Sponsors
  • Developer articles
  • Enterprises

This view

  • Original page
  • New address

GeezerVison is showing github.com — fix(update): retry sanity-exec on ETXTBSY — deflake coverage and harden self-update against the fork/exec fd race by mikolalysenko · Pull Request #140 · SocketDev/socket-patch

Conversation

@mikolalysenko

@mikolalysenko Mikola Lysenko (mikolalysenko) commented Jul 30, 2026 •
edited by cursor Bot
Loading

Uh oh!

There was an error while loading. Please reload this page.

Copy link
Copy Markdown
Collaborator

Summary

Fixes the coverage-job flake first seen on PR #139 (failing run): update::download::tests::sanity_exec_rejects_wrong_program_and_honors_strictness died with

VerifyFailed("downloaded binary failed to execute (wrong architecture?): Text file busy (os error 26)")

Root cause — the classic Unix fork/exec fd-inheritance race, not a broken test assertion: between a sibling thread's fork() and its exec(), the child briefly inherits every open fd, including the write fd on a script/binary written moments earlier. Exec'ing that file during the window fails with ETXTBSY. The parallel test binary forks constantly, and llvm-cov instrumentation widens the window — which is why it bit coverage while the identical test passed in test/test-release of the same run. The race is equally real for production self-update in any multi-threaded process.

Changes (two commits, RED then GREEN)

  1. test(update) — RED: adds sanity_exec_retries_when_binary_briefly_text_busy (linux-gated; other platforms don't reliably enforce ETXTBSY), which reproduces the race deterministically by holding a write fd on the staged script for 150 ms from another thread while sanity_exec runs. Also tightens the existing strictness test to assert each rejection's reason instead of bare is_err() — an ETXTBSY spawn failure previously masqueraded as the expected rejection on the assertion one line above where the flake surfaced. This commit is pushed alone so CI demonstrates the failure in the exact environment that flaked; see the first (red) run on this branch.
  2. fix(update) — GREEN: sanity_exec retries the spawn on ErrorKind::ExecutableFileBusy (up to 10 attempts, 25 ms linear backoff, ≤ ~1.4 s worst case) instead of failing a fully SHA-verified download. Same dance Go's os/exec and cargo do. All other spawn errors still fail immediately with the existing message; the 10 s hang timeout still applies per attempt.

Verification

  • macOS: full update::download suite passes with the fix (regression test correctly linux-skipped).
  • Linux (CI): the branch's first push (test-only) is expected RED on the new test in test/test-release/coverage; the fix commit turns it GREEN — commit history preserves the evidence.

🤖 Generated with Claude Code


Note

Low Risk
Changes are confined to unit tests; no production logic appears in this diff.

Overview
Test-only changes in download.rs around post-download sanity_exec (--version self-check).

The existing strictness test now checks specific error text for each failure case (wrong program name, non-zero exit, version mismatch, exec failure) instead of only is_err(), so unrelated spawn errors—especially ETXTBSY from the fork/exec fd race—cannot satisfy the wrong assertion.

A new Linux-only test holds a write handle on a staged script for 150ms on another thread while sanity_exec runs, reproducing “text file busy” and expecting a successful pass once the handle is released (regression for the coverage-job flake described in the PR).

Reviewed by Cursor Bugbot for commit 3fca03a. Configure here.

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

All reactions
Mikola Lysenko (mikolalysenko) and others added 2 commits July 30, 2026 11:34
@mikolalysenko @claude
test(update): regression test for the ETXTBSY sanity-exec race (RED)
3fca03a
Reproduces the coverage-job flake deterministically: a write fd held open
on the staged binary while sanity_exec runs — the shape a sibling
thread's fork() leaves behind via fd inheritance — makes the exec fail
with "Text file busy" (Linux enforces ETXTBSY; the test is linux-gated).

Also tightens the existing strictness test to assert each rejection's
REASON instead of bare is_err(), which previously let an ETXTBSY spawn
failure masquerade as the expected rejection one line before the flake
surfaced.

This commit is intentionally pushed without the fix so CI demonstrates
the failure; the follow-up commit makes it pass.

Co-Authored-By: Claude Fable 5 <[email protected]>
@mikolalysenko @claude
fix(update): retry sanity-exec on ETXTBSY (fork/exec fd-inheritance r…
fe03f2c
…ace)

Between a sibling thread's fork() and its exec(), the child briefly
inherits every open fd — including a write fd on the binary staged
moments ago — and exec'ing the file during that window fails with
"Text file busy". Retry the spawn on ErrorKind::ExecutableFileBusy
(10 attempts, 25 ms linear backoff, <=1.4 s worst case) instead of
failing a fully SHA-verified download; all other spawn errors still
fail immediately and the 10 s hang timeout applies per attempt. Same
dance Go's os/exec and cargo do.

Turns the previous commit's RED regression test green and deflakes the
coverage job (first bitten on PR #139: llvm-cov widens the race window,
which is why `test`/`test-release` never caught it).

Co-Authored-By: Claude Fable 5 <[email protected]>
@mikolalysenko

Mikola Lysenko (mikolalysenko) commented Jul 30, 2026

Copy link
Copy Markdown
Collaborator Author

RED confirmed on real CI (commit 3fca03a, test-only): test (ubuntu-latest) failed on exactly the new regression test:

thread 'update::download::tests::sanity_exec_retries_when_binary_briefly_text_busy' panicked:
called `Result::unwrap()` on an `Err` value: VerifyFailed("downloaded binary failed to execute (wrong architecture?): Text file busy (os error 26)")

The fix commit (fe03f2c) is now pushed; CI should go green.

Separate observation from the RED run — test (windows-latest) failed on update_upgrade_branch_swaps (self_update_e2e.rs:133), not related to this diff (everything here is unix/linux-gated test code + a unix-race retry):

Error: could not install the update: self-replace failed: The process cannot access the file because it is being used by another process. (os error 32)

That's the Windows sibling of the same disease — a transient handle (typically Defender's real-time scan) on the freshly written binary during the swap rename-dance → ERROR_SHARING_VIOLATION. The analogous hardening (retry sharing violations around the swap with backoff) is deliberately not in this PR to keep it single-purpose; flagging it as a candidate follow-up.

All reactions

Sorry, something went wrong.

Uh oh!

There was an error while loading. Please reload this page.

Wenxin-Jiang
Wenxin Jiang (Wenxin-Jiang) approved these changes Jul 31, 2026
View reviewed changes
@mikolalysenko
Mikola Lysenko (mikolalysenko) merged commit e541be9 into main Jul 31, 2026
54 checks passed

Uh oh!

There was an error while loading. Please reload this page.

@mikolalysenko
Mikola Lysenko (mikolalysenko) deleted the fix/sanity-exec-etxtbsy branch July 31, 2026 16:19
@mikolalysenko Mikola Lysenko (mikolalysenko) mentioned this pull request Sep 27, 2026
Support vlt in hosted, vendored and agent modes #269
Merged
@mikolalysenko Mikola Lysenko (mikolalysenko) mentioned this pull request Oct 7, 2026
Decide: keep the --update binary swap, or replace it with the installer and keep only the update notifier #983
Closed
3 tasks
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Reviewers

@Wenxin-Jiang Wenxin Jiang (Wenxin-Jiang) Wenxin-Jiang approved these changes

Uh oh!

There was an error while loading. Please reload this page.

Assignees

No one assigned

Labels

None yet

Projects

None yet

Milestone

No milestone

Development

Successfully merging this pull request may close these issues.

Uh oh!

There was an error while loading. Please reload this page.

2 participants

@mikolalysenko @Wenxin-Jiang
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
You are visitor 01402503 — GeezerVison does not store the pages you look up.
Best viewed with Netscape Navigator 4.7 or Internet Explorer 6 at 800×600. No cookies required.