pacman heap-corrupts and aborts in alpm_trans_commit on large transactions (~98+ packages)
- Dominant language
- C
- Stars
- 14
- Forks
- 4
- PR merge metrics
- No merged PRs in 30d
Description
pacman -Su` reliably aborts with glibc heap corruption when the transaction is
large (~98+ packages). The abort happens at the **first pre-transaction hook**,
so nothing is ever installed. Small transactions are unaffected.
```
:: Running pre-transaction hooks...
(1/9) Rejecting pacman transaction if running in snapshot...
corrupted size vs. prev_size while consolidating
error: command terminated by signal 6: Aborted
error: failed to commit transaction (failed to run transaction hooks)
Errors occurred, no packages were upgraded.
```
The message points at a pacman hook, but the hook is not at fault — see below.
### Environment
| | |
|---|---|
| pacman | `7.1.0.r9.g54d9411-4` (repo `cachyos`, `Architecture: x86_64`, Packager: CachyOS, built 2026-06-14) |
| Arch equivalent | `core/pacman 7.1.0.r9.g54d9411-2` — same upstream git revision |
| Distro | Garuda Linux, CachyOS `znver4` repos enabled |
| CPU | AMD Ryzen 7 7840HS |
| Kernel | 7.1.6-zen1-1-zen |
### It is not the hook
`error: command terminated by signal 6` reads like the hook script died, but
`/usr/share/libalpm/scripts/garuda-hooks-runner` is plain bash. A **forked
pacman child still reports `Executable: /usr/bin/pacman`** in coredumpctl, which
is what is actually crashing. Backtrace (stripped, no debug package available):
```
#5 0x00007fcc2debc4dc in ?? () from /usr/lib/libc.so.6
#6 0x00007fcc2debc5a4 in ?? () from /usr/lib/libc.so.6
#7 0x00007fcc2e59bc77 in ?? () from /usr/lib/libalpm.so.16
#8 0x00007fcc2e5a7ef4 in ?? () from /usr/lib/libalpm.so.16
#9 0x00007fcc2e5946e0 in ?? () from /usr/lib/libalpm.so.16
#10 0x00007fcc2e5aa436 in ?? () from /usr/lib/libalpm.so.16
#11 0x00007fcc2e5990a4 in ?? () from /usr/lib/libalpm.so.16
#12 0x00007fcc2e5a7bb8 in alpm_trans_commit () from /usr/lib/libalpm.so.16
#13 0x00005564d4c428ac in ?? ()
```
pacman corrupts its own heap during `alpm_trans_commit`; glibc detects it when
the child forks to run the hook.
### Reproduction / threshold
| transaction size | result |
|---|---|
| 1 package | OK, all hooks run |
| 16 packages | OK (used ~13 times consecutively to complete the upgrade) |
| 98 packages | **crash** |
| 193 packages | **crash** |
The corruption is **non-deterministic in kind** — across five runs of the same
transaction glibc reported both `corrupted size vs. prev_size while
consolidating` and `double free or corruption (!prev)` — but deterministic in
occurrence at large sizes.
### Ruled out
- `pacman -Dk` → "No database errors have been found!"
- `pacman -Qkk pacman` → 426 files, **0 altered** (on-disk binary matches the package)
- No `NoExtract` / `NoUpgrade` / `IgnorePkg` directives in `pacman.conf`
- Not disk or DB corruption; not the distro's hook scripts
### Users cannot fall back to stock pacman
Worth noting since it removes the obvious workaround: `core/pacman` **cannot** be
substituted on a CachyOS-repo system. It rejects every optimized package with
`error: failed to prepare transaction (package architecture is not valid)` /
`does not have a valid architecture`, and emits
`warning: : unknown key '%INSTALLED_DB%' in local database` for every
locally installed package.
### Possibly relevant build difference
Same upstream source, very different codegen — `libalpm.so.16.0.1` `.text`:
| build | `.text` size | file size |
|---|---|---|
| CachyOS | **1,637,311 bytes** | 2,025,008 |
| Arch `core` | **184,637 bytes** | 281,240 |
An 8.9× code-size difference. The CachyOS build additionally links `libm`, which
the Arch build does not. Both are stripped and declare identical `NEEDED` libs,
so this is generated code, not static linking. I don't know whether the cause is
the build flags or the CachyOS patches (`x86_64_v4` architecture support, the
`%INSTALLED_DB%` local-DB field) — the latter is per-package work, which would
scale with transaction size the way the crash does.
### Workaround
Upgrading in batches of ~16 completes fine. Note that batches must also avoid
splitting exact-version pinned pairs (e.g. `python-curl_cffi` requires
`curl-impersonate=1.5.6`), since `pacman -S ` will not pull in a reverse
dependent that must move in lockstep.
Contributor guide
No contributing guide indexed for this repository
Research direction
Reproduce the failure with 98- and 193-package transactions, then start at alpm_trans_commit and compare the CachyOS and Arch libalpm builds. Use the coredump backtrace and the reported build differences to narrow the heap corruption; done means large transactions complete without aborting while small transactions and hooks continue to work.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- c
- Domain
- cli
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100