Skip to content

fix(link): #5892 — keep perry_ffi test shims out of production ext archives#5911

Merged
proggeramlug merged 1 commit into
mainfrom
fix/5892-test-shims-cfg-gate
Jul 3, 2026
Merged

fix(link): #5892 — keep perry_ffi test shims out of production ext archives#5911
proggeramlug merged 1 commit into
mainfrom
fix/5892-test-shims-cfg-gate

Conversation

@proggeramlug

@proggeramlug proggeramlug commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

Fixes #5892.

Root cause

perry-ext-http and perry-ext-http-server ship their test_async_shims modules in production archives — the mod declaration is missing the #[cfg(test)] gate that perry-ext-net already has. The shims define the same #[no_mangle] C symbols as perry-stdlib's real perry-ffi async bridge with catastrophically different semantics:

When the linker resolves these from an ext archive instead of libperry_stdlib.a (single-pass archive scan; the referencing member and the shim member sit in the same archive), the current-thread runtime is never driven: js_wait_for_event falls back to the 1 s condvar park and any in-process server+client program parks forever. The auto-opt compile path is immune because strip-dedup (#5000/#5685) localizes duplicate wrapper globals — which is why only the cargo-test/debug-driver path hangs.

Evidence (hang-lab, debug/5892-hang-lab branch)

  • Hung binary: single thread, timed futex cycling every ~1 s (condvar fallback), server LISTENing, zero client connections — spawned tasks never ran (runs 28664851669, 28665408372)
  • Binary-corruption and self-deadlock hypotheses eliminated (identical md5 on clean recompile; timed not infinite futex)
  • With this gate: single-run repro clean + 6/6 exact cargo-test iterations clean vs hang-on-iteration-1 in three consecutive ungated runs (run 28669296187)
  • A same-run A/B (ungated loop → gate → loop) is running now for final causality confirmation; will post results here

Impact

Unblocks: nightly full-workspace cargo-test (red since ~Jun 21 from this + the pre-#5831 write_end flake family), release-tag Tests gates, and restores real async dispatch semantics to any natively-compiled binary whose link picked the shims (spawn_async dropping tasks silently is not test-only behavior anyone wants in the field).

Summary by CodeRabbit

  • Chores
    • Updated test-only code to compile conditionally in two components.
    • No user-facing behavior, APIs, or runtime functionality changed.

…chives

perry-ext-http and perry-ext-http-server compiled their test_async_shims
modules (synchronous perry_ffi_* stand-ins for unit-test linking) into the
production staticlib archives: the mod declaration was missing the
#[cfg(test)] gate that perry-ext-net already has. The shims' own comment
says 'Test-only; never shipped.' — but they shipped.

Those shims define the same #[no_mangle] C symbols as perry-stdlib's real
perry-ffi async bridge, with catastrophically different semantics:
perry_ffi_spawn_blocking_with_reactor/spawn_blocking run the closure
inline (no runtime context, no pump/wait-driver registration) and
perry_ffi_spawn_async is a no-op that silently drops the task. Whenever
the linker resolves these from an ext archive instead of libperry_stdlib.a
(single-pass archive scanning: the reference and the shim live in the same
archive), the #5831 current-thread runtime is never driven: the wait-driver
never registers, js_wait_for_event falls back to the 1 s condvar park, and
any program with in-process server+client I/O parks forever. This is the
cargo-test hang in issue_4903_listen_callback_deferred (#5892) that has
blocked nightlies and release tags since #5831 merged; the auto-opt path
was immune because strip-dedup (#5000/#5685) localizes duplicate wrapper
globals.

Gate both modules with #[cfg(test)], matching perry-ext-net. Validation on
the hang-lab branch (debug/5892-hang-lab): ungated cargo-test loop hung on
iteration 1 in three consecutive runs; with the gate, single-run repro +
6/6 cargo-test iterations clean (run 28669296187).
@coderabbitai

coderabbitai Bot commented Jul 3, 2026

Copy link
Copy Markdown

Review Change Stack

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 7a952d65-79d6-455c-a056-b11f6f851821

📥 Commits

Reviewing files that changed from the base of the PR and between edd608a and 7a21506.

📒 Files selected for processing (2)
  • crates/perry-ext-http-server/src/lib.rs
  • crates/perry-ext-http/src/lib.rs

📝 Walkthrough

Walkthrough

This PR adds #[cfg(test)] attributes before test module declarations in two files: perry-ext-http-server/src/lib.rs and perry-ext-http/src/lib.rs, restricting compilation of test code to test builds only.

Changes

Test compilation gating

Layer / File(s) Summary
Add cfg(test) attributes
crates/perry-ext-http-server/src/lib.rs, crates/perry-ext-http/src/lib.rs
Inserted #[cfg(test)] attributes before test module declarations so test-only code compiles only under test configuration.

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

Related issues: None of the changes address the linked issue (#5892) regarding cargo-test hangs in issue_4903_listen_callback_deferred; these are unrelated single-line test-gating edits.

Suggested labels: trivial, chore

Suggested reviewers: None required given the trivial scope of this change.

🐰 A whisker-thin change, so small and neat,
Two lines of #[cfg(test)], a tidy feat,
No logic stirred, no bugs to chase,
Just gates for tests kept in their place.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description is detailed, but it does not follow the repository template sections for Summary, Changes, Related issue, Test plan, or Checklist. Rewrite the PR body to match the template, adding Summary, Changes, Related issue, Test plan, and Checklist sections.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly states the core fix: gating perry_ffi test shims out of production archives.
Linked Issues check ✅ Passed The change matches #5892 by adding #[cfg(test)] to the test shim modules in both HTTP crates, which is the requested fix.
Out of Scope Changes check ✅ Passed The diff is narrowly scoped to test-only module gating in two files and introduces no unrelated code changes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/5892-test-shims-cfg-gate

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

Comment @coderabbitai help to get the list of available commands.

@proggeramlug

Copy link
Copy Markdown
Contributor Author

Final lab results (runs 28669296187, 28671098729): with archives built by the lab's combined cargo build invocation, the ungated link happened to pick the real stdlib shims (bug-state loop 0/4 hangs) — the shadowing is sensitive to how the wrapper/ext archives are built (test.yml's per-package serial loop produced the hanging member order in rounds 2–4 and in every real nightly/preflight). The gate ends the sensitivity outright: after it, perry_ffi_spawn_blocking_with_reactor/spawn_async have exactly one definition in the workspace (ext-net's copy was already #[cfg(test)]-gated), so no link order can resurrect the shadow. Definitive validation = full test.yml on the merged tip, which is the next step.

@proggeramlug proggeramlug merged commit 9ba13ee into main Jul 3, 2026
16 checks passed
@proggeramlug proggeramlug deleted the fix/5892-test-shims-cfg-gate branch July 3, 2026 16:06
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.

Full cargo-test hangs in issue_4903_listen_callback_deferred on every SHA containing #5831 (180-min timeout; blocks nightly + release tag gates)

1 participant