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


Attachment: 0001-lib-intl-cache-the-primary-language-preference-in-se.patch
Description: Binary data

Reply via email to