Configuration Information: Machine: aarch64 OS: darwin27.2.0 Compiler: clang Compilation CFLAGS: (Nixpkgs build) uname output: Darwin 27.2.0 Darwin Kernel Version 27.2.0: Wed Oct 14 23:47:32 PDT 2026; root:xnu-13432.41.4~25/RELEASE_ARM64_T6031 arm64 Machine Type: aarch64-apple-darwin25.6.0
Bash Version: 5.3
Patch Level: 20
Release Status: release
Description:
On macOS, a temporary locale assignment for a builtin in a subshell,
such as `LANG=C read ...' in the body of `find ... | while read ...',
intermittently crashes the subshell with SIGSEGV. When bash restores
the locale, reset_locale_vars calls setlocale (LC_ALL, ""). The
libintl setlocale then calls CFLocaleCopyPreferredLanguages() in the
fork()ed child, which Apple's fork(2) says is unsafe before exec():
libsystem_trace _os_log_preferences_refresh <- EXC_BAD_ACCESS
CoreFoundation CFLocaleCopyPreferredLanguages
bash libintl_setlocale
bash reset_locale_vars
bash sv_locale
bash dispose_temporary_env
It needs the same setting as bug #68453
(https://savannah.gnu.org/bugs/?68453): an AppleLocale that libc
rejects, such as "en_DE" or "en_US@rg=fizzzz" (English with a
non-default region), with LANG and LC_* unset. setlocale_single
(LC_MESSAGES, ...) then fails, and the fallback in
lib/intl/setlocale.c looks up the preferred languages again on every
call, without caching. It still happens on devel, with the
setlocale.c from gettext 1.0. I have reported it to gettext and
gnulib:
https://lists.gnu.org/archive/html/bug-gettext/2026-11/msg00001.html
It hits Nix builds on macOS often, because the stdenv setup hooks
use `LANG=C read' in `find | while' loops: about 13% of my local
darwin builds since December 2025 had at least one such crash.
Repeat-By:
Set System Settings > Language & Region to English with a region
such as Finland or Germany, so that `defaults read -g AppleLocale'
shows a modifier or a combination like en_DE. Then:
LOOP='find /usr/bin -maxdepth 1 -type f -print0 | head -c 4000 |
while IFS= read -r -d "" f; do
LANG=C read -r -n 4 -u 3 m 3<"$f" 2>/dev/null
done'
for i in $(seq 1 200); do
env -i HOME=/homeless-shelter PATH=/usr/bin:/bin ./bash -c "$LOOP"
done 2>&1 | grep -c 'Segmentation fault'
Crashes in 200 runs: bash-5.3.20: 28 to 36; devel (5.4.0-devel): 28.
`LANG=C :' instead of `LANG=C read' crashes just as often.
Fix:
The attached patch, against devel's lib/intl/setlocale.c, moves
the preferred-language lookup into a function that caches its
result. The first lookup happens in set_default_locale(), before
any fork(), so subshells reuse the cached value. (If bash starts
with LANG set and a subshell later unsets it, the first lookup
can still happen in the child.) With it, devel had 0 crashes in
600 runs (and 0 in 200 with `LANG=C :'); lldb shows no
CoreFoundation call from reset_locale_vars, and LC_MESSAGES ends
up with the same value ("en"). The same change on 5.3.20 had 0
crashes in 600 runs, and the German messages still work.
AI disclosure: Claude Opus 5.5 has been used in the process.
Mika Tammi
0001-lib-intl-cache-the-primary-language-preference-in-se.patch
Description: Binary data
