Skip to content

libc: report complete locale information - #916

Closed
brandonpayton wants to merge 1 commit into
mainfrom
fix/libc-locale-names
Closed

libc: report complete locale information#916
brandonpayton wants to merge 1 commit into
mainfrom
fix/libc-locale-names

Conversation

@brandonpayton

@brandonpayton brandonpayton commented Jul 13, 2026

Copy link
Copy Markdown
Member

Why

A locale object tells the C standard library (libc) how to format language-dependent information such as month names. POSIX.1-2024 defines the behavior applications should observe when they query those objects.

Kandelo's POSIX.1-2024 locale surface reported invented or missing data: getlocalename_l() always returned "C" without reading the supplied locale object, and nl_langinfo_l() returned empty strings for the declared ALTMON_* and ABALTMON_* items. Locale-aware software and Homebrew build probes therefore could not observe the locale state that libc actually held.

This makes locale names truthful for local and global locale objects on both hosts and supplies the alternate-month fallback that musl's catalog model can represent.

What changed

  • getlocalename_l() was a Kandelo stub rather than an implementation over musl's locale_t category maps.
  • musl's private mixed-LC_ALL codec used ; as a delimiter even though ; is legal in musl locale names, so it could not meet POSIX's required same-process getlocalename_l(LC_ALL) -> setlocale(LC_ALL, ...) round trip for every valid name.
  • A process-lifetime cache for composite names would grow with every combination queried. The finalized implementation instead keeps at most one composite-name entry per live non-global locale object and removes it under __locale_lock before successful in-place newlocale() mutation and before freelocale().

The shared serializer now uses /, which musl forbids inside locale names. The decoder requires exactly six nonempty, bounded fields and commits libc.global_locale only after every category has loaded, so malformed input cannot partially mutate process locale state. Legal semicolons remain ordinary locale-name data.

LC_GLOBAL_LOCALE mixed names use thread-local storage, matching POSIX's cross-thread pointer-lifetime requirement. Local-object results remain valid until the object is freed or successfully reused as a newlocale() base.

ALTMON_1..12 and ABALTMON_1..12 map to the existing full and abbreviated month catalog keys. This is documented as partial because musl catalogs do not encode a second grammatical month form.

Downstream coordination

Open PR #822 hardcodes Perl's target LC_ALL separator to musl's former ; representation. Before Perl is rebuilt with this libc, #822 (or the branch that absorbs it) must switch that target config and its assertions/docs to /, or avoid parsing the private representation. Existing statically linked binaries are unaffected. POSIX explicitly limits this encoding contract to round trips within the same process and permits the implementation-specific representation to change between builds.

ABI and artifacts

This changes statically linked libc behavior only. It does not change the kernel/host ABI, shared layouts, syscalls, Wasm exports, VFS metadata, or fork instrumentation. ABI_VERSION remains 18 and the ABI snapshot gate is clean. Programs and bottles must be rebuilt to consume the new libc behavior; no existing artifact is rewritten by this PR.

Validation

  • ./scripts/dev-shell.sh bash scripts/build-musl.sh - passed (wasm32)
  • ./scripts/dev-shell.sh bash scripts/build-musl.sh --arch wasm64posix - passed
  • fixture compile with -Wall -Wextra -Werror and direct guest execution - locale-info-ok
  • ./scripts/dev-shell.sh bash -c 'rm -rf host/dist; cd host && npx vitest run test/locale-info.test.ts' - 1 passed, 0 failed
  • ./scripts/dev-shell.sh bash -c 'rm -rf host/dist; cd apps/browser-demos && KANDELO_PLAYWRIGHT_PORT=5417 npx playwright test test/locale-info.spec.ts --project=chromium' - 1 passed, 0 failed
  • full libc suite - 303 passed, 0 failed, 20 expected failures, 1 known flaky, 324 total
  • Open POSIX suite - 174 passed, 0 failed, 3 expected failures, 2 skipped, 179 total
  • ./scripts/dev-shell.sh bash scripts/run-sortix-tests.sh --all - 5,035 passed, 0 failed, 19 expected failures, 52 skipped, 0 build failures, 0 timeouts, 5,106 total
  • ./scripts/dev-shell.sh bash scripts/check-abi-version.sh - snapshot and ABI version consistent
  • git diff --check origin/main..618f8d603 - clean

The focused Chromium run used the locally rebuilt ABI 18 kernel and fixture with a generated empty ABI 18 rootfs. The full host Vitest and aggregate browser suites were not run locally; CI remains the evidence for those broader surfaces.

An independent devil's-advocate review of commit 618f8d6031ed95bae4ab122cc6c98d99cdd96d6f found no blocking, high, or medium issues.

@brandonpayton

Copy link
Copy Markdown
Member Author

CI setup classification for exact head 618f8d6031ed95bae4ab122cc6c98d99cdd96d6f:

The current file, gawk, and gzip matrix failures are GitHub Actions infrastructure failures, not package or locale failures. Each job exhausted retries resolving action download metadata and ended with Service Unavailable before any build command ran:

The workflow is still running, so GitHub does not yet allow those jobs to be rerun. I will rerun the exact failed jobs once the run becomes eligible. This comment does not classify any later failure without inspecting its log.

@github-actions

github-actions Bot commented Jul 13, 2026

Copy link
Copy Markdown
Contributor

Phase B-1 matrix build status — pr-916-staging

ABI v18. 69 built, 0 failed, 69 total.

Package Arch Status Sha
libcurl wasm32 built c2eb35c3
libcxx wasm32 built 01454e96
libcxx wasm64 built 17edecea
libpng wasm32 built 9373ec07
libxml2 wasm32 built 29c66726
libxml2 wasm64 built c465e980
openssl wasm32 built 887151e1
openssl wasm64 built d233a2f2
sqlite wasm32 built 548305b0
sqlite wasm64 built 61788f0e
zlib wasm32 built 4224cc4d
zlib wasm64 built a9bf6489
bc wasm32 built 64949762
bzip2 wasm32 built 34c7aa1e
coreutils wasm32 built 2344bdb3
curl wasm32 built aa69b5db
dash wasm32 built 6c366450
diffutils wasm32 built 32032bc8
dinit wasm32 built 9ae1bce0
fbdoom wasm32 built ce3164e4
file wasm32 built 11dba372
findutils wasm32 built f67592ae
gawk wasm32 built e54fdc61
git wasm32 built 9b2d548d
grep wasm32 built fbf0203e
gzip wasm32 built b1c84007
hello wasm32 built eab596f0
kandelo-sdk wasm32 built f35dd048
kernel wasm32 built 5203e0d9
less wasm32 built 83900e94
lsof wasm32 built 544d229c
m4 wasm32 built 233df978
make wasm32 built 74046ca8
mariadb wasm32 built b4d8dcea
mariadb wasm64 built bdc57cfe
modeset wasm32 built dcac4290
msmtpd wasm32 built 29ebf352
nano wasm32 built aeeb65e1
ncurses wasm32 built e7b60d2b
netcat wasm32 built 6583d80f
nginx wasm32 built c6184ee2
php wasm32 built 01f079da
posix-utils-lite wasm32 built 4cc63712
ruby wasm32 built dcaf8e6a
sed wasm32 built 8576502e
spidermonkey wasm32 built 3de9f860
tar wasm32 built 0f292535
tcl wasm32 built c02e9685
unzip wasm32 built a4ea44c9
userspace wasm32 built 1af95362
vim wasm32 built d2117418
wget wasm32 built 89cd8b4f
xz wasm32 built 73d01c0f
zip wasm32 built 7e48916b
zstd wasm32 built 73150090
bash wasm32 built e3fd75d7
mariadb-test wasm32 built 7e42fd81
mariadb-vfs wasm32 built 14c8450f
mariadb-vfs wasm64 built 92763175
nethack wasm32 built 722e0fb7
node wasm32 built 64ef67eb
spidermonkey-node wasm32 built e765fc51
vim-browser-bundle wasm32 built acd74781
nethack-browser-bundle wasm32 built 1cbba481
rootfs wasm32 built f794d4ec
shell wasm32 built bd66f39b
lamp wasm32 built d086319f
node-vfs wasm32 built b21c4bd3
wordpress wasm32 built 8344e0e9

Auto-generated; replaced on each push. Raw data in the publish-status workflow artifact.

@brandonpayton

Copy link
Copy Markdown
Member Author

Absorbed by rebase-merged #967. Main is now 6efb411 with the sealed tree b133bfa018f7e2bc84c4845edf2f945b2f844954, and ABI 41 activation completed successfully in run 29550069085. The absorption audit confirmed this PR\x27s behavior and tests are present in that merged tree, so this source PR is closed and its branch is deleted.

@brandonpayton
brandonpayton deleted the fix/libc-locale-names branch July 17, 2026 02:39
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant