Repository navigation
Parse glibc guests' options the way glibc's getopt does - #15
Open
buyemune-sys wants to merge 2 commits into
Open
buyemune-sys wants to merge 2 commits into
buyemune-sys wants to merge 2 commits into
Conversation
Security updates replaced libapparmor1 4.0.1really4.0.1-0ubuntu0.24.04.7 with .9 and libexpat1 2.6.1-2ubuntu0.4 with ubuntu0.6, and the pool kept only the new files, so the cold-cache Fetch x86_64 job answers 404 and every x86-64 job behind it is skipped. Both pins move to the versions noble-updates ships now; their SHA256s match the archive's Packages index. The other twelve pins are still served.
glibc's getopt family differs from musl's in ways programs notice: - glibc's getopt permutes argv just like getopt_long, so `prog file -v` still sees -v; musl's getopt stops at the first operand. Only a string starting with '+' or '-', POSIXLY_CORRECT, or __posix_getopt keep glibc in order. - musl's getopt_long, permuting past a short option whose argument is missing at the end of argv, leaves optind at argc + 1 and rotates argv's NULL terminator into the vector. glibc stops at argc and keeps argv terminated. - The diagnostics: "invalid option -- 'Z'" and "option requires an argument -- 'n'" against musl's "unrecognized option: Z" and "option requires an argument: n", and likewise for every long-option error. Tarantool's test suite matches glibc's wording, and so do users' scripts. - __posix_getopt resolved straight to musl's export of that name, which never touches the executable's copy of optind: a guest parsing with it in a COPY-relocated executable looped on the same argument forever. The bridge now finds the next option element itself and has musl parse only that element, with musl's messages off. It then rotates what musl consumed in front of the operands the scan stepped over, the order glibc's exchange leaves, and prints glibc's message. __posix_getopt joins the overridden names. Two glibc rules stay out of reach without replacing musl's parser: an abbreviation that matches several options with identical effect is not ambiguous to glibc, and getopt_long_only skips an unknown "-xyz" as a whole rather than trying it as short options. The conformance battery checks permutation, argv integrity after a missing argument, and each diagnostic. The guest executable parses with __posix_getopt through its own copy of optind. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
buyemune-sys
force-pushed
the
fix/glibc-getopt
branch
from
October 20, 2026 08:11
ded7cee to
adb8241
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
The problem
The getopt family went straight to musl, apart from the
optind/optargshuttle around it (lib/glibc_shim.cpp:1603). glibc's getopt behaves differently in ways programs notice:Permutation. glibc's
getoptpermutes argv just likegetopt_long. Only a string starting with+or-,POSIXLY_CORRECT, or__posix_getoptkeep it in order. musl'sgetoptnever permutes, soprog file -vloses-v:argv corruption. In musl's
getopt_long, when the short option's argument is missing at the end of argv after a permuted operand (prog file -n),getoptleavesoptind = argc + 1. The permutation step (ext/musl/src/misc/getopt_long.c:47) then rotates argv's NULL terminator into the vector:argv[2] = NULL,argv[3] = "file". glibc stops atargcand keeps argv terminated.Diagnostics. glibc prints
invalid option -- 'Z',option requires an argument -- 'n',unrecognized option '--bogus=1',option '--ver' is ambiguous; possibilities: '--verbose' '--version',option '--verbose' doesn't allow an argument. musl printsunrecognized option: Z,option requires an argument: n, and so on. Tarantool's own test suite matches glibc's wording (app-luatest/args_test.lua,app-luatest/gh_8613_centralized_config_options_test.lua).__posix_getopt. musl exports a__posix_getoptof its own, so the name resolved straight to musl. That bypassed the shuttle: in a COPY-relocated executable the guest'soptindnever advanced, and a parse loop spun on the same argument.The fix
sh_getopt_run(lib/glibc_shim.cpp:1710) backsgetopt,__posix_getopt,getopt_longandgetopt_long_only. The order of work:optindatargcand rotates what musl consumed in front of the skipped operands, the order glibc's exchange leaves (sh_getopt_rotate,:1617).sh_getopt_complain,:1631).The element is classified exactly as musl's parser classified it.
__posix_getoptjoinsoverrideNames.Two glibc rules stay out of reach without replacing musl's parser:
getopt_long_onlyskips an unknown-xyzas a whole.Test
The conformance battery (
tst/glibc_shim_test.c,options()) checks:+and__posix_getoptkeeping order;optindafter a missing argument;All of these values were first checked against real glibc.
The guest executable calls
__posix_getoptthrough its own copy ofoptind. Needle:guest getopt q optind=2.On
main: 13 battery checks fail, and the guest printsguest getopt q optind=1. With the fix:./build testpasses. rootfs_smoke is skipped here because user namespaces are unavailable.This conflicts with #9 in
lib/glibc_shim.cppandtst/run_smoke.py, both near the getopt wrappers. The resolution keeps both sides. Once both are in,POSIXLY_CORRECTshould be read throughsh_getenv.