Skip to content

execve() requires parent process to be cosmo program on windows #1253

@jcbhmr

Description

@jcbhmr

Contact Details

[email protected]

What happened?

When running a binary (ex. execvnode.exe) that uses execv() in the PowerShell terminal on Windows 10 it doesn't print anything. However, if I spawn the binary as a subprocess then suddenly the output does appear, but only after the main process has finished.

Here's an example main.c file:

#include <stdio.h>
#include <unistd.h>

int main(int argc, char *argv[]) {
    int err = execv("/C/Program Files/nodejs/node.exe", argv);
    if (err) {
        printf("error %d\n", err);
        return err;
    }
}
cosmocc -o execvnode.exe main.c

In theory this should act sorta like a symlink to run Node.js on Windows. I could open up PowerShell and run .\execvnode.exe --version and it would spit out the version, right?

It doesn't. It also exits with an error but with no output text.

image

If you run it via a cmd terminal instead you get a weird error message. Though I think that's the node.exe binary from the title of the alert box? But somehow it breaks in cmd

image

...but ONLY when its the top-level cmd. Using cmd in PowerShell window to start a cmd session inside the powershell graphical window successfully runs it but does a weird print-after-exit thing.

image

if you spawn it as a double subprocess it seems to print its own output after it has exited somehow.

image

Note that the "v20.11.0" is after the parent PowerShell process has already printed the next prompt line.

Example real-world scenario using ptime (a time similar-ish command for Windows https://community.chocolatey.org/packages/ptime)

image

Note that the "v20.11.0" is after the parent PowerShell process has already printed the next prompt line.

This is even more apparent when using --strace or other stdout logging vs the execv()-ed processes stdout which appears to print to the parent processes stdout (that's my best guess as to what's happening but I really have no idea)

image

👆 ptime .\execvnode.exe --strace --version
Note that the normal process output (from --strace) is all normal but the execv()-ed node.exe is after. idk.

This post-exit process printing thing also breaks stdio capturing.

image

Version

cosmocc (GCC) 14.1.0

What operating system are you seeing the problem on?

Windows

Relevant log output

i used screenshots since i think they convey the context and lack of output and position of text & cursor stuff a bit better than text does. let me know if i should include transcriptions and id be happy to

here's the --strace of ".\execvnode.exe --strace --version"

SYS   5076  11768          3'217'479 CreateFileMapping(-1, 0, kNtPageExecuteReadwrite, 65'536, NULL) → 268
SYS   5076  11768          6'476'456 MapViewOfFileEx(268, kNtFileMapWrite|kNtFileMapExecute, 0, 65'536, 0) → 0xf0000
SYS   5076  11768          6'670'288 VirtualProtect(0xf0000, 65'536, kNtPageReadwrite, [kNtPageExecuteReadwrite]) → true
SYS   5076  11768          6'870'788 CreateFileMapping(-1, 0, kNtPageExecuteReadwrite, 65'536, NULL) → 208
SYS   5076  11768          7'028'714 MapViewOfFileEx(208, kNtFileMapWrite|kNtFileMapExecute, 0, 65'536, 0x6fe000000) → 0x6fe000000
SYS   5076  11768          7'179'510 VirtualProtect(0x6fe000000, 65'536, kNtPageReadwrite, [kNtPageExecuteReadwrite]) → true
SYS   5076  11768          7'316'001 mmap(0x6fe000000, 65'536, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED, -1, 0) → 0x6fe000000 (8'769'536 bytes total)
SYS   5076  11768          7'722'341 getenv("_COSMO_FDS_V2") → NULL
SYS   5076  11768          7'834'480 getenv("COSMOPOLITAN_DISABLE_ZIPOS") → NULL
SYS   5076  11768          7'989'145 issetugid() → 0
SYS   5076  11768          8'690'313 getenv("COSMOPOLITAN_INIT_ZIPOS") → NULL
SYS   5076  11768          9'280'138 GetProgramExecutableName() → "/C/Users/jcbhm/Downloads/execvnode.exe"
SYS   5076  11768          9'954'953 GetFileAttributes(u"C:\\Users\\jcbhm\\Downloads\\execvnode.exe") → kNtFileAttributeArchive
SYS   5076  11768         10'489'241 CreateFile(u"C:\\Users\\jcbhm\\Downloads\\execvnode.exe", kNtFileGenericRead|kNtGenericExecute|kNtFileWriteEa|kNtFileWriteAttributes, kNtFileShareRead|kNtFileShareWrite|kNtFileShareDelete, 4405168, kNtOpenExisting, kNtFileAttributeNotContentIndexed|kNtFileFlagOverlapped, 0) → {276, 0}
SYS   5076  11768         11'127'161 CreateFileMapping(-1, 0, kNtPageExecuteReadwrite, 16, NULL) → 212
SYS   5076  11768         11'651'556 MapViewOfFileEx(212, kNtFileMapWrite|kNtFileMapExecute, 0, 16, 0xf4cb1640000) → 0xf4cb1640000
SYS   5076  11768         12'244'086 VirtualProtect(0xf4cb1640000, 16, kNtPageReadwrite, [kNtPageExecuteReadwrite]) → true
SYS   5076  11768         12'846'441 mmap(0, 16, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) → 0xf4cb1640000 (8'773'632 bytes total)
SYS   5076  11768         13'488'273 CreateFileMapping(-1, 4405168, kNtPageExecuteReadwrite, 24, NULL) → 280
SYS   5076  11768         14'104'046 MapViewOfFileEx(280, kNtFileMapWrite|kNtFileMapExecute, 0, 24, 0xf4cb1650000) → 0xf4cb1650000
SYS   5076  11768         14'776'391 VirtualProtect(0xf4cb1650000, 24, kNtPageReadwrite, [kNtPageExecuteReadwrite]) → true
SYS   5076  11768         15'484'057 mmap(0, 24, PROT_READ|PROT_WRITE, MAP_ANONYMOUS|MAP_SHARED, -1, 0) → 0xf4cb1650000 (8'777'728 bytes total)
SYS   5076  11768         16'073'718 openat(AT_FDCWD, "/C/Users/jcbhm/Downloads/execvnode.exe", O_RDONLY) → 3
SYS   5076  11768         16'869'421 fstat(3, [{.st_size=538'644, .st_blocks=540'672/512, .st_mode=0100700, .st_uid=27294, .st_gid=27294, .st_dev=0xb0e7e721, .st_ino=0x2dd0000000042dc, .st_flags=20}]) → 0
SYS   5076  11768         17'364'659 CreateFileMapping(276, 4405168, kNtPageExecuteRead, 538'644, NULL) → 284
SYS   5076  11768         17'888'151 MapViewOfFileEx(284, kNtFileMapRead|kNtFileMapExecute, 0, 538'644, 0xf4cb1660000) → 0xf4cb1660000
SYS   5076  11768         18'659'957 VirtualProtect(0xf4cb1660000, 538'644, kNtPageReadonly, [kNtPageExecuteRead]) → true
SYS   5076  11768         22'876'578 mmap(0, 538'644, PROT_READ, MAP_SHARED, 3, 0) → 0xf4cb1660000 (9'318'400 bytes total)
SYS   5076  11768         23'512'477 CreateFileMapping(-1, 0, kNtPageExecuteReadwrite, 24, NULL) → 288
SYS   5076  11768         24'071'454 MapViewOfFileEx(288, kNtFileMapWrite|kNtFileMapExecute, 0, 24, 0xad231b70000) → 0xad231b70000
SYS   5076  11768         24'651'348 VirtualProtect(0xad231b70000, 24, kNtPageReadwrite, [kNtPageExecuteReadwrite]) → true
SYS   5076  11768         25'239'632 mmap(0, 24, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) → 0xad231b70000 (9'322'496 bytes total)
SYS   5076  11768         25'995'063 UnmapViewOfFile(0xf4cb1650000) → true
SYS   5076  11768         26'437'840 munmap(0xf4cb1650000, 24) → 0 (9'318'400 bytes total)
SYS   5076  11768         27'169'289 UnmapViewOfFile(0xf4cb1640000) → true
SYS   5076  11768         27'767'218 munmap(0xf4cb1640000, 16) → 0 (9'314'304 bytes total)
SYS   5076  11768         28'353'836 close(3) → 0
SYS   5076  11768         28'846'056 __zipos_get("/C/Users/jcbhm/Downloads/execvnode.exe") → 0
SYS   5076  11768         29'380'741 CreateFileMapping(-1, 0, kNtPageExecuteReadwrite, 49'152, NULL) → 276
SYS   5076  11768         29'911'631 MapViewOfFileEx(276, kNtFileMapWrite|kNtFileMapExecute, 0, 49'152, 0xad231b80000) → 0xad231b80000
SYS   5076  11768         30'671'975 VirtualProtect(0xad231b80000, 49'152, kNtPageReadwrite, [kNtPageExecuteReadwrite]) → true
SYS   5076  11768         31'293'657 mmap(0, 49'152, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) → 0xad231b80000 (9'363'456 bytes total)
SYS   5076  11768         32'515'541 inflate([u"SYMT☺   ╛♦       └       └        @     "...], 49'152, u"φ£y|T╒┘°☼A♣½ò *╘♪\\┴♪┬&╕T◘╔ä♦ÆL╠$$╪Ωd2s3↓"..., 17'485) → 0
SYS   5076  11768         32'714'841 GetSymbolTableFromZip() → 0xad231b80000
SYS   5076  11768         33'455'062 getenv("HOME") → "/C/Users/jcbhm"
SYS   5076  11768         33'876'088 getenv("TMPDIR") → NULL
SYS   5076  11768         34'559'707 getenv("TERM") → "xterm-256color"
SYS   5076  11768         35'246'759 CreateFileMapping(-1, 0, kNtPageExecuteReadwrite, 65'536, NULL) → 280
SYS   5076  11768         38'552'245 MapViewOfFileEx(280, kNtFileMapWrite|kNtFileMapExecute, 0, 65'536, 0xad231b90000) → 0xad231b90000
SYS   5076  11768         39'168'855 VirtualProtect(0xad231b90000, 65'536, kNtPageReadwrite, [kNtPageExecuteReadwrite]) → true
SYS   5076  11768         39'725'555 mmap(0, 65'536, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0) → 0xad231b90000 (9'428'992 bytes total)
SYS   5076  11768         40'314'757 execve("/C/Program Files/nodejs/node.exe", {"/C/Users/jcbhm/Downloads/execvnode.exe", "--version", NULL}, {"=::=::\\", "ALLUSERSPROFILE=/C/ProgramData", "APPDATA=/C/Users/jcbhm/AppData/Roaming", "CHOCOLATEYINSTALL=/C/ProgramData/chocolatey", "CHOCOLATEYLASTPATHUPDATE=133515754319390407", "COMMONPROGRAMFILES=/C/Program Files/Common Files", "COMMONPROGRAMFILES(X86)=/C/Program Files (x86)/Common Files", .)
SYS   5076  11768         41'026'370 OpenProcess(kNtProcessCreateProcess|kNtProcessDupHandle, false, 12400) → 212
SYS   5076  11768         41'744'158 CreateFile(!!2d4c20, kNtFileGenericRead, kNtFileShareRead|kNtFileShareWrite|kNtFileShareDelete, 0, kNtOpenExisting, kNtFileAttributeNormal|kNtFileFlagBackupSemantics, 0) → {292, 0}
SYS   5076  11768         43'844'628 CreateProcess(u"C:\\Program Files\\nodejs\\node.exe", u"C:\\Users\\jcbhm\\Downloads\\execvnode.exe --version", 0, 0, true, 590880, 0x2e541e, NULL, 0x7000007de8f0, 0x7000007dea78) → true

Metadata

Metadata

Assignees

No one assigned

    Labels

    acceptedWe intend to address this issue.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions