Skip to content

Instantly share code, notes, and snippets.

@axelhamil
Last active July 14, 2026 00:29
Show Gist options
  • Select an option

  • Save axelhamil/8b1fec5447334cbc4a2d5eaa0679e17e to your computer and use it in GitHub Desktop.

Select an option

Save axelhamil/8b1fec5447334cbc4a2d5eaa0679e17e to your computer and use it in GitHub Desktop.
Fix NVIDIA DKMS gcc internal compiler error (segfault) on Arch — raise cc1 stack limit instead of downgrading gcc

nvidia-dkms-stackfix

Fixes NVIDIA DKMS modules failing to build on Arch Linux with an internal compiler error: Segmentation fault — by raising the compiler's stack limit, not by downgrading gcc.

Symptom

A pacman -Syu pulls a new kernel or NVIDIA driver, and the DKMS rebuild fails:

inc/libraries/utils/nv_enum.h:397:20: internal compiler error: Segmentation fault
make[1]: *** [Makefile:203: _out/Linux_x86_64/kern_mem_sys_ga100.o] Error 1
make: *** [Makefile:34: src/nvidia/_out/Linux_x86_64/nv-kernel.o] Error 2
Error! Bad return status for module build on kernel: 6.18.38-1-lts (x86_64)

The pacman hooks then regenerate the initramfs without the nvidia modules:

==> ERROR: module not found: 'nvidia'
==> ERROR: module not found: 'nvidia_modeset'
==> ERROR: module not found: 'nvidia_uvm'
==> ERROR: module not found: 'nvidia_drm'

Reboot in that state and you land on a black screen.

The actual cause

This is not "the new gcc can't compile the NVIDIA source". gcc — both 15 and 16 — segfaults while lexing the very large NV_ENUM_GENERATOR / NV_ENUM_DEF macro in nv_enum.h. The backtrace sits in the C front-end, not the optimizer:

internal_error(char const*, ...)
c_lex_with_flags(tree_node**, unsigned long*, unsigned char*, int)
c_parse_file()

That is cc1 running out of stack. The default soft stack limit is 8 MB (ulimit -s8192), and expanding that macro overflows it. Upstream this is gcc bug c++/120257 (deeply nested macros, marked WONTFIX — clang reports a clean "function scope depth exceeded" instead of crashing).

It explains two things that usually confuse people:

  • Why downgrading gcc "sometimes" helps. An older gcc happens to use slightly less stack and stays under 8 MB by luck. It is not a real fix and stops working the moment that gcc version regresses too.
  • Why it fails for one kernel but not another in the same update. Different kernel headers change the macro expansion just enough to cross the 8 MB line on one kernel and not the other. Building with fewer parallel jobs (-j1) can also slip under the line by chance — same reason, not a real fix.

The fix

Raise the stack limit before building:

ulimit -s unlimited

With an unlimited stack the stock gcc builds the modules fine — no downgrade, no gcc14/gcc15 shim, no clang. Everything else the script does is convenience and safety around that one line.

Proof (A/B)

Same machine, same nvidia-open-dkms 610.43.03, same kernel 7.1.3-arch1, same stock gcc 16, same make -j20 — the only variable changed is the stack limit:

stack limit result
8 MB (default) internal compiler error: Segmentation fault
ulimit -s unlimited builds, signs and installs cleanly

So it is the stack — not the gcc version, not the parallelism (-j), not RAM/OC.

Usage

curl -Lo fix-nvidia-dkms https://gist.githubusercontent.com/axelhamil/8b1fec5447334cbc4a2d5eaa0679e17e/raw/fix-nvidia-dkms
chmod +x fix-nvidia-dkms
sudo ./fix-nvidia-dkms

Run it whenever a pacman -Syu leaves your NVIDIA DKMS build broken.

What the script does

  • Raises the stack limit (ulimit -s unlimited) — the actual fix.
  • Auto-detects the installed nvidia DKMS version and every kernel that has headers.
  • Skips kernels whose module is already built; rebuilds only the ones that failed.
  • Re-runs depmod for every kernel that carries the module, so an already-built module that is missing from modules.dep still gets picked up.
  • Regenerates every initramfs (mkinitcpio -P).
  • Verifies each initramfs actually contains the nvidia modules before reporting success — so you never reboot into a black screen.

If dkms says installed but the initramfs still has no nvidia

If a previous run built the module with dkms install --no-depmod (the Arch pacman hook does this and defers depmod to the end), the module can be present in /usr/lib/modules/<kver>/updates/dkms/ while modules.dep never learned about it. Then dkms status says installed, modinfo -k <kver> nvidia says Module nvidia not found, and mkinitcpio fails with module not found: nvidia. The build is fine — only the index is stale. Rebuild it:

sudo depmod <kver> && sudo mkinitcpio -p linux

The script now does this depmod pass unconditionally, so re-running it is enough to recover from that state without a rebuild.

If the stock gcc still crashes

Force a specific compiler installed alongside (e.g. an older gcc):

sudo FIXNV_CC=gcc-14 ./fix-nvidia-dkms

Tested on

Arch Linux, RTX 50-series, nvidia-open-dkms, gcc 16, linux + linux-lts kernels.

License

MIT

#!/usr/bin/env bash
# ulimit -s unlimited is the actual fix: cc1 (gcc 15/16) segfaults while lexing
# the huge NV_ENUM_GENERATOR macro in the NVIDIA source (gcc bug c++/120257) =
# a stack overflow. A large stack lets the stock gcc build fine, no downgrade.
# FIXNV_CC=gcc-14 forces another compiler if the stock gcc still crashes.
set -euo pipefail
[[ $EUID -eq 0 ]] || { echo "Run as root: sudo $0" >&2; exit 1; }
ulimit -s unlimited
NV_VER=$(dkms status nvidia 2>/dev/null | sed -n 's#^nvidia/\([^,]*\),.*#\1#p' | head -1)
[[ -n "$NV_VER" ]] || { echo "No nvidia DKMS module found." >&2; exit 1; }
echo ">> nvidia/$NV_VER (stack $(ulimit -s))"
BUILD=(env)
CC_BIN=${FIXNV_CC:-}
if [[ -n "$CC_BIN" ]]; then
command -v "$CC_BIN" >/dev/null || { echo "$CC_BIN not found" >&2; exit 1; }
CXX_BIN=${CC_BIN/gcc/g++}
SHIM=$(mktemp -d /tmp/cc-shim.XXXXXX)
trap 'rm -rf "$SHIM"' EXIT
ln -sf "$(command -v "$CC_BIN")" "$SHIM/gcc"
ln -sf "$(command -v "$CC_BIN")" "$SHIM/cc"
ln -sf "$(command -v "$CXX_BIN")" "$SHIM/g++"
BUILD=(env "PATH=$SHIM:/usr/bin:/bin" CC="$CC_BIN" CXX="$CXX_BIN" HOSTCC="$CC_BIN" HOSTCXX="$CXX_BIN")
echo ">> forced compiler: $CC_BIN"
fi
for kdir in /usr/lib/modules/*/build; do
[[ -e "$kdir" ]] || continue
KVER=$(basename "$(dirname "$kdir")")
if dkms status "nvidia/$NV_VER" 2>/dev/null | grep "$KVER," | grep -q installed; then
echo ">> $KVER: already installed"
continue
fi
echo ">> $KVER: building..."
dkms remove "nvidia/$NV_VER" -k "$KVER" 2>/dev/null || true
"${BUILD[@]}" dkms install "nvidia/$NV_VER" -k "$KVER"
done
# A module already built but missing from modules.dep (e.g. an earlier
# --no-depmod build) makes mkinitcpio fail with "module not found" even though
# dkms says installed. Re-run depmod for every kernel that carries the module.
for kdir in /usr/lib/modules/*/; do
KVER=$(basename "$kdir")
ls "$kdir"updates/dkms/nvidia.ko* >/dev/null 2>&1 && depmod "$KVER"
done
echo ">> mkinitcpio -P"
mkinitcpio -P
fail=0
for img in /boot/initramfs-*.img; do
[[ -e "$img" ]] || continue
case "$img" in *fallback*) continue ;; esac
n=$(lsinitcpio "$img" 2>/dev/null | grep -c nvidia || true)
if (( n >= 4 )); then echo " OK $img ($n)"; else echo " MISSING $img ($n)"; fail=1; fi
done
(( fail == 0 )) && echo ">> OK, safe to reboot." || {
echo ">> An initramfs is missing the nvidia modules, DO NOT reboot." >&2; exit 1; }
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment