Windows: cosmocc cc1 blocks indefinitely (~0% CPU) on large C translation units, intermittently, at -O0
Summary
Compiling a large C translation unit with cosmocc on Windows intermittently hangs. cc1 stops making progress and sits at ~0% CPU indefinitely while holding its temporary .s output open. It is not an ICE, not an error, and not a slow compile - the process simply blocks and never returns.
Measured rate on GitHub Actions windows-latest: ~12% per compile of a large TU, at -O0, on both x86_64-linux-cosmo and aarch64-linux-cosmo. It did not reproduce on a Windows 11 desktop in 40 compiles, so the rate is environment-dependent - see below; that contrast is probably the most useful thing in this report.
This is distinct from #1488 (cosmoc++ / std::sort), which is deterministic, C++-only, and does not occur at -O0. This one is intermittent, plain C, and happens at -O0.
Cheap reproducer (no third-party tree needed)
Two downloads and a loop. The SQLite amalgamation is a convenient large TU because it is one self-contained file; QuickJS's quickjs.c hangs identically, so nothing here is SQLite-specific.
# 1. toolchain
curl -fsSLO https://cosmo.zip/pub/cosmocc/cosmocc-4.0.2.zip
mkdir -p cosmo && unzip -q cosmocc-4.0.2.zip -d cosmo
export PATH="$PWD/cosmo/bin:$PATH"
# 2. a large C translation unit (8.6 MB, ~239k lines)
curl -fsSLO https://sqlite.org/2024/sqlite-amalgamation-3450100.zip
unzip -q sqlite-amalgamation-3450100.zip
cd sqlite-amalgamation-3450100
# 3. compile it in a loop. A healthy compile takes ~5s; anything past ~90s is wedged.
for i in $(seq 1 40); do
start=$(date +%s)
timeout -k 5 90 cosmocc -std=c11 -O0 -w -c -o /tmp/out.o sqlite3.c >/dev/null 2>&1
rc=$?
echo "iter $i rc=$rc elapsed=$(( $(date +%s) - start ))s"
[ "$rc" = 124 ] && echo " ^^ WEDGED"
doneRun under an MSYS2 shell on Windows. On the affected host this wedges roughly once per eight compiles - 24 iterations give ~95% confidence of catching at least one - and rc=124 is the timeout firing on a cc1 that never returned. Note the caveat below: this does not fire everywhere.
To see that it is blocked rather than spinning, sample the stuck process twice while it hangs - only the Win32 process table exposes a native process's cumulative CPU:
foreach ($i in 1..2) {
Get-Process cc1 -ErrorAction SilentlyContinue |
Select-Object Id, @{n='cpu';e={$_.CPU}}, @{n='rssMB';e={[math]::Round($_.WorkingSet64/1MB,1)}}
Start-Sleep 5
}Evidence
A watchdog firing after 120s of silence, sampling every build process twice 5 seconds apart:
WEDGED after 120s of silence
pid=5744 ppid=7140 cc1 cpu=3.42s dcpu=0.01s rss=219.4MB
cmd: ...\libexec\gcc\aarch64-linux-cosmo\14.1.0\cc1 -quiet -nostdinc
-I vendor/sqlite -imultiarch aarch64-linux-cosmo ...
vendor/sqlite/sqlite3.c -quiet -dumpdir build/.aarch64/
-dumpbase sqlite3.c ... -O0 -std=c11 -fportcosmo ...
-o D:\a\_temp\msys64\tmp\ccfs5cmy.s
pid=7140 ppid=5396 aarch64-linux-cosmo-gcc cpu=0.09s dcpu=0s
pid=8512 ppid=500 make.exe cpu=0.66s dcpu=0.04sdcpu=0.01s over a 5-second window is the key measurement: cc1 is blocked, not spinning. It accumulates 3-7s of CPU, then stops, consistently at roughly the same point, holding its temp .s open.
Rate measurement
250 solo compiles of sqlite3.c across 10 parallel jobs, each looping until it wedged:
first wedge at iteration: 1, 1, 2, 2, 3, 8, 11, 13, 19, 23
mean 8.3 iterationsA geometric distribution with p = 0.12 has mean 1/p = 8.3, matching a constant ~12% per-compile probability. At whole-build level (one sqlite3.c plus one quickjs.c, -j2) that surfaces as ~30% of builds hanging: 6/20 observed.
The rate is environment-dependent (and this narrows it)
The same reproducer, same cosmocc 4.0.2, same -O0, same MSYS2 shell, run on a Windows 11 Pro 26200 desktop: 0 wedges in 40 consecutive compiles, every one finishing in 4-5s.
That is not merely "did not reproduce" - it is statistically incompatible with the CI rate. If p were 0.12, the chance of 40 clean compiles is 0.88^40 = 0.6%. Zero events in 40 puts a 95% upper bound of 3/40 = 7.5% on the rate for this host, and the observation sits far below the CI figure.
So whatever the trigger is, it is not simply "cosmocc compiling a large TU on Windows". Something about the GitHub Actions Windows image differs: candidates worth checking are its ephemeral D:\ work volume, Defender / real-time scanning on the temp path cc1 writes its .s into, or that image's particular MSYS2 installation. The temp-directory arm below relocated TMPDIR/TMP/TEMP within that image and did not clear it, which does not rule out the volume or the scanner.
If it would help, I can run any arm on either host - the desktop gives a clean control, which the CI-only data did not have.
What has been ruled out
Each tested rather than reasoned about, both arms in a single dispatch on the same image:
| Hypothesis | Test | Result |
|---|---|---|
| Optimizer / codegen blow-up | CPU delta while wedged | No. dcpu ~ 0; a blow-up would burn CPU. |
| MSYS2 temp directory | 10 runs with TMPDIR/TMP/TEMP relocated off the MSYS2 tree vs 10 without |
No. 2/10 vs 4/10, Fisher exact two-tailed p=0.63. |
| Parallel-make contention | 10 full builds at -j1 |
No. Still 2/10. |
| Needs a big build around it | 250 compiles of sqlite3.c alone, nothing else running |
No. 10/10 jobs wedged. |
| One bad source file | which TU each wedge hit | No. sqlite3.c and quickjs.c both. |
| Architecture-specific | arch of the stuck cc1 |
No. Both x86_64-linux-cosmo and aarch64-linux-cosmo. |
| Optimization-dependent | -O0 throughout |
No. All of the above is at -O0. |
Environment
| cosmocc | 4.0.2 (cosmocc-4.0.2.zip, SHA-256 85b8c37a406d862e656ad4ec14be9f6ce474c1b436b9615e91a55208aced3f44), GCC 14.1.0 |
| Host where it reproduces | GitHub Actions windows-latest (Windows Server 2025, image windows-2025-vs2026) |
| Host where it did NOT | Windows 11 Pro 26200 desktop - see "the rate is environment-dependent" below |
| Shell | MSYS2 (msystem: MSYS), GNU Make 4.4.1 |
| Optimization | -O0 |
What would help
Anything narrowing where cc1 blocks would beat more sampling from outside:
- whether the temporary
.soutput path is implicated - the block is observed whilecc1holds it open; - whether this is known behaviour of the Windows port of the GCC cosmocc 4.0.2 ships, or specific to the cosmo build of it (the stuck command line carries
-fportcosmo, and #1488's investigation also landed near the portcosmo patch, though that hang is CPU-burning and deterministic while this one is blocked and intermittent); - whether a newer cosmocc changes the rate.
Happy to run further arms on request - the sampling method above is short enough that any additional arm can be stood up and answered quickly.
Workaround currently in use
Retrying the build on a stall. make resumes from the objects already completed, so a retry costs a fraction of a build and three attempts leave roughly 3% residual failure. A mitigation, not a fix - it is why a source build of our project on Windows runs nightly rather than on the PR path.
Source: jart/cosmopolitan