Skip to content

test(go): hard-link the test binary instead of copying it before exec - #225

Merged
calvin-archastro merged 1 commit into
mainfrom
fix/go-unlink-test-hard-link
Oct 30, 2026
Merged

calvin-archastro merged 1 commit into
mainfrom
fix/go-unlink-test-hard-link

Conversation

@calvin-archastro

@calvin-archastro calvin-archastro commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor

Review on ArchCode

Problem and author intent

plugins::go::tests::deferred_tests_decline_unlinked_current_executable (Linux only) failed on #224 at go.rs:820 with Os { code: 26, kind: ExecutableFileBusy, message: "Text file busy" }.

The race:

  1. The test fs::copys its own binary, then execs the copy.
  2. cargo test runs tests on many threads, and several of them spawn processes.
  3. If one of those threads forks while the copy's write descriptor is still open, the child inherits it.
  4. Linux refuses to exec a file that some process holds open for writing: ETXTBSY.

What changed

  • fs::copy → fs::hard_link. A hard link is never opened for writing.
  • The link lives in a temp dir beside the test binary, because hard links can't cross filesystems.
  • The test still unlinks only its own link, never Cargo's binary.
  • No retries or sleeps.

Scope / Risk / User impact

Test-only. Low risk. No user impact.

Testing

  • Not reproduced: cargo test --lib -- plugins:: ran 150 times each before and after in a rust:1.88 container, with 0 failures in both. The ETXTBSY window is narrow. This fix follows from the CI error and the known fork-during-copy behaviour, not from a local repro.
  • On Linux: the test runs on ubuntu-latest in this PR's CI (Test (ubuntu-latest)).
  • Checks: fmt and clippy are clean.

Follow-ups

If ETXTBSY ever appears again in this test, the cause is something else.

🤖 Generated with Claude Code

@calvin-archastro
calvin-archastro requested a review from a team October 30, 2026 00:27
deferred_tests_decline_unlinked_current_executable copied its own binary
and exec'd the copy. A test thread that forks while the copy's write
descriptor is open hands that descriptor to its child, and exec of a
file open for writing fails with ETXTBSY ("Text file busy"), as CI saw
on #224. A hard link is never opened for writing; it lives beside the
binary because hard links cannot cross filesystems.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@calvin-archastro
calvin-archastro force-pushed the fix/go-unlink-test-hard-link branch from c46c59d to e06718a Compare October 30, 2026 00:28
@calvin-archastro
calvin-archastro merged commit bf4a14b into main Oct 30, 2026
13 checks passed
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.

1 participant