anthropics / anthropics/claude-code

[BUG] v2.1.242 segfaults on every launch (even `--version`) — interposed mimalloc `free` has no NULL check, glibc `newlocale` calls `free(NULL)` pre-main; v2.1.241 unaffected

Abierto
#89,334 16 comentarios 11 reacciones 0 asignados Ver en GitHub
area:packaging bug has repro platform:linux regression
Lenguaje dominante
Python
Estrellas
145k
Forks
23.1k
Métricas de merge de PR
Métricas de PR pendientes

Descripción

## Summary

v2.1.242 (native install, Linux x64) segfaults on **every** invocation, including `claude --version`. The crash is pre-`main`, during startup. v2.1.241 and earlier are unaffected.

Root cause: 2.1.242 is the first build to export its bundled mimalloc as **versioned glibc allocator symbols**, which interposes the allocator process-wide. The interposed `free` does not handle a NULL argument, so the first `free(NULL)` anywhere in the process — glibc's own `newlocale` makes one during startup — dereferences a null pointer.

`free(NULL)` is required to be a no-op (C17 7.22.3.3p2), so this will fire on any libc path that frees a null pointer.

## Reproduction

```
$ ~/.local/share/claude/versions/2.1.242 --version
[1] 88020 segmentation fault (core dumped)
$ echo $?
139
```

Every launch, 100% reproducible, no config or arguments required.

Adjacent versions on the same machine, same glibc, same shell:

```
2.1.239: exit=0 2.1.239 (Claude Code)
2.1.240: exit=0 2.1.240 (Claude Code)
2.1.241: exit=0 2.1.241 (Claude Code)
2.1.242: exit=139 (SIGSEGV)
```

## Backtrace

```
Signal: 11 (SEGV) si_code: SEGV_MAPERR
#0 0x0000000001d10458 in free () <- in the claude binary, not libc
#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
#5 0x0000000001abc2d2 in ?? ()
...
#16 0x00007ffff7c27892 in __libc_start_main () from /usr/lib/libc.so.6
#17 0x0000000001953a2e in ?? ()
```

## Root cause

**1. 2.1.242 newly interposes the process allocator.** `readelf --dyn-syms` on the two builds:

```
$ readelf --dyn-syms --wide 2.1.241 | grep -E '\b(free|malloc|calloc|realloc|aligned_alloc|posix_memalign)\b'
(no output)

$ readelf --dyn-syms --wide 2.1.242 | grep -E '\b(free|malloc|calloc|realloc|aligned_alloc|posix_memalign)\b'
560: 0000000001d10320 145 FUNC GLOBAL DEFAULT 17 calloc@@GLIBC_2.2.5
700: 0000000001d102d0 79 FUNC GLOBAL DEFAULT 17 malloc@@GLIBC_2.2.5
862: 0000000001d10b70 122 FUNC GLOBAL DEFAULT 17 aligned_alloc@@GLIBC_2.16
927: 0000000001d10ab0 181 FUNC GLOBAL DEFAULT 17 posix_memalign@@GLIBC_2.2.5
1048: 0000000001d10430 126 FUNC GLOBAL DEFAULT 17 free@@GLIBC_2.2.5
1213: 0000000001d103c0 98 FUNC GLOBAL DEFAULT 17 realloc@@GLIBC_2.2.5
```

The executable is first in the global symbol lookup scope, so glibc's own internal calls to `free` now bind to mimalloc inside the claude binary.

**2. The interposed `free` has no NULL check.** Disassembly of `free` in 2.1.242:

```
0000000001d10430 :
1d10430: push %rbp
1d10431: mov %rsp,%rbp
1d10434: mov %rdi,%rsi
1d10437: mov 0x3781982(%rip),%rax # segment map base
1d1043e: mov %rdi,%rcx
1d10441: shr $0x1d,%rcx # ptr >> 29
1d10445: mov 0x80(%rax,%rcx,8),%rax # rax = map[ptr >> 29] -> NULL for ptr==0
1d1044d: mov %esi,%ecx
1d1044f: shr $0xd,%ecx
1d10452: and $0xfff8,%ecx
1d10458: mov (%rax,%rcx,1),%rdi # <-- SIGSEGV, rax=0, rcx=0 => load from 0x0
```

With `ptr == NULL`: `rcx = 0`, the segment-map slot is NULL, and the next load dereferences address 0. No null guard anywhere on this path.

**3. The faulting call really is `free(NULL)`.** Breaking on `free` shows the first call in the process is null, and it is the one that crashes:

```
$ gdb -batch -ex 'break free' -ex 'run --version' -ex 'printf "free arg #1 = %p\n", $rdi' -ex continue --args 2.1.242 --version
Breakpoint 1.1, 0x0000000001d10434 in free ()
free arg #1 = (nil)

Program received signal SIGSEGV, Segmentation fault.
0x0000000001d10458 in free ()
```

Register state at the fault corroborates it: `rax=0`, and `rsi=0` — `rsi` is the preserved copy of the incoming argument made at `free+4` and never rewritten before the fault.

## Ruled out

- **Not locale-dependent.** `LC_ALL=C LANG=C` crashes identically. `newlocale` is simply the first libc path to hit `free(NULL)`.
- **Not a corrupt or truncated download.** Valid ELF, `ldd` resolves cleanly, binary is not stripped.
- **Not a glibc regression.** glibc 2.44 has been installed since 2026-08-12; 2.1.241 was installed 2026-08-23 and works fine on that same glibc.
- **Not launcher/wrapper related.** Executing the versioned binary directly reproduces it.

## Environment

- Claude Code 2.1.242, native install (`~/.local/share/claude/versions/2.1.242`)
- `BUILD_TIME: 2026-08-24T17:00:10Z`, `GIT_SHA: 2482ce9083708842d832441fde1721626f306157`
- Binary size jumped 342,636,848 -> 377,568,472 bytes vs 2.1.241
- Arch Linux, kernel 7.1.8-zen1-3-zen x86_64
- glibc 2.44 (`glibc 2.44+r24+g16be1518495f-1`)
- AMD Ryzen 7 5800X3D

## Impact

The CLI cannot start at all, which also means it cannot auto-update out of the broken state. Recovery requires manually repointing `~/.local/bin/claude` at an older version:

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

## Suggested fix

Add the standard `if (p == NULL) return;` guard to the exported `free` (and check `realloc(NULL, n)` on the same interposition path), or stop exporting versioned glibc allocator symbols so mimalloc is only used for the runtime's own allocations.

Possibly related pre-`main` startup regression from the same area: #87583.

Guía de contribución

No hay ninguna guía de contribución indexada para este repositorio

Línea de trabajo

No source files or tests are named. Start by locating the bundled mimalloc allocator and its symbol-export configuration, then compare versions 2.1.241 and 2.1.242 with readelf and inspect the exported free/realloc paths. Reproduce with the versioned binary and --version; done when startup succeeds and free(NULL) no longer crashes.

Escrito por el modelo de indexación a partir del texto del issue.

Evaluación

Stack tecnológico
c, linux
Área
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
38/100

Recibe los nuevos issues en tu correo

Un resumen breve de issues de GitHub para principiantes.