Skip to content

0.7.3 --- a started program's arguments and directory arrive as they were given - #22

Merged
Sunrisepeak merged 1 commit into
mainfrom
verbatim-prefix-not-given
Sep 13, 2026
Merged

0.7.3 --- a started program's arguments and directory arrive as they were given#22
Sunrisepeak merged 1 commit into
mainfrom
verbatim-prefix-not-given

Conversation

@Sunrisepeak

@Sunrisepeak Sunrisepeak commented Sep 13, 2026

Copy link
Copy Markdown
Member

A program started on Windows did not receive the arguments it was given, and the command interpreter could not be started at all.

Found through lsp-mcpp, whose Windows conformance run starts mcpp, which on windows-2022 went through the command interpreter, and got:

'\\?\C:\Users\runneradmin\AppData\Local\Temp\lsp-mcpp-conformance-mingw-…\mingw'
CMD.EXE was started with the above path as the current directory.
UNC paths are not supported.  Defaulting to Windows directory.
The syntax of the command is incorrect.

Three defects, each measured with a round-trip test (a program starts a copy of itself and prints the vector it received) under Wine:

1. Backslashes were dropped from the command line, and quoting overwrote unread input. append_quoted counted a run of backslashes and never wrote it, so C:\dir\file.txt arrived as C:dirfile.txt and a trailing backslash closed the quote early and merged the following elements. Separately, each element was converted in place just beyond the line, so any escape the quoting added overwrote characters it had not read yet.

given:  [plain][two words][][C:\dir\file.txt][trailing\][quote"inside][back\"quote][\\server\share][tab	here][--flag=a b]
before: [plain][two words][][C:dirfile.txt][trailing" quote//nside back///uote servershare tab][here --flag=a][b]

Now an element is converted into its own buffer and quoted by the rule CommandLineToArgvW inverts: backslashes before a quote are doubled and the quote escaped, backslashes before the closing quote are doubled, every other backslash is literal.

2. Every element was quoted. The splitting accepts that, but the command interpreter parses its own command line and reads "/c" as a command rather than its switch; a batch file, which runs through the interpreter, received a line it called incorrect. An element is now quoted only when the splitting would otherwise alter it (empty, or containing a space, tab, newline or quote).

3. Arguments were narrowed as names. prepare() in src/env.cpp stored each argument through okw::narrow, which rewrites \ as / because openkal spells a name's separator that way. An argument is not a name; clause 7.6 requires the vector unaltered.

after 1 and 2 only: [C:/dir/file.txt][trailing/][quote"inside][back/"quote][//server/share]…
after all three:    identical to what was given

4. The program and its directory were handed over in the \\?\ form. GetFinalPathNameByHandleW answers with the verbatim prefix; CreateProcessW accepts it, but a started program inherits it as its current directory and the command interpreter refuses that (above). The prefix is now removed wherever the name means the same without it: a drive path within the classic bound, or \\?\UNC\host\share as \\host\share. A longer name keeps the prefix, because without it the name would not be accepted at all. (Wine's interpreter tolerates the prefix, so this one is shown by the log above rather than by a local run.)

Environment values are unchanged: they are still narrowed with the name substitution, which the specification does not address; recorded here rather than changed.

With openkal-llvm-runtime → openkal-musl → this tree, lsp-mcpp's test_process for x86_64-windows-gnu passes all 11 cases under Wine, including arguments arrive unaltered and the command interpreter runs in the work directory (cmd.exe /d /c type marker.txt in a work directory). The objects still reference no C runtime symbol in the dev and release profiles.

Remaining, and a requirement rather than a defect: an argument carrying the interpreter's own metacharacters (& | < > ^ %) is passed to a batch file as the splitting rule says, which the interpreter then interprets. openkal does not define starting a script through its interpreter, so this is not addressed.

0.7.3.

…were given

The command line dropped every backslash: a run of them was counted and never
written, and an element was converted in place just beyond the line, so quoting
overwrote what it had not read. Every element was also quoted, which the command
interpreter reads as a command rather than a switch. Elements are now written as
they are unless the splitting would alter them, and quoted by the rule it
inverts otherwise. A started program read its arguments through the
name-narrowing that turns backslashes into slashes; arguments are now narrowed
as given (clause 7.6). And the program and its directory were handed over in
the \\?\ form, which the command interpreter refuses as a current directory;
the prefix is removed wherever the name means the same without it.
@Sunrisepeak
Sunrisepeak merged commit fc89f29 into main Sep 13, 2026
4 checks passed
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