ncc exits 0 when a constexpr helper compile fails (silent miscompile in cross-compile flows)
- Dominant language
- C
- Stars
- 0
- Forks
- 0
- Avg merge
- 5d 4h
- Merged PRs (30d)
- 1
Description
## Summary
When a `constexpr_eval`/`constexpr_min`/`constexpr_max`/`constexpr_strlen`/etc. helper subprocess fails to compile, `ncc` emits a diagnostic but exits with status `0` and produces no output binary. Build systems treat this as success.
## Reproducer
On macOS arm64 with `llvm-mingw` available for cross-builds, using the README's documented validation flow from PR #1:
\`\`\`
\$ build-host/ncc --target=x86_64-w64-windows-gnu \\
-o /tmp/ncc-win-constexpr.exe test/test_constexpr.c
ncc: 25:18: constexpr: helper compile failed with exit status 1:
/var/folders/.../ncc_ce_XXXXXX/src.c:1:10: fatal error: 'stdio.h' file not found
1 | #include
| ^~~~~~~~~
1 error generated.
\$ echo \$?
0
\$ ls /tmp/ncc-win-constexpr.exe
ls: /tmp/ncc-win-constexpr.exe: No such file or directory
\`\`\`
The exit status from ncc is \`0\`, no \`.exe\` was written, and \`make\`/\`ninja\`/CI wrappers will not notice.
## Why this matters
Two distinct problems compound here:
1. **Helper subprocess sysroot is not propagated for cross-targets.** When the host ncc runs with \`--target=x86_64-w64-windows-gnu\`, the spawned helper compile inherits the \`--target\` flag but not the include path, library path, or any flags set by the surrounding compiler config (\`x86_64-w64-windows-gnu.cfg\` from llvm-mingw, \`-isysroot\`, \`--sysroot=\`, \`-I\`, etc.). The user has no obvious way to ensure helpers find their headers. This is the proximate cause of the reproducer above.
2. **Helper-compile-failure path returns success.** Even setting (1) aside, a *failed* constexpr helper should fail the parent compile. Today \`xform_constexpr.c\` prints \`helper compile failed with exit status N\` and continues (looks like it falls through to the substitution path with whatever default value, then never re-checks status before emitting). The compile finishes, but no output is produced — ncc still exits 0.
(2) is the more dangerous one: any future scenario where a helper genuinely fails — bad headers, missing dependency, clang ICE — will silently produce no binary while the build reports green.
## Suggested fix
- In \`xform_constexpr.c\`, treat any non-zero helper exit as fatal: emit a diagnostic and exit non-zero from the top-level driver. (Or set an error flag observed by \`ncc.c\`'s exit path.)
- For (1): forward the parent's \`-I\`, \`-isysroot\`, \`--sysroot\`, and any \`-L\` / library search flags into the helper invocation. Possibly also forward the parent's full argv subset that survives into clang, modulo \`-c\`/\`-o\` which the helper sets itself.
Both should land before the Windows port (#1) merges, since the README's own validation step documents the failing command but the user has no way to notice today that it's not actually working.
## Environment
- Host: macOS 25.3.0 arm64, Homebrew clang 21.1.8 as build-host CC
- Cross toolchain: llvm-mingw 20260421 (clang 22.1.4 + lld) targeting \`x86_64-w64-windows-gnu\`
- Repo: \`crashappsec/ncc\` at \`baron/windows@6455dbfa9a80\`
Contributor guide
No contributing guide indexed for this repository
Assessment
This issue has not been assessed yet.