authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-03-04 10:52:54+00:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-03-10 10:26:15+00:00
loga5219cd288c322f5f5bda89d608af5b243e9fd6f
treeccb3c205da6f25dde27b12f679c98d98ea480edb
parentc73db56b4543776ce157626361f1cb66df1dac69
signaturelock-open Commit is signed but in an unrecognized format.

bootstrap: work around GCC bug

GCC bug 119085, which affects versions 13.0--15.1, is being triggered by the C backend, resulting in a (small but critical) miscompilation in zig2. Unfortunately, we can't really work around that bug without a command-line flag, because the bug is sensitive to things like the order in which `struct` types are defined. Therefore, I have added an option to `bootstrap.c` which causes it to pass the appropriate flag to `gcc` to disable the optimization pass in question. This flag can likely be removed in future, once the affected GCC versions become less common. At least one of our x86_64-linux CI machines is using an affected GCC version, so I also updated the relevant CI script to pass this flag when testing no-LLVM bootstrap. CMakeLists also has a workaround, but no user intervention is required there: the GCC version range is automatically detected by CMakeLists.

3 files changed, 33 insertions(+), 3 deletions(-)

CMakeLists.txt+10-2
......@@ -330,7 +330,6 @@ set(ZIG_STAGE2_SOURCES
330330 src/Air/Liveness.zig
331331 src/Air/Liveness/Verify.zig
332332 src/Air/print.zig
333 src/Air/types_resolved.zig
334333 src/Builtin.zig
335334 src/Compilation.zig
336335 src/Compilation/Config.zig
......@@ -344,6 +343,7 @@ set(ZIG_STAGE2_SOURCES
344343 src/Sema.zig
345344 src/Sema/bitcast.zig
346345 src/Sema/comptime_ptr_access.zig
346 src/Sema/type_resolution.zig
347347 src/Type.zig
348348 src/Value.zig
349349 src/Zcu.zig
......@@ -360,7 +360,8 @@ set(ZIG_STAGE2_SOURCES
360360 src/codegen/aarch64/Mir.zig
361361 src/codegen/aarch64/Select.zig
362362 src/codegen/c.zig
363 src/codegen/c/Type.zig
363 src/codegen/c/type.zig
364 src/codegen/c/type/render_defs.zig
364365 src/codegen/llvm.zig
365366 src/codegen/llvm/bindings.zig
366367 src/crash_report.zig
......@@ -375,6 +376,7 @@ set(ZIG_STAGE2_SOURCES
375376 src/libs/libunwind.zig
376377 src/link.zig
377378 src/link/C.zig
379 src/link/ConstPool.zig
378380 src/link/Coff.zig
379381 src/link/Dwarf.zig
380382 src/link/Elf.zig
......@@ -623,6 +625,12 @@ else()
623625 else()
624626 set(ZIG2_LINK_FLAGS "-Wl,-z,stack-size=0x10000000")
625627 endif()
628 # Prevent GCC from miscompiling 'zig2.c'. See also 'workaround_gcc_sra_miscomp' in 'bootstrap.c'.
629 if (CMAKE_C_COMPILER_ID STREQUAL "GNU" AND
630 CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL "13.0" AND
631 CMAKE_C_COMPILER_VERSION VERSION_LESS_EQUAL "15.2")
632 set(ZIG2_COMPILE_FLAGS "${ZIG2_COMPILE_FLAGS} -fno-tree-sra")
633 endif()
626634endif()
627635
628636set(ZIG1_WASM_MODULE "${PROJECT_SOURCE_DIR}/stage1/zig1.wasm")
bootstrap.c+21
......@@ -102,6 +102,26 @@ int main(int argc, char **argv) {
102102 const char *cc = get_c_compiler();
103103 const char *host_triple = get_host_triple();
104104
105 // GCC versions 13.0--14.1 have a miscompilation where some bytes of a union may get clobbered
106 // depending on the union layout and the order in which types are defined. This miscompilation
107 // affects the output of the C backend, and thus can affect the bootstrap process. Specifically,
108 // we observe that using the self-hosted x86_64 backend in 'zig2' will cause all function calls
109 // to be relocated incorrectly, causing immediate crashes on any binary produced by it.
110 //
111 // The only reliable workaround for this bug is to disable the optimization pass containing it,
112 // so here we check for a CLI flag requesting that workaround.
113 //
114 // The upstream bug is fixed in GCC version 15.2 onwards (and was also backported to the 13 and
115 // 14 branches). Once this bug is no longer widespread, we can remove this CLI flag.
116 //
117 // Upstream bug report: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=119085
118 bool workaround_gcc_sra_miscomp = false;
119 for (int i = 1; i < argc; ++i) {
120 if (!strcmp(argv[i], "--workaround-gcc-sra-miscomp")) {
121 workaround_gcc_sra_miscomp = true;
122 }
123 }
124
105125 {
106126 const char *child_argv[] = {
107127 cc, "-o", "zig-wasm2c", "stage1/wasm2c.c", "-O2", "-std=c99", NULL,
......@@ -193,6 +213,7 @@ int main(int argc, char **argv) {
193213#if defined(__GNUC__)
194214 "-pthread",
195215#endif
216 workaround_gcc_sra_miscomp ? "-fno-tree-sra" : NULL,
196217 NULL,
197218 };
198219 print_and_run(child_argv);
ci/x86_64-linux-release.sh+2-1
......@@ -21,7 +21,8 @@ export ZIG_LOCAL_CACHE_DIR="$PWD/zig-local-cache"
2121
2222# Test building from source without LLVM.
2323cc -o bootstrap bootstrap.c
24./bootstrap
24# See comments in bootstrap.c for an explanation of the flag given here.
25./bootstrap --workaround-gcc-sra-miscomp
2526./zig2 build -Dno-lib
2627./zig-out/bin/zig test test/behavior.zig
2728