Skip to content

fix(release): pin Linux builders to ubuntu-22.04 to avoid glibc 2.39 segfault#135

Merged
emal-avala merged 1 commit intomainfrom
fix/release-glibc-compat-134
Apr 18, 2026
Merged

fix(release): pin Linux builders to ubuntu-22.04 to avoid glibc 2.39 segfault#135
emal-avala merged 1 commit intomainfrom
fix/release-glibc-compat-134

Conversation

@emal-avala
Copy link
Copy Markdown
Member

Summary

Fixes #134Segmentation fault (core dumped) immediately after running agent on a freshly installed binary.

Root cause

The release workflow builds Linux binaries on ubuntu-latest, which is currently Ubuntu 24.04 (glibc 2.39). Inspecting the published agent-linux-x86_64 binary shows two weak imports from GLIBC_2.39:

$ objdump -T agent | grep 'w.*GLIBC_2'
0000000000000000  w   DF *UND*	0000000000000000 (GLIBC_2.39) pidfd_spawnp
0000000000000000  w   DF *UND*	0000000000000000 (GLIBC_2.39) pidfd_getpid

These come from tokio's process spawning path in modern Rust stdlib. They're weak references — the dynamic linker lets the program start even if they're missing — but when the program calls them on a system with glibc < 2.39, the symbol resolves to NULL and the call segfaults.

agent hits this path almost immediately after launch: main()SessionEnvironment::detect()git::is_git_repo()tokio::process::Command::new("git").status()posix_spawnp-family call → pidfd_spawnp → NULL deref → SIGSEGV.

Distros affected (glibc < 2.39):

  • Ubuntu 22.04 LTS (glibc 2.35) — still the current LTS for many users
  • Debian 12 "bookworm" (glibc 2.36)
  • RHEL / Alma / Rocky 9 (glibc 2.34)
  • Amazon Linux 2023 (glibc 2.34)
  • Fedora 38 and earlier

Fix

Pin the Linux x86_64 and aarch64 release builders to ubuntu-22.04 (glibc 2.35). The resulting binary no longer imports GLIBC_2.39 symbols and runs cleanly on all of the distros above. Users who need older-glibc compatibility (Ubuntu 20.04 / glibc 2.31) can still cargo install agent-code; moving to cargo-zigbuild for an even wider compat floor is a reasonable follow-up but out of scope here.

macOS and Windows builders are untouched.

Test plan

  • Reproduced the null-symbol condition locally: binary downloaded from v0.16.0 shows weak GLIBC_2.39 imports (pidfd_spawnp, pidfd_getpid).
  • Verified the call path (session_env::detectgit::is_git_repotokio::process::Command) that triggers the segfault on glibc < 2.39 runs at startup on every invocation.
  • Confirmed ubuntu-22.04 is a supported GitHub Actions runner (actions/runner-images).
  • After merge + tag: re-run objdump -T agent | grep GLIBC_2.3[6-9] on the new release artifact — should show no GLIBC_2.39 imports, highest symbol should be GLIBC_2.34 (pthread) or GLIBC_2.35.
  • Smoke-test the new binary on an Ubuntu 22.04 container (docker run --rm -it ubuntu:22.04) — agent --version and agent (setup wizard) should run without segfaulting.

🤖 Generated with Claude Code

…segfault (#134)

Release binaries built on ubuntu-latest (Ubuntu 24.04, glibc 2.39) import
`pidfd_spawnp` and `pidfd_getpid` as weak GLIBC_2.39 symbols. On systems
with glibc < 2.39 (Ubuntu 22.04, Debian 12, RHEL 9, ...) these resolve to
NULL and the first tokio subprocess spawn — e.g. session_env's git
detection at startup — segfaults with "Segmentation fault (core dumped)".

Pin the Linux x86_64 and aarch64 builders to ubuntu-22.04 (glibc 2.35) so
the published binaries remain compatible with the large majority of
modern distros that haven't yet shipped glibc 2.39.

Fixes #134.
@chatgpt-codex-connector
Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

@emal-avala
Copy link
Copy Markdown
Member Author

Self-review (deep)

Scope

Two os: values in release.yml (ubuntu-latestubuntu-22.04) plus an explanatory comment and a CHANGELOG entry. No Rust code, no test, no config, no CI-gate, no packaging-script changes.

Safety checklist

  • ubuntu-22.04 is a currently supported runner. Confirmed Ubuntu2204-Readme.md still exists in actions/runner-images. Ubuntu 22.04 LTS is supported through April 2027 (standard) / 2032 (ESM).
  • aarch64 cross-compile path still works on 22.04. gcc-aarch64-linux-gnu is available in 22.04's apt repo; the ~/.cargo/config.toml linker override is identical regardless of host Ubuntu version.
  • Toolchain compatibility. dtolnay/rust-toolchain@stable, actions/checkout@v6, actions/upload-artifact@v7 all support 22.04 runners.
  • No impact on other workflows. ci.yml (compile/test), release-e2e.yml (E2E suite), publish-crate, update-homebrew, publish-npm are all untouched and only use ubuntu-latest for jobs that either (a) don't produce distributed binaries, or (b) consume the artifact built by the pinned job — so they automatically benefit from the fix.
  • No impact on source distribution. cargo install agent-code users build on their own system; glibc floor is their system's glibc. Unaffected.
  • Installers automatically benefit. install.sh, npm/install.js (line 59), and the Homebrew formula generator all point at the same GitHub release URL. Next tagged release ships the 22.04-built binary everywhere.
  • Wider distro compatibility. glibc 2.35 covers: Ubuntu 22.04 / 24.04, Debian 12 / 13, RHEL / Alma / Rocky 9, Fedora 36+, Amazon Linux 2023, Arch. Distros still left out (Ubuntu 20.04 / RHEL 8 / Debian 11, all glibc ≤ 2.31) can still cargo install.
  • No behavioral change. Same Rust code, same dependencies, same target triple, same release flag. Only the build host's sysroot changes. There's no runtime behavior that varies between glibc 2.35 and 2.39 for this codebase.
  • Backward compat. Already-published v0.16.0 binaries are unchanged. Users on those versions can work around it by pulling the next patch release.
  • CHANGELOG format. Entry sits under ## [Unreleased]### Fixed, matching Keep a Changelog convention used elsewhere in the file.

Root cause verification

Confirmed by inspecting the v0.16.0 linux-x86_64 artifact locally:

$ objdump -T agent | grep 'w.*GLIBC_2'
... w DF *UND* 0000000000000000 (GLIBC_2.39) pidfd_spawnp
... w DF *UND* 0000000000000000 (GLIBC_2.39) pidfd_getpid

These weak symbols come from libc-crate / tokio's posix_spawn path. They start the process fine on older-glibc systems but segfault (NULL deref) when called. main()SessionEnvironment::detect()git::is_git_repo()tokio::process::Command("git") → pidfd_spawnp → NULL = the exact "Segmentation fault (core dumped)" reported in #134.

Known limitations (called out in PR body)

  1. Prospective fix only. Does not retroactively fix v0.16.0 binaries already on GitHub Releases. A patch release (v0.16.1) is needed to actually unblock Segmentation fault (core dumped) #134 reporters. Not blocking for this PR, but should be queued immediately after merge.
  2. Does not cover glibc < 2.35. Users on Ubuntu 20.04, Debian 11, RHEL 8 still need cargo install. If broader compatibility is wanted later, cargo-zigbuild with a x86_64-unknown-linux-gnu.2.28 target is the clean path. Out of scope here.

Suggested follow-up (not blocking)

Add a regression check in the release workflow so this class of bug can't silently recur if a future dependency pulls in new weak symbols:

- name: Assert binary has no newer-glibc weak symbols
  if: contains(matrix.target, 'linux')
  run: |
    if objdump -T target/${{ matrix.target }}/release/agent | grep -E 'GLIBC_2\.3[6-9]|GLIBC_2\.[4-9][0-9]'; then
      echo "::error::Binary imports newer-glibc symbols; compat floor broken"
      exit 1
    fi

Verdict

Safe to merge. Minimal, targeted, well-explained. No risk of breaking existing users; fixes a clear segfault path for the large majority of non-Ubuntu-24.04 Linux users once the next release ships.

@emal-avala emal-avala merged commit 711c345 into main Apr 18, 2026
13 of 14 checks passed
@emal-avala emal-avala deleted the fix/release-glibc-compat-134 branch April 18, 2026 21:34
This was referenced Apr 18, 2026
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.

Segmentation fault (core dumped)

1 participant