anthropics / anthropics/claude-code

2.1.243 native build segfaults instantly on startup: interposed free() crashes on free(NULL) from glibc 2.44 newlocale

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

説明

## Summary

The native (Bun standalone) Linux x64 build of **2.1.243 segfaults on every invocation** — including `claude --version` — before printing a single byte. **2.1.241, 2.1.236 and 2.1.235 all run fine on the same machine.**

This is not a corrupt download: I hashed my copy, deleted it, re-downloaded via `claude install latest`, and got a **byte-identical binary** (sha256 `4b0dafeedd0b469c41988e200036fd773e7553ba960349c9f02a82c6d1f2ba27`) that segfaults identically.

I have a core dump and disassembly; the root cause is below.

## Environment

- CachyOS Linux, kernel `7.2.0-1-cachyos`, bare metal
- glibc **2.44** (`ldd (GNU libc) 2.44`)
- Intel Core i7-7700 (sse4_2, avx, avx2 — no AVX-512)
- Both 2.1.241 and 2.1.243 embed **Bun v1.4.0** (per `strings`), so it is not a runtime bump
- Locale-independent: crashes under `LC_ALL=C`, `C.UTF-8`, and `env -i HOME=$HOME PATH=/usr/bin`
- ASLR-independent: crashes under `setarch -R` (binary is non-PIE anyway)

## Crash

dmesg (identical `ip` on every run):

```
claude[15182]: segfault at 0 ip 0000000001d10458 sp 00007ffe2cb0dfb0 error 4 in 2.1.243[1b0f458,1953000+3b33000]
```

`error 4` + `at 0` = user-mode read of unmapped page at address 0. `si_code: SEGV_MAPERR`.

coredumpctl backtrace:

```
#0 0x0000000001d10458 free (2.1.243 + 0x1b10458)
#1 0x00007fdfbce3a1ab __newlocale (libc.so.6 + 0x3a1ab)
#2 0x0000000001abd282 n/a (2.1.243 + 0x18bd282)
#3 0x00007fdfbceb2584 n/a (libc.so.6 + 0xb2584)
#4 0x00007fdfbceb26a9 pthread_once (libc.so.6 + 0xb26a9)
#5 0x0000000001abc2d2 n/a (2.1.243 + 0x18bc2d2)
...
#16 0x00007fdfbce27e23 __libc_start_main (libc.so.6 + 0x27e23)
```

Registers at the fault (gdb on the core):

```
rax 0x0 rcx 0x0 rdi 0x0 rsi 0x0
```

## Root cause

**2.1.243 newly interposes the C allocator, and the interposed `free` crashes on `free(NULL)`.**

1. 2.1.243 exports `malloc` / `free` / `__libc_malloc` / `__libc_free` / `__libc_cfree` as strong symbols from the executable. **2.1.241 exports none of these** — this is the regression between the two builds:

```
$ nm 2.1.241 | grep -E ' (free|malloc|__libc_)' → (nothing)
$ nm 2.1.243 | grep -E ' (free|malloc|__libc_)'
0000000001d10430 T free
0000000001d10430 T __libc_cfree
0000000000d10430 T __libc_free
0000000001d102d0 T __libc_malloc
0000000001d102d0 T malloc
```

Because the executable wins symbol resolution, glibc's own *internal* `free` calls now land in the bundled allocator (mimalloc).

2. During startup, a static initializer in the binary (frame #2, under `pthread_once`) calls glibc `newlocale()`. On glibc 2.44 this path calls `free(NULL)` (legal; must be a no-op).

3. The interposed `free` does its segment-map lookup **before** any NULL check. Disassembly at the fault:

```asm
0000000001d10430 <__libc_cfree>:
1d10434: mov %rdi,%rsi
1d10437: mov 0x3781982(%rip),%rax # segment map @ 0x5491dc0
1d1043e: mov %rdi,%rcx
1d10441: shr $0x1d,%rcx
1d10445: mov 0x80(%rax,%rcx,8),%rax # map entry for ptr 0 → 0
1d1044d: mov %esi,%ecx
1d1044f: shr $0xd,%ecx
1d10452: and $0xfff8,%ecx
1d10458: mov (%rax,%rcx,1),%rdi # ← deref of NULL entry: SIGSEGV
1d1045c: test %rdi,%rdi # null check comes one insn too late
1d1045f: je ...
```

With `rdi = 0` (the freed pointer): the segment-map entry for pointer 0 is 0, and the code dereferences it at `1d10458` before the `test %rdi,%rdi` guard. Deterministic crash at a fixed address on every run — matching the identical `ip` in all dmesg lines.

So any glibc whose `newlocale`/startup path calls `free(NULL)` (glibc 2.44 here) kills 2.1.243 instantly, regardless of locale settings or environment. Upstream mimalloc handles a NULL segment-map entry (`mi_free(NULL)` is a no-op), so this looks like the check was reordered/dropped in this build's interposition shim or by LTO.

## Steps to reproduce

On a glibc 2.44 system (e.g. up-to-date Arch/CachyOS):

```
~/.local/share/claude/versions/2.1.243 --version # SIGSEGV
~/.local/share/claude/versions/2.1.241 --version # 2.1.241 (Claude Code)
```

## Workaround

```
ln -sf ~/.local/share/claude/versions/2.1.241 ~/.local/bin/claude
```

plus pinning in `~/.claude/settings.json`:

```json
{ "autoUpdatesChannel": "stable", "minimumVersion": "2.1.241" }
```

(Note: `claude install latest` repoints the symlink back at the broken build, so the auto-updater re-breaks the install until pinned.)

## Possibly related

#84293 reports a startup crash on Bun 1.4.0/x64-baseline, but that one is `si_code=SI_KERNEL` (general protection fault) and was closed as a corrupt download. Mine is `SEGV_MAPERR` with a verified-identical re-download — different fault class, and evidence that report may have been misdiagnosed.

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

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

調査の方向性

Start by reproducing the crash with ~/.local/share/claude/versions/2.1.243 --version on glibc 2.44, then compare its allocator symbols and disassembly with 2.1.241. Verify the native build's free(NULL) path and startup initialization; done means the 2.1.243 binary starts and prints --version without crashing on the reported environment.

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

評価

技術スタック
bun, linux
領域
build-system, cli, operating-systems
issue の種類
バグ
難易度
4/5
見積もり時間
3〜5日
活発さ
活発
明瞭さ
おおむね明確
初心者へのやさしさ
52/100

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

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