anthropics / anthropics/claude-code

Native linux-x64 binary segfaults on Arch Linux (glibc 2.44) — free() called from libc newlocale() crashes with NULL table pointer

オープン
#89,399 コメント 1 件 リアクション 3 件 担当者 0 名 GitHub で見る
area:packaging duplicate has repro platform:linux platform:wsl
主要言語
Python
スター
145k
フォーク
23.1k
PR マージ指標
PR 指標を取得中

説明

## Description

The native (Bun-compiled) `claude` binary segfaults on Arch Linux (rolling release) due to an allocator‑interposition conflict with a newer glibc runtime. The crash is deterministic (same crash address every run) and reproducible with both the `install.sh` bootstrapper and the pre‑downloaded binary run directly.

Root cause: the binary statically exports its own `malloc`/`free` symbols, which (via normal ELF symbol resolution) end up intercepting `free()` calls made internally by the *system* `libc.so.6` (e.g. from `newlocale()` during process/locale bootstrap). On this glibc version the pointer being freed was allocated by the system libc's own allocator, not the binary's bundled one, so the bundled `free()` dereferences an uninitialized/mismatched heap-metadata table pointer (`RAX == 0`) and crashes.

I confirmed the exact same binary works fine under an older glibc, and that switching to the musl build avoids the bug entirely (see "Workaround" below).

## Environment

- **OS**: Arch Linux (rolling release), running under WSL2
- **Kernel**: `6.18.33.2-microsoft-standard-WSL2`
- **glibc**: `2.44+r24+g16be1518495f-1` (Arch's current rolling package)
- **Claude Code version**: `2.1.243`
- **Install method**: `curl -fsSL https://claude.ai/install.sh | bash`
- **Platform key resolved by installer**: `linux-x64`

## Steps to Reproduce

```bash
curl -fsSL https://claude.ai/install.sh | bash
```

or, running the downloaded binary directly:

```bash
DOWNLOAD_BASE_URL="https://downloads.claude.ai/claude-code-releases"
version=$(curl -fsSL "$DOWNLOAD_BASE_URL/latest")
curl -fsSL -o ./claude "$DOWNLOAD_BASE_URL/$version/linux-x64/claude"
chmod +x ./claude
./claude install
```

## Actual Behavior

The installer/binary segfaults immediately:

```
Setting up Claude Code...
bash: line 226: 1151 Segmentation fault "$binary_path" install ${TARGET:+"$TARGET"}
Installation was killed before it could finish (exit code 139).
```

`dmesg` shows a deterministic null-pointer dereference at the same code offset on every run:

```
claude-2.1.243-[...]: segfault at 0 ip 0000000001d10458 sp ... error 4 in claude-2.1.243-linux-x64[1b0f458,1953000+3b33000] likely on CPU ...
claude-2.1.243-linux-x64: claude-2.1.243-: potentially unexpected fatal signal 11.
```

A `gdb` backtrace on the raw downloaded binary shows the crash is inside the binary's own statically-linked `free()`, called from the *system* glibc's `newlocale()`:

```
Program received signal SIGSEGV, Segmentation fault.
0x0000000001d10458 in free ()
#0 0x0000000001d10458 in free ()
#1 0x00007ffff7c3530a in newlocale () from /usr/lib/libc.so.6
#2 0x0000000001abd282 in ?? ()
#3 0x00007ffff7c9d7fc in ?? () from /usr/lib/libc.so.6
#4 0x00007ffff7c9d879 in pthread_once () from /usr/lib/libc.so.6
...
#16 0x00007ffff7c27892 in __libc_start_main () from /usr/lib/libc.so.6

rax = 0x0 rcx = 0x0 rdi = 0x0

=> 0x1d10458 : mov (%rax,%rcx,1),%rdi ; RAX is a NULL table pointer
0x1d1045c : test %rdi,%rdi
0x1d1045f : je 0x1d1047f
```

`RAX` (loaded via a `rip`-relative global at the top of `free`) is `NULL`, i.e. the binary's own heap-metadata table was never initialized for this allocation — consistent with `free()` being invoked on a pointer that the *system* libc's own `malloc` allocated internally (inside `newlocale`/`pthread_once` locale bootstrap), not the binary's bundled allocator.

## Expected Behavior

`claude install` completes successfully, as it does on other Linux distributions.

## Root-Cause Confirmation

1. Setting `vm.mmap_rnd_bits=28` (ruling out an ASLR/ address-layout theory) had **no effect** — crash address (`0x1d10458`) and register state were byte-for-byte identical across runs, i.e. it's deterministic, not layout-dependent.
2. Running the *exact same downloaded `linux-x64` binary* inside a Docker container:
- `ubuntu:22.04` (glibc **2.35**) → installs successfully, no crash.
- Host Arch Linux (glibc **2.44**) → segfaults every time.
3. `LC_ALL=C LANG=C` env vars do not avoid the crash (still segfaults, same address).

This strongly suggests a regression/incompatibility introduced somewhere between glibc 2.35 and 2.44 in how `newlocale()` (or its internal `pthread_once`-guarded locale-category init path) interacts with a statically-linked allocator that overrides the process-wide `malloc`/`free` symbols.

## Workaround

Downloading and running the **musl** build instead of the glibc build completely avoids the issue, since musl doesn't participate in this dynamic symbol interposition the same way:

```bash
sudo pacman -S musl # official Arch `extra` repo, ~3.7MB, does not touch system glibc

version=$(curl -fsSL https://downloads.claude.ai/claude-code-releases/latest)
curl -fsSL -o /tmp/claude-musl "https://downloads.claude.ai/claude-code-releases/$version/linux-x64-musl/claude"
chmod +x /tmp/claude-musl
/tmp/claude-musl install
```

This installs and runs `claude` successfully on the same host.

## Suggested Fix

- Investigate why the bundled allocator's `free()` is reachable from `libc.so.6`-internal calls (e.g. `newlocale`) on newer glibc, and/or avoid globally exporting `malloc`/`free` symbols from the binary in a way that shadows the system libc's own internal allocations.
- As a pragmatic short-term mitigation, `install.sh` / the updater could detect the glibc version at install time and prefer the `-musl` build when the detected glibc is newer than whatever version the binary was validated against, since the musl build is already published and unaffected.

Happy to provide the full binary, a core dump, or further `gdb`/`objdump` output if useful.

コントリビューションガイド

このリポジトリのコントリビューションガイドは索引されていません

調査の方向性

Start by reproducing the crash with the downloaded `linux-x64` binary on Arch Linux, then compare it with the successful Ubuntu 22.04 and musl runs described in the issue. Use the provided backtrace to investigate allocator symbol interposition between the binary and libc during `newlocale()`; done means `claude install` succeeds on Arch with glibc 2.44.

索引モデルが issue の本文から書いたものです。

評価

技術スタック
linux
領域
operating-systems
issue の種類
バグ
難易度
4/5
見積もり時間
3〜5日
活発さ
活発
明瞭さ
明確に書かれている
初心者へのやさしさ
42/100

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。