anthropics / anthropics/claude-code
2.1.243 native build segfaults instantly on startup: interposed free() crashes on free(NULL) from glibc 2.44 newlocale
- Lenguaje dominante
- Python
- Estrellas
- 145k
- Forks
- 23.1k
- Métricas de merge de PR
- Métricas de PR pendientes
Descripción
## 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.
Guía de contribución
No hay ninguna guía de contribución indexada para este repositorio
Línea de trabajo
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.
Escrito por el modelo de indexación a partir del texto del issue.
Evaluación
- Stack tecnológico
- bun, linux
- Área
- build-system, cli, operating-systems
- Tipo de issue
- Error
- Dificultad
- 4/5
- Tiempo estimado
- 3-5 días
- Estado de actividad
- Activo
- Claridad
- Bastante claro
- Aptitud para principiantes
- 52/100