From 7a8a5deca98f4a16f9fed2917d07b5a492cc0ad7 Mon Sep 17 00:00:00 2001 From: Richard Wheeler <18647491+PythonWillRule@users.noreply.github.com> Date: Sat, 25 Jul 2026 07:54:16 -0400 Subject: [PATCH 01/23] ci: adopt shared tccbin conformance test suite Wires this branch into the shared cross-platform conformance suite (thirdparty/tccbin_tests in vlang/v) via a real FreeBSD VM (cross-platform-actions/action, same tooling vlang/v's own update_tccbin.yml uses to rebuild this branch). No rebuild here - validates the already-committed tcc.exe/lib/libgc.a as-is. Unverified locally (no FreeBSD access here) - V's own builder also references -lgc-threaded for this platform+tcc combo (vlib/builtin/builtin_d_gcboehm.c.v), which isn't in this branch's bundle; starting without it since the bundled libgc.a should be self-sufficient, and will adjust based on real CI results if not. --- .github/workflows/build-and-test.yml | 57 ++++++++++++++++++++++++++++ 1 file changed, 57 insertions(+) create mode 100644 .github/workflows/build-and-test.yml diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml new file mode 100644 index 0000000..4884024 --- /dev/null +++ b/.github/workflows/build-and-test.yml @@ -0,0 +1,57 @@ +name: build and test (freebsd-amd64) + +on: + push: + branches: [thirdparty-freebsd-amd64] + pull_request: + branches: [thirdparty-freebsd-amd64] + workflow_dispatch: {} + +jobs: + build: + runs-on: ubuntu-latest + steps: + # cross-platform-actions/action boots a real FreeBSD VM inside this + # Linux runner - the same action vlang/v's own update_tccbin.yml + # uses to rebuild this branch's binaries. Cloning both repos + # directly inside the VM (rather than actions/checkout on the + # runner + sync_files) mirrors that proven-working pattern instead + # of relying on an unverified file-permission-preserving sync. + - name: Start freebsd-amd64 VM + uses: cross-platform-actions/action@v1.3.0 + with: + operating_system: freebsd + version: '15.1' + memory: 4G + shell: sh + sync_files: runner-to-vm + + - name: run shared conformance tests + shell: cpa.sh {0} + run: | + set -eu + sudo pkg install -y bash git + + git clone --branch thirdparty-freebsd-amd64 --depth=1 \ + https://github.com/vlang/tccbin.git thirdparty/tcc + + # thirdparty/libgc/include (gc.h) and thirdparty/tccbin_tests + # (the shared cross-platform conformance suite) both live in + # the main v repo, not here. + git clone --filter=blob:none --no-checkout --depth=1 \ + https://github.com/vlang/v.git vsrc + git -C vsrc sparse-checkout set --no-cone thirdparty/libgc thirdparty/tccbin_tests + git -C vsrc checkout c82d3f08271e9324d6fb8de3c251e9c0e1a9154b + + chmod +x thirdparty/tcc/tcc.exe + + # The bundled tcc.exe resolves its own crt/libtcc1.a via a path + # relative to the process's working directory (confirmed on + # linux-amd64/macos-arm64's CI) - thirdparty/tcc/tcc.exe is + # already correctly placed relative to $PWD here since we just + # cloned it there directly. + bash vsrc/thirdparty/tccbin_tests/run.sh "$PWD/thirdparty/tcc/tcc.exe" freebsd -- \ + -DGC_BUILTIN_ATOMIC=1 -DBUS_PAGE_FAULT=T_PAGEFLT -DALL_INTERIOR_POINTERS=1 \ + -I "$PWD/vsrc/thirdparty/libgc/include" \ + "$PWD/thirdparty/tcc/lib/libgc.a" \ + -lpthread From 4fd6d3a116f4e2f5cc1fbc22c68899bd8819ce56 Mon Sep 17 00:00:00 2001 From: Richard Wheeler <18647491+PythonWillRule@users.noreply.github.com> Date: Sat, 25 Jul 2026 07:57:30 -0400 Subject: [PATCH 02/23] ci: add temporary diagnostic step to surface the compile error --- .github/workflows/build-and-test.yml | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 4884024..94e82e5 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -45,6 +45,16 @@ jobs: chmod +x thirdparty/tcc/tcc.exe + # TEMPORARY diagnostic: run.sh swallows compile stderr, so on + # first failure here we can't see *why* linking failed. Show + # it directly before running the real suite. + thirdparty/tcc/tcc.exe vsrc/thirdparty/tccbin_tests/shared/hello.c \ + -DGC_BUILTIN_ATOMIC=1 -DBUS_PAGE_FAULT=T_PAGEFLT -DALL_INTERIOR_POINTERS=1 \ + -I "$PWD/vsrc/thirdparty/libgc/include" \ + "$PWD/thirdparty/tcc/lib/libgc.a" \ + -lpthread \ + -o /tmp/hello_diag || true + # The bundled tcc.exe resolves its own crt/libtcc1.a via a path # relative to the process's working directory (confirmed on # linux-amd64/macos-arm64's CI) - thirdparty/tcc/tcc.exe is From 9cd7ceca13ee3fc745c0eddb12254a6844638e10 Mon Sep 17 00:00:00 2001 From: Richard Wheeler <18647491+PythonWillRule@users.noreply.github.com> Date: Sat, 25 Jul 2026 09:09:13 -0400 Subject: [PATCH 03/23] ci: add temporary job to verify candidate tinycc etext/end fix --- .github/workflows/build-and-test.yml | 78 ++++++++++++++++++++++++++++ 1 file changed, 78 insertions(+) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 94e82e5..30338a8 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -65,3 +65,81 @@ jobs: -I "$PWD/vsrc/thirdparty/libgc/include" \ "$PWD/thirdparty/tcc/lib/libgc.a" \ -lpthread + + # TEMPORARY: verifies a candidate tinycc fix for the 'undefined symbol + # etext/end' failure above, before submitting it upstream. Builds a + # patched tcc from vanilla tinycc source (there's no GitHub mirror to + # push a real branch to - tinycc's canonical repo is repo.or.cz, using + # email patch submission, not PRs) and tests it against this branch's + # already-committed libgc.a. Remove this job once the fix is confirmed + # and submitted - it's not part of the branch's real CI. + verify-etext-fix: + runs-on: ubuntu-latest + steps: + - name: Start freebsd-amd64 VM + uses: cross-platform-actions/action@v1.3.0 + with: + operating_system: freebsd + version: '15.1' + memory: 4G + shell: sh + sync_files: runner-to-vm + + - name: build patched tcc and test against bundled libgc.a + shell: cpa.sh {0} + run: | + set -eu + sudo pkg install -y bash git gmake + + cat > etext_fix.patch <<'PATCHEOF' + diff --git a/tccelf.c b/tccelf.c + index 7e9758af..f9ae676c 100644 + --- a/tccelf.c + +++ b/tccelf.c + @@ -1890,6 +1890,19 @@ static void tcc_add_linker_symbols(TCCState *s1) + #if TARGETOS_OpenBSD + set_global_sym(s1, "__executable_start", NULL, ELF_START_ADDR); + #endif + +#if TARGETOS_BSD + + /* Traditional BSD systems provide the plain (non-underscore) names + + as the primary linker-provided segment-boundary symbols, unlike + + glibc/Linux where they're only weak aliases of _etext/_edata/_end + + supplied by the C library's own crt objects - so code that + + references the plain names directly (e.g. BDWGC's FreeBSD + + data-segment-scanning code looks up `etext`/`end` to find its + + conservative-GC root region) links fine under a BSD system's + + native linker but fails here with "undefined symbol" errors. */ + + set_global_sym(s1, "etext", text_section, -1); + + set_global_sym(s1, "edata", data_section, -1); + + set_global_sym(s1, "end", bss_section, -1); + +#endif + #ifdef TCC_TARGET_RISCV64 + /* XXX should be .sdata+0x800, not .data+0x800 */ + set_global_sym(s1, "__global_pointer$", data_section, 0x800); + PATCHEOF + + git clone --quiet https://repo.or.cz/tinycc.git tinycc-src + git -C tinycc-src apply --verbose ../etext_fix.patch + + cd tinycc-src + ./configure --prefix=/tmp/tcc-patched + gmake -j"$(sysctl -n hw.ncpu)" + ./tcc --version + cd .. + + git clone --branch thirdparty-freebsd-amd64 --depth=1 \ + https://github.com/vlang/tccbin.git thirdparty/tcc + git clone --filter=blob:none --no-checkout --depth=1 \ + https://github.com/vlang/v.git vsrc + git -C vsrc sparse-checkout set --no-cone thirdparty/libgc thirdparty/tccbin_tests + git -C vsrc checkout c82d3f08271e9324d6fb8de3c251e9c0e1a9154b + + echo "=== testing PATCHED tcc against bundled libgc.a ===" + tinycc-src/tcc vsrc/thirdparty/tccbin_tests/shared/hello.c \ + -DGC_BUILTIN_ATOMIC=1 -DBUS_PAGE_FAULT=T_PAGEFLT -DALL_INTERIOR_POINTERS=1 \ + -I "$PWD/vsrc/thirdparty/libgc/include" \ + -I "$PWD/thirdparty/tcc/include" \ + "$PWD/thirdparty/tcc/lib/libgc.a" \ + -lpthread \ + -o /tmp/hello_patched + /tmp/hello_patched From 37059aca25b3ad43547743e89273ddec7bdf17e0 Mon Sep 17 00:00:00 2001 From: Richard Wheeler <18647491+PythonWillRule@users.noreply.github.com> Date: Sat, 25 Jul 2026 09:11:42 -0400 Subject: [PATCH 04/23] ci: retry (repo.or.cz connection reset on prior attempt) From d689605f5c0aa60a9dd1026e0d8979069ef8d888 Mon Sep 17 00:00:00 2001 From: Richard Wheeler <18647491+PythonWillRule@users.noreply.github.com> Date: Sat, 25 Jul 2026 09:15:29 -0400 Subject: [PATCH 05/23] ci: clone+patch tinycc on the runner, not inside the VM (repo.or.cz connection reset there twice) --- .github/workflows/build-and-test.yml | 37 +++++++++++++++++----------- 1 file changed, 23 insertions(+), 14 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 30338a8..3bddde4 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -76,21 +76,15 @@ jobs: verify-etext-fix: runs-on: ubuntu-latest steps: - - name: Start freebsd-amd64 VM - uses: cross-platform-actions/action@v1.3.0 - with: - operating_system: freebsd - version: '15.1' - memory: 4G - shell: sh - sync_files: runner-to-vm - - - name: build patched tcc and test against bundled libgc.a - shell: cpa.sh {0} + # repo.or.cz (tinycc's canonical host - no GitHub mirror exists) + # resets connections from inside the FreeBSD VM every time + # (reproduced twice) - cloning + patching here on the runner instead + # avoids that network path entirely; sync_files: runner-to-vm below + # carries the already-patched source into the VM via rsync (which + # preserves permissions) before each cpa.sh step runs. + - name: clone and patch tinycc on the runner run: | set -eu - sudo pkg install -y bash git gmake - cat > etext_fix.patch <<'PATCHEOF' diff --git a/tccelf.c b/tccelf.c index 7e9758af..f9ae676c 100644 @@ -119,7 +113,22 @@ jobs: PATCHEOF git clone --quiet https://repo.or.cz/tinycc.git tinycc-src - git -C tinycc-src apply --verbose ../etext_fix.patch + git -C tinycc-src apply --verbose etext_fix.patch + + - name: Start freebsd-amd64 VM + uses: cross-platform-actions/action@v1.3.0 + with: + operating_system: freebsd + version: '15.1' + memory: 4G + shell: sh + sync_files: runner-to-vm + + - name: build patched tcc and test against bundled libgc.a + shell: cpa.sh {0} + run: | + set -eu + sudo pkg install -y bash git gmake cd tinycc-src ./configure --prefix=/tmp/tcc-patched From f8d776a7ffeba4aa05ecbc76c5386316dd429e44 Mon Sep 17 00:00:00 2001 From: Richard Wheeler <18647491+PythonWillRule@users.noreply.github.com> Date: Sat, 25 Jul 2026 10:50:50 -0400 Subject: [PATCH 06/23] ci: fix patch file path (git -C changes cwd, relative path was wrong) --- .github/workflows/build-and-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 3bddde4..fcefcb2 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -113,7 +113,7 @@ jobs: PATCHEOF git clone --quiet https://repo.or.cz/tinycc.git tinycc-src - git -C tinycc-src apply --verbose etext_fix.patch + git -C tinycc-src apply --verbose "$PWD/etext_fix.patch" - name: Start freebsd-amd64 VM uses: cross-platform-actions/action@v1.3.0 From eaa3217b12192f79ac1a1b9a9a440f0754e4cbbf Mon Sep 17 00:00:00 2001 From: Richard Wheeler <18647491+PythonWillRule@users.noreply.github.com> Date: Sat, 25 Jul 2026 11:11:43 -0400 Subject: [PATCH 07/23] ci: use git:// protocol for repo.or.cz (https is currently broken there, confirmed independently) --- .github/workflows/build-and-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index fcefcb2..c598dcb 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -112,7 +112,7 @@ jobs: set_global_sym(s1, "__global_pointer$", data_section, 0x800); PATCHEOF - git clone --quiet https://repo.or.cz/tinycc.git tinycc-src + git clone --quiet git://repo.or.cz/tinycc.git tinycc-src git -C tinycc-src apply --verbose "$PWD/etext_fix.patch" - name: Start freebsd-amd64 VM From a83356a47eee339d43ad6e45bb9a05284c49646a Mon Sep 17 00:00:00 2001 From: Richard Wheeler <18647491+PythonWillRule@users.noreply.github.com> Date: Sat, 25 Jul 2026 11:14:06 -0400 Subject: [PATCH 08/23] ci: use system cc (clang) instead of gcc, matching update_tccbin.yml's freebsd config --- .github/workflows/build-and-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index c598dcb..038c631 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -131,7 +131,7 @@ jobs: sudo pkg install -y bash git gmake cd tinycc-src - ./configure --prefix=/tmp/tcc-patched + CC=cc ./configure --prefix=/tmp/tcc-patched --cc=cc gmake -j"$(sysctl -n hw.ncpu)" ./tcc --version cd .. From 4d6ada50ba93cf2b8a291bfabe1d64bbe35dd27f Mon Sep 17 00:00:00 2001 From: Richard Wheeler <18647491+PythonWillRule@users.noreply.github.com> Date: Sat, 25 Jul 2026 11:16:52 -0400 Subject: [PATCH 09/23] ci: run gmake install so the configured --prefix path actually exists --- .github/workflows/build-and-test.yml | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 038c631..98b53f1 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -133,7 +133,8 @@ jobs: cd tinycc-src CC=cc ./configure --prefix=/tmp/tcc-patched --cc=cc gmake -j"$(sysctl -n hw.ncpu)" - ./tcc --version + gmake install + /tmp/tcc-patched/bin/tcc --version cd .. git clone --branch thirdparty-freebsd-amd64 --depth=1 \ @@ -144,7 +145,7 @@ jobs: git -C vsrc checkout c82d3f08271e9324d6fb8de3c251e9c0e1a9154b echo "=== testing PATCHED tcc against bundled libgc.a ===" - tinycc-src/tcc vsrc/thirdparty/tccbin_tests/shared/hello.c \ + /tmp/tcc-patched/bin/tcc vsrc/thirdparty/tccbin_tests/shared/hello.c \ -DGC_BUILTIN_ATOMIC=1 -DBUS_PAGE_FAULT=T_PAGEFLT -DALL_INTERIOR_POINTERS=1 \ -I "$PWD/vsrc/thirdparty/libgc/include" \ -I "$PWD/thirdparty/tcc/include" \ From 146aec2de876ef9b9be4233d084f157706429872 Mon Sep 17 00:00:00 2001 From: Richard Wheeler <18647491+PythonWillRule@users.noreply.github.com> Date: Sat, 25 Jul 2026 11:21:58 -0400 Subject: [PATCH 10/23] ci: finalize with XFAIL lane for the tcc etext/end limitation tcc on FreeBSD cannot currently link the bundled libgc.a (undefined symbol 'etext'/'end' - see tccelf.c's tcc_add_linker_symbols, which only defines the glibc-style _etext/_edata/_end, never the plain BSD-style names BDWGC's FreeBSD code references). Root-caused and a fix verified against a real FreeBSD VM, being submitted upstream to tinycc-devel - but it isn't in any shipped tcc.exe yet. crash.c (no GC) is checked directly as the real blocking regression check. The GC-dependent tests (hello.c, gc_alloc.c) run via the full shared suite as an explicit, temporary XFAIL lane - visible in CI logs so a regression that fails *differently* is still noticed, but not blocking. Remove continue-on-error once the tcc fix ships in a rebuilt tcc.exe here. Removes the temporary etext-fix verification job now that the fix is confirmed and the real CI reflects reality. --- .github/workflows/build-and-test.yml | 129 ++++++--------------------- 1 file changed, 29 insertions(+), 100 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 98b53f1..4876549 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -26,7 +26,7 @@ jobs: shell: sh sync_files: runner-to-vm - - name: run shared conformance tests + - name: fetch shared conformance suite and this branch's binaries shell: cpa.sh {0} run: | set -eu @@ -45,111 +45,40 @@ jobs: chmod +x thirdparty/tcc/tcc.exe - # TEMPORARY diagnostic: run.sh swallows compile stderr, so on - # first failure here we can't see *why* linking failed. Show - # it directly before running the real suite. - thirdparty/tcc/tcc.exe vsrc/thirdparty/tccbin_tests/shared/hello.c \ - -DGC_BUILTIN_ATOMIC=1 -DBUS_PAGE_FAULT=T_PAGEFLT -DALL_INTERIOR_POINTERS=1 \ - -I "$PWD/vsrc/thirdparty/libgc/include" \ - "$PWD/thirdparty/tcc/lib/libgc.a" \ - -lpthread \ - -o /tmp/hello_diag || true - - # The bundled tcc.exe resolves its own crt/libtcc1.a via a path - # relative to the process's working directory (confirmed on - # linux-amd64/macos-arm64's CI) - thirdparty/tcc/tcc.exe is - # already correctly placed relative to $PWD here since we just - # cloned it there directly. - bash vsrc/thirdparty/tccbin_tests/run.sh "$PWD/thirdparty/tcc/tcc.exe" freebsd -- \ - -DGC_BUILTIN_ATOMIC=1 -DBUS_PAGE_FAULT=T_PAGEFLT -DALL_INTERIOR_POINTERS=1 \ - -I "$PWD/vsrc/thirdparty/libgc/include" \ - "$PWD/thirdparty/tcc/lib/libgc.a" \ - -lpthread - - # TEMPORARY: verifies a candidate tinycc fix for the 'undefined symbol - # etext/end' failure above, before submitting it upstream. Builds a - # patched tcc from vanilla tinycc source (there's no GitHub mirror to - # push a real branch to - tinycc's canonical repo is repo.or.cz, using - # email patch submission, not PRs) and tests it against this branch's - # already-committed libgc.a. Remove this job once the fix is confirmed - # and submitted - it's not part of the branch's real CI. - verify-etext-fix: - runs-on: ubuntu-latest - steps: - # repo.or.cz (tinycc's canonical host - no GitHub mirror exists) - # resets connections from inside the FreeBSD VM every time - # (reproduced twice) - cloning + patching here on the runner instead - # avoids that network path entirely; sync_files: runner-to-vm below - # carries the already-patched source into the VM via rsync (which - # preserves permissions) before each cpa.sh step runs. - - name: clone and patch tinycc on the runner + # tcc on FreeBSD cannot currently link the bundled libgc.a: its + # linker only ever defines the glibc-style _etext/_edata/_end + # (see tccelf.c's tcc_add_linker_symbols), never the plain BSD- + # style etext/edata/end that BDWGC's FreeBSD data-segment-scanning + # code references directly - so any GC-dependent program fails + # with "undefined symbol 'etext'"/"'end'". Root-caused and a fix + # verified against a real FreeBSD VM (patched tcc successfully + # builds+runs shared/hello.c against this same libgc.a); the fix + # is being submitted upstream to tinycc-devel but isn't in any + # shipped tcc.exe yet, so it can't be relied on here. + # + # crash.c doesn't touch the GC at all, so it's checked directly + # (bypassing run.sh, which would otherwise apply the same GC + # flags to every test) as the real, blocking regression check for + # this platform's tcc/libtcc1.a/crt pairing. + - name: run shared conformance tests (crash only, no GC - blocking) + shell: cpa.sh {0} run: | set -eu - cat > etext_fix.patch <<'PATCHEOF' - diff --git a/tccelf.c b/tccelf.c - index 7e9758af..f9ae676c 100644 - --- a/tccelf.c - +++ b/tccelf.c - @@ -1890,6 +1890,19 @@ static void tcc_add_linker_symbols(TCCState *s1) - #if TARGETOS_OpenBSD - set_global_sym(s1, "__executable_start", NULL, ELF_START_ADDR); - #endif - +#if TARGETOS_BSD - + /* Traditional BSD systems provide the plain (non-underscore) names - + as the primary linker-provided segment-boundary symbols, unlike - + glibc/Linux where they're only weak aliases of _etext/_edata/_end - + supplied by the C library's own crt objects - so code that - + references the plain names directly (e.g. BDWGC's FreeBSD - + data-segment-scanning code looks up `etext`/`end` to find its - + conservative-GC root region) links fine under a BSD system's - + native linker but fails here with "undefined symbol" errors. */ - + set_global_sym(s1, "etext", text_section, -1); - + set_global_sym(s1, "edata", data_section, -1); - + set_global_sym(s1, "end", bss_section, -1); - +#endif - #ifdef TCC_TARGET_RISCV64 - /* XXX should be .sdata+0x800, not .data+0x800 */ - set_global_sym(s1, "__global_pointer$", data_section, 0x800); - PATCHEOF - - git clone --quiet git://repo.or.cz/tinycc.git tinycc-src - git -C tinycc-src apply --verbose "$PWD/etext_fix.patch" - - - name: Start freebsd-amd64 VM - uses: cross-platform-actions/action@v1.3.0 - with: - operating_system: freebsd - version: '15.1' - memory: 4G - shell: sh - sync_files: runner-to-vm + thirdparty/tcc/tcc.exe vsrc/thirdparty/tccbin_tests/shared/crash.c \ + -o /tmp/crash_nogc + if /tmp/crash_nogc; then + echo "expected a nonzero exit from an unguarded null-pointer dereference, got 0" >&2 + exit 1 + fi + echo "no-GC compile+crash check passed" - - name: build patched tcc and test against bundled libgc.a + - name: run shared conformance tests (libgc.a - XFAIL until the etext/end tcc fix ships) shell: cpa.sh {0} + continue-on-error: true run: | set -eu - sudo pkg install -y bash git gmake - - cd tinycc-src - CC=cc ./configure --prefix=/tmp/tcc-patched --cc=cc - gmake -j"$(sysctl -n hw.ncpu)" - gmake install - /tmp/tcc-patched/bin/tcc --version - cd .. - - git clone --branch thirdparty-freebsd-amd64 --depth=1 \ - https://github.com/vlang/tccbin.git thirdparty/tcc - git clone --filter=blob:none --no-checkout --depth=1 \ - https://github.com/vlang/v.git vsrc - git -C vsrc sparse-checkout set --no-cone thirdparty/libgc thirdparty/tccbin_tests - git -C vsrc checkout c82d3f08271e9324d6fb8de3c251e9c0e1a9154b - - echo "=== testing PATCHED tcc against bundled libgc.a ===" - /tmp/tcc-patched/bin/tcc vsrc/thirdparty/tccbin_tests/shared/hello.c \ + bash vsrc/thirdparty/tccbin_tests/run.sh "$PWD/thirdparty/tcc/tcc.exe" freebsd -- \ -DGC_BUILTIN_ATOMIC=1 -DBUS_PAGE_FAULT=T_PAGEFLT -DALL_INTERIOR_POINTERS=1 \ -I "$PWD/vsrc/thirdparty/libgc/include" \ - -I "$PWD/thirdparty/tcc/include" \ "$PWD/thirdparty/tcc/lib/libgc.a" \ - -lpthread \ - -o /tmp/hello_patched - /tmp/hello_patched + -lpthread From b591f24103c14f83cb10c98df4a7ed94b329b444 Mon Sep 17 00:00:00 2001 From: Richard Wheeler <18647491+PythonWillRule@users.noreply.github.com> Date: Sat, 25 Jul 2026 13:12:22 -0400 Subject: [PATCH 11/23] ci: test the PR's own revision, and require SIGSEGV specifically Two issues found by Codex review (pullrequestreview-4779654227): - The hardcoded `git clone --branch thirdparty-freebsd-amd64 .../vlang/tccbin.git` always tested the already-merged target branch, regardless of what a PR actually proposed - a PR updating tcc.exe/libgc.a could pass CI while testing the old, unrelated binaries. Now resolves the PR's own head repo+ref for pull_request events, falling back to the triggering ref for push/workflow_dispatch (which have no PR context). - The no-GC crash check only verified "nonzero exit", which an exec-format error, missing dynamic loader, or an unrelated miscompilation exiting 1 would also satisfy - silently masking a real regression, since the GC-backed suite is explicitly non-blocking. Now requires exit 139 specifically (killed by SIGSEGV), matching crash.c's actual intended fault. --- .github/workflows/build-and-test.yml | 47 +++++++++++++++++++++++++--- 1 file changed, 42 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 4876549..b71a860 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -17,6 +17,25 @@ jobs: # directly inside the VM (rather than actions/checkout on the # runner + sync_files) mirrors that proven-working pattern instead # of relying on an unverified file-permission-preserving sync. + # For a pull_request event, clone the PR's own head repo+ref + # (so a PR that updates tcc.exe/libgc.a is actually tested) + # instead of the unrelated target branch's current tip - a + # hardcoded `git clone --branch thirdparty-freebsd-amd64 + # .../vlang/tccbin.git` would silently test only the + # already-merged target branch regardless of what the PR + # proposes. push/workflow_dispatch have no PR context, so they + # fall back to whatever ref actually triggered the run. + - name: resolve what to clone + id: clone_target + run: | + if [ "${{ github.event_name }}" = "pull_request" ]; then + echo "url=${{ github.event.pull_request.head.repo.clone_url }}" >> "$GITHUB_OUTPUT" + echo "ref=${{ github.event.pull_request.head.ref }}" >> "$GITHUB_OUTPUT" + else + echo "url=https://github.com/vlang/tccbin.git" >> "$GITHUB_OUTPUT" + echo "ref=${{ github.ref_name }}" >> "$GITHUB_OUTPUT" + fi + - name: Start freebsd-amd64 VM uses: cross-platform-actions/action@v1.3.0 with: @@ -25,6 +44,10 @@ jobs: memory: 4G shell: sh sync_files: runner-to-vm + environment_variables: TCCBIN_CLONE_URL TCCBIN_CLONE_REF + env: + TCCBIN_CLONE_URL: ${{ steps.clone_target.outputs.url }} + TCCBIN_CLONE_REF: ${{ steps.clone_target.outputs.ref }} - name: fetch shared conformance suite and this branch's binaries shell: cpa.sh {0} @@ -32,8 +55,8 @@ jobs: set -eu sudo pkg install -y bash git - git clone --branch thirdparty-freebsd-amd64 --depth=1 \ - https://github.com/vlang/tccbin.git thirdparty/tcc + git clone --branch "$TCCBIN_CLONE_REF" --depth=1 \ + "$TCCBIN_CLONE_URL" thirdparty/tcc # thirdparty/libgc/include (gc.h) and thirdparty/tccbin_tests # (the shared cross-platform conformance suite) both live in @@ -66,11 +89,25 @@ jobs: set -eu thirdparty/tcc/tcc.exe vsrc/thirdparty/tccbin_tests/shared/crash.c \ -o /tmp/crash_nogc - if /tmp/crash_nogc; then - echo "expected a nonzero exit from an unguarded null-pointer dereference, got 0" >&2 + + set +e + /tmp/crash_nogc + code=$? + set -e + + # Any nonzero exit isn't enough: an exec-format error, a + # missing dynamic loader, or an unrelated miscompilation that + # just exit(1)s would also satisfy that and silently mask a + # real regression, since the GC-backed suite below is + # non-blocking. crash.c's null-pointer dereference is + # expected to be killed by SIGSEGV specifically, which a + # POSIX shell reports as exit code 128+11=139 - verify that + # exact signal-terminated signature, not just "nonzero". + if [ "$code" -ne 139 ]; then + echo "expected exit 139 (killed by SIGSEGV) from an unguarded null-pointer dereference, got $code" >&2 exit 1 fi - echo "no-GC compile+crash check passed" + echo "no-GC compile+crash check passed (killed by SIGSEGV as expected)" - name: run shared conformance tests (libgc.a - XFAIL until the etext/end tcc fix ships) shell: cpa.sh {0} From 69d6496d6ac4a15403f51bd3bc708d31318414ca Mon Sep 17 00:00:00 2001 From: Richard Wheeler <18647491+PythonWillRule@users.noreply.github.com> Date: Sat, 25 Jul 2026 13:17:33 -0400 Subject: [PATCH 12/23] ci: fix environment_variables forwarding (needs job-level env, not step-level) --- .github/workflows/build-and-test.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index b71a860..dc5484d 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -10,6 +10,9 @@ on: jobs: build: runs-on: ubuntu-latest + env: + TCCBIN_CLONE_URL: ${{ steps.clone_target.outputs.url }} + TCCBIN_CLONE_REF: ${{ steps.clone_target.outputs.ref }} steps: # cross-platform-actions/action boots a real FreeBSD VM inside this # Linux runner - the same action vlang/v's own update_tccbin.yml @@ -45,9 +48,6 @@ jobs: shell: sh sync_files: runner-to-vm environment_variables: TCCBIN_CLONE_URL TCCBIN_CLONE_REF - env: - TCCBIN_CLONE_URL: ${{ steps.clone_target.outputs.url }} - TCCBIN_CLONE_REF: ${{ steps.clone_target.outputs.ref }} - name: fetch shared conformance suite and this branch's binaries shell: cpa.sh {0} From b37132d0158fab0ff1287afdac06a530cf4a8a0f Mon Sep 17 00:00:00 2001 From: Richard Wheeler <18647491+PythonWillRule@users.noreply.github.com> Date: Sat, 25 Jul 2026 13:20:59 -0400 Subject: [PATCH 13/23] ci: fix job-level env referencing steps context (schema violation - GH Actions doesn't allow it) --- .github/workflows/build-and-test.yml | 37 +++++++++++----------------- 1 file changed, 15 insertions(+), 22 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index dc5484d..f87d948 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -10,9 +10,6 @@ on: jobs: build: runs-on: ubuntu-latest - env: - TCCBIN_CLONE_URL: ${{ steps.clone_target.outputs.url }} - TCCBIN_CLONE_REF: ${{ steps.clone_target.outputs.ref }} steps: # cross-platform-actions/action boots a real FreeBSD VM inside this # Linux runner - the same action vlang/v's own update_tccbin.yml @@ -20,25 +17,18 @@ jobs: # directly inside the VM (rather than actions/checkout on the # runner + sync_files) mirrors that proven-working pattern instead # of relying on an unverified file-permission-preserving sync. - # For a pull_request event, clone the PR's own head repo+ref - # (so a PR that updates tcc.exe/libgc.a is actually tested) - # instead of the unrelated target branch's current tip - a - # hardcoded `git clone --branch thirdparty-freebsd-amd64 - # .../vlang/tccbin.git` would silently test only the - # already-merged target branch regardless of what the PR - # proposes. push/workflow_dispatch have no PR context, so they - # fall back to whatever ref actually triggered the run. - - name: resolve what to clone - id: clone_target - run: | - if [ "${{ github.event_name }}" = "pull_request" ]; then - echo "url=${{ github.event.pull_request.head.repo.clone_url }}" >> "$GITHUB_OUTPUT" - echo "ref=${{ github.event.pull_request.head.ref }}" >> "$GITHUB_OUTPUT" - else - echo "url=https://github.com/vlang/tccbin.git" >> "$GITHUB_OUTPUT" - echo "ref=${{ github.ref_name }}" >> "$GITHUB_OUTPUT" - fi - + # + # For a pull_request event, clone the PR's own head repo+ref (so + # a PR that updates tcc.exe/libgc.a is actually tested) instead + # of the unrelated target branch's current tip - a hardcoded + # `git clone --branch thirdparty-freebsd-amd64 .../vlang/tccbin.git` + # would silently test only the already-merged target branch + # regardless of what the PR proposes. push/workflow_dispatch have + # no PR context, so they fall back to whatever ref triggered the + # run. Computed inline here (not a separate step + job-level env) + # because job-level env can't reference the steps context at all - + # that's a schema violation that fails the whole workflow file, + # not just this expression. - name: Start freebsd-amd64 VM uses: cross-platform-actions/action@v1.3.0 with: @@ -48,6 +38,9 @@ jobs: shell: sh sync_files: runner-to-vm environment_variables: TCCBIN_CLONE_URL TCCBIN_CLONE_REF + env: + TCCBIN_CLONE_URL: ${{ github.event.pull_request.head.repo.clone_url || 'https://github.com/vlang/tccbin.git' }} + TCCBIN_CLONE_REF: ${{ github.event.pull_request.head.ref || github.ref_name }} - name: fetch shared conformance suite and this branch's binaries shell: cpa.sh {0} From bf1697fa26feb0c5f71d6c2d07689dce94f3d1e2 Mon Sep 17 00:00:00 2001 From: Richard Wheeler <18647491+PythonWillRule@users.noreply.github.com> Date: Sat, 25 Jul 2026 13:36:49 -0400 Subject: [PATCH 14/23] ci: move env to job level (step-level env on a uses: step wasn't forwarded by environment_variables) --- .github/workflows/build-and-test.yml | 30 ++++++++++++++-------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index f87d948..7f6b5cd 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -10,6 +10,21 @@ on: jobs: build: runs-on: ubuntu-latest + # For a pull_request event, clone the PR's own head repo+ref (so a + # PR that updates tcc.exe/libgc.a is actually tested) instead of + # the unrelated target branch's current tip - a hardcoded + # `git clone --branch thirdparty-freebsd-amd64 .../vlang/tccbin.git` + # would silently test only the already-merged target branch + # regardless of what the PR proposes. push/workflow_dispatch have + # no PR context, so they fall back to whatever ref triggered the + # run. Set at job level (matching update_tccbin.yml's own working + # BSD job env, which only ever references github.*/secrets.*, never + # steps.* - step-level env on the "Start VM" step was tried first + # and empirically did NOT get forwarded into the VM by + # environment_variables, unlike this job-level placement). + env: + TCCBIN_CLONE_URL: ${{ github.event.pull_request.head.repo.clone_url || 'https://github.com/vlang/tccbin.git' }} + TCCBIN_CLONE_REF: ${{ github.event.pull_request.head.ref || github.ref_name }} steps: # cross-platform-actions/action boots a real FreeBSD VM inside this # Linux runner - the same action vlang/v's own update_tccbin.yml @@ -17,18 +32,6 @@ jobs: # directly inside the VM (rather than actions/checkout on the # runner + sync_files) mirrors that proven-working pattern instead # of relying on an unverified file-permission-preserving sync. - # - # For a pull_request event, clone the PR's own head repo+ref (so - # a PR that updates tcc.exe/libgc.a is actually tested) instead - # of the unrelated target branch's current tip - a hardcoded - # `git clone --branch thirdparty-freebsd-amd64 .../vlang/tccbin.git` - # would silently test only the already-merged target branch - # regardless of what the PR proposes. push/workflow_dispatch have - # no PR context, so they fall back to whatever ref triggered the - # run. Computed inline here (not a separate step + job-level env) - # because job-level env can't reference the steps context at all - - # that's a schema violation that fails the whole workflow file, - # not just this expression. - name: Start freebsd-amd64 VM uses: cross-platform-actions/action@v1.3.0 with: @@ -38,9 +41,6 @@ jobs: shell: sh sync_files: runner-to-vm environment_variables: TCCBIN_CLONE_URL TCCBIN_CLONE_REF - env: - TCCBIN_CLONE_URL: ${{ github.event.pull_request.head.repo.clone_url || 'https://github.com/vlang/tccbin.git' }} - TCCBIN_CLONE_REF: ${{ github.event.pull_request.head.ref || github.ref_name }} - name: fetch shared conformance suite and this branch's binaries shell: cpa.sh {0} From f7ae4ae192d81cfa167f05aad5359c26da73d4b2 Mon Sep 17 00:00:00 2001 From: Richard Wheeler <18647491+PythonWillRule@users.noreply.github.com> Date: Sat, 25 Jul 2026 16:52:50 -0400 Subject: [PATCH 15/23] ci: fix Codex-flagged CI hardening issues (pin SHA, pin action, fetch pinned suite commit, harden XFAIL) Fixes 3 P2 + 1 P1 findings from pullrequestreview-4780048339 on vlang/tccbin#75: - P1: fetch the pinned vlang/v suite commit directly instead of a plain --depth=1 clone-then-checkout, which only ever has the current tip's objects and would start failing the moment vlang/v advances past the pinned commit - P2: clone the exact triggering commit (SHA) instead of a mutable ref name, which was racy against a push landing while this run was queued - P2: fall back to the triggering event's own repository for non-PR runs instead of a hardcoded vlang/tccbin.git - P2: assert the exact known etext/end failure signature in the libgc.a XFAIL lane instead of a blanket continue-on-error, so an unrelated regression (corrupted archive, bad checkout) can't silently pass as the known XFAIL Also pins cross-platform-actions/action to a commit SHA instead of the mutable v1.3.0 tag (same class of finding as the sibling openbsd-amd64 workflow, pullrequestreview-4780049532 on vlang/tccbin#76). --- .github/workflows/build-and-test.yml | 106 ++++++++++++++++++++------- 1 file changed, 81 insertions(+), 25 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 7f6b5cd..5527724 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -10,21 +10,26 @@ on: jobs: build: runs-on: ubuntu-latest - # For a pull_request event, clone the PR's own head repo+ref (so a - # PR that updates tcc.exe/libgc.a is actually tested) instead of - # the unrelated target branch's current tip - a hardcoded + # For a pull_request event, clone the PR's own head repo+commit (so a + # PR that updates tcc.exe/libgc.a is actually tested) instead of the + # unrelated target branch's current tip - a hardcoded # `git clone --branch thirdparty-freebsd-amd64 .../vlang/tccbin.git` # would silently test only the already-merged target branch - # regardless of what the PR proposes. push/workflow_dispatch have - # no PR context, so they fall back to whatever ref triggered the - # run. Set at job level (matching update_tccbin.yml's own working - # BSD job env, which only ever references github.*/secrets.*, never - # steps.* - step-level env on the "Start VM" step was tried first - # and empirically did NOT get forwarded into the VM by - # environment_variables, unlike this job-level placement). + # regardless of what the PR proposes. push/workflow_dispatch have no + # PR context, so they fall back to the event's own repository/commit + # (not a branch *name*, which is mutable: another push landing while + # this run is queued/starting would otherwise make the resolved + # value, a ref name, silently resolve to a different commit than the + # one that triggered this run - Codex pullrequestreview-4780048339 on + # vlang/tccbin#75). Set at job level (matching update_tccbin.yml's + # own working BSD job env, which only ever references + # github.*/secrets.*, never steps.* - step-level env on the "Start + # VM" step was tried first and empirically did NOT get forwarded + # into the VM by environment_variables, unlike this job-level + # placement). env: - TCCBIN_CLONE_URL: ${{ github.event.pull_request.head.repo.clone_url || 'https://github.com/vlang/tccbin.git' }} - TCCBIN_CLONE_REF: ${{ github.event.pull_request.head.ref || github.ref_name }} + TCCBIN_CLONE_URL: ${{ github.event.pull_request.head.repo.clone_url || github.event.repository.clone_url }} + TCCBIN_CLONE_SHA: ${{ github.event.pull_request.head.sha || github.sha }} steps: # cross-platform-actions/action boots a real FreeBSD VM inside this # Linux runner - the same action vlang/v's own update_tccbin.yml @@ -32,15 +37,20 @@ jobs: # directly inside the VM (rather than actions/checkout on the # runner + sync_files) mirrors that proven-working pattern instead # of relying on an unverified file-permission-preserving sync. + # Pinned to the v1.3.0 tag's commit (resolved via the GitHub API) + # rather than the mutable tag itself, so a retag upstream can't + # silently swap in different third-party code here without a + # review-visible diff (Codex pullrequestreview-4780048339 on + # vlang/tccbin#75). - name: Start freebsd-amd64 VM - uses: cross-platform-actions/action@v1.3.0 + uses: cross-platform-actions/action@4347c661239bf5dcd0cd77708061488d907343d6 # v1.3.0 with: operating_system: freebsd version: '15.1' memory: 4G shell: sh sync_files: runner-to-vm - environment_variables: TCCBIN_CLONE_URL TCCBIN_CLONE_REF + environment_variables: TCCBIN_CLONE_URL TCCBIN_CLONE_SHA - name: fetch shared conformance suite and this branch's binaries shell: cpa.sh {0} @@ -48,16 +58,35 @@ jobs: set -eu sudo pkg install -y bash git - git clone --branch "$TCCBIN_CLONE_REF" --depth=1 \ - "$TCCBIN_CLONE_URL" thirdparty/tcc + # Fetch the exact commit that triggered this run, not a branch + # name - `git clone --branch ` would resolve whatever + # that name points to *at clone time*, which can race a push + # that lands after this run started (Codex pullrequestreview- + # 4780048339 on vlang/tccbin#75). + mkdir thirdparty/tcc && cd thirdparty/tcc + git init -q + git remote add origin "$TCCBIN_CLONE_URL" + git fetch --depth=1 origin "$TCCBIN_CLONE_SHA" + git checkout -q FETCH_HEAD + cd ../.. # thirdparty/libgc/include (gc.h) and thirdparty/tccbin_tests # (the shared cross-platform conformance suite) both live in - # the main v repo, not here. - git clone --filter=blob:none --no-checkout --depth=1 \ - https://github.com/vlang/v.git vsrc - git -C vsrc sparse-checkout set --no-cone thirdparty/libgc thirdparty/tccbin_tests - git -C vsrc checkout c82d3f08271e9324d6fb8de3c251e9c0e1a9154b + # the main v repo, not here. A plain `git clone --depth=1` + # only ever contains the CURRENT tip commit's objects - once + # vlang/v advances past this pinned SHA, that historical commit + # object won't exist in a fresh shallow clone and this checkout + # would fail (Codex P1, pullrequestreview-4780048339 on + # vlang/tccbin#75, line 60). Fetch that exact SHA directly + # instead of cloning HEAD and hoping it's still there. + mkdir vsrc && cd vsrc + git init -q + git remote add origin https://github.com/vlang/v.git + git sparse-checkout init --no-cone + git sparse-checkout set thirdparty/libgc thirdparty/tccbin_tests + git fetch --filter=blob:none --depth=1 origin c82d3f08271e9324d6fb8de3c251e9c0e1a9154b + git checkout -q FETCH_HEAD + cd .. chmod +x thirdparty/tcc/tcc.exe @@ -102,13 +131,40 @@ jobs: fi echo "no-GC compile+crash check passed (killed by SIGSEGV as expected)" + # continue-on-error alone would also swallow an unrelated failure + # (a corrupted libgc.a, a bad checkout, run.sh going missing) as if + # it were the known etext/end failure, and the blocking crash-only + # step above never references libgc.a at all - so a real + # regression in the archive itself could pass CI unnoticed (Codex + # pullrequestreview-4780048339 on vlang/tccbin#75, line 107). + # Assert the exact known failure signature instead, mirroring + # macos-arm64's own libgc.a XFAIL lane: any other failure shape + # (or an unexpected full pass, meaning the etext/end fix landed) + # fails the job for real. - name: run shared conformance tests (libgc.a - XFAIL until the etext/end tcc fix ships) shell: cpa.sh {0} - continue-on-error: true run: | - set -eu - bash vsrc/thirdparty/tccbin_tests/run.sh "$PWD/thirdparty/tcc/tcc.exe" freebsd -- \ + set +e + output=$(bash vsrc/thirdparty/tccbin_tests/run.sh "$PWD/thirdparty/tcc/tcc.exe" freebsd -- \ -DGC_BUILTIN_ATOMIC=1 -DBUS_PAGE_FAULT=T_PAGEFLT -DALL_INTERIOR_POINTERS=1 \ -I "$PWD/vsrc/thirdparty/libgc/include" \ "$PWD/thirdparty/tcc/lib/libgc.a" \ - -lpthread + -lpthread 2>&1) + code=$? + set -e + echo "$output" + + if [ "$code" -eq 0 ]; then + echo "expected the known etext/end unresolved-symbol failure, but this lane fully passed - the upstream tcc fix must have landed; remove this XFAIL special-casing and fold it back into a single blocking lane." >&2 + exit 1 + fi + + case "$output" in + *"PASS crash"*"FAIL gc_alloc (compile error)"*"FAIL hello (compile error)"*) + echo "known XFAIL: etext/end still unresolved on FreeBSD tcc, as expected - not blocking CI" + ;; + *) + echo "libgc.a lane failed, but NOT with the known/expected signature (PASS crash, FAIL gc_alloc/hello with compile error) - this looks like a different, unexpected problem and should not be silently treated as the known XFAIL." >&2 + exit 1 + ;; + esac From fd124a30eeb9fdf7cb19292b23c6bd3c20c5d8c9 Mon Sep 17 00:00:00 2001 From: Richard Wheeler <18647491+PythonWillRule@users.noreply.github.com> Date: Sat, 25 Jul 2026 16:57:57 -0400 Subject: [PATCH 16/23] ci: fix mkdir (needs -p, thirdparty/ parent dir doesn't exist yet in a fresh VM) --- .github/workflows/build-and-test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 5527724..7b4a207 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -63,7 +63,7 @@ jobs: # that name points to *at clone time*, which can race a push # that lands after this run started (Codex pullrequestreview- # 4780048339 on vlang/tccbin#75). - mkdir thirdparty/tcc && cd thirdparty/tcc + mkdir -p thirdparty/tcc && cd thirdparty/tcc git init -q git remote add origin "$TCCBIN_CLONE_URL" git fetch --depth=1 origin "$TCCBIN_CLONE_SHA" @@ -79,7 +79,7 @@ jobs: # would fail (Codex P1, pullrequestreview-4780048339 on # vlang/tccbin#75, line 60). Fetch that exact SHA directly # instead of cloning HEAD and hoping it's still there. - mkdir vsrc && cd vsrc + mkdir -p vsrc && cd vsrc git init -q git remote add origin https://github.com/vlang/v.git git sparse-checkout init --no-cone From 2df21416014a6b5fc6176c7397c7ded3f4c573d6 Mon Sep 17 00:00:00 2001 From: Richard Wheeler <18647491+PythonWillRule@users.noreply.github.com> Date: Sat, 25 Jul 2026 18:08:09 -0400 Subject: [PATCH 17/23] ci: harden libgc.a XFAIL to assert the actual etext/end error, not just the run.sh summary shape Fixes P2 finding from pullrequestreview-4780219278 on vlang/tccbin#75: the pinned run.sh's summary-only match couldn't distinguish the known etext/end bug from a different static-link regression producing the same PASS-crash/FAIL-gc_alloc/FAIL-hello shape (e.g. a PR replacing libgc.a with a valid-but-incomplete archive). Now compiles hello.c directly to capture real tcc stderr and requires it specifically mention an unresolved etext/end symbol before accepting the XFAIL. Mirrors the identical fix just applied to macos-amd64's libgc.a XFAIL lane for the same class of finding (pullrequestreview-4780178390 on vlang/tccbin#74). --- .github/workflows/build-and-test.yml | 32 ++++++++++++++++++++++++++-- 1 file changed, 30 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 7b4a207..6beba0d 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -159,12 +159,40 @@ jobs: exit 1 fi + # The pinned run.sh only ever prints "(compile error)" with no + # detail, so the summary-line match above can't tell "the known + # etext/end bug" apart from a DIFFERENT static-link regression + # that happens to fail the same two tests - e.g. a PR that + # replaces libgc.a with a valid-but-incomplete archive lacking + # the GC objects entirely: crash.c still compiles (it never + # references GC symbols) while gc_alloc/hello both report + # "compile error", matching this same summary shape for an + # unrelated reason (Codex pullrequestreview-4780219278 on + # vlang/tccbin#75). Compile hello.c directly to capture the + # real tcc stderr and assert it's specifically the known + # etext/end unresolved-symbol error. + direct_err=$(thirdparty/tcc/tcc.exe vsrc/thirdparty/tccbin_tests/shared/hello.c \ + -DGC_BUILTIN_ATOMIC=1 -DBUS_PAGE_FAULT=T_PAGEFLT -DALL_INTERIOR_POINTERS=1 \ + -I vsrc/thirdparty/libgc/include \ + thirdparty/tcc/lib/libgc.a \ + -lpthread \ + -o /tmp/hello_xfail_probe 2>&1) + case "$output" in *"PASS crash"*"FAIL gc_alloc (compile error)"*"FAIL hello (compile error)"*) - echo "known XFAIL: etext/end still unresolved on FreeBSD tcc, as expected - not blocking CI" + case "$direct_err" in + *"undefined symbol 'etext'"*|*"undefined symbol 'end'"*) + echo "known XFAIL: etext/end still unresolved on FreeBSD tcc, as expected - not blocking CI" + ;; + *) + echo "libgc.a lane failed with the known summary shape, but the direct hello.c compile error does NOT mention an unresolved etext/end symbol - this looks like a different, unexpected regression:" >&2 + echo "$direct_err" >&2 + exit 1 + ;; + esac ;; *) - echo "libgc.a lane failed, but NOT with the known/expected signature (PASS crash, FAIL gc_alloc/hello with compile error) - this looks like a different, unexpected problem and should not be silently treated as the known XFAIL." >&2 + echo "libgc.a lane failed, but NOT with the known/expected summary (PASS crash, FAIL gc_alloc/hello with compile error) - this looks like a different, unexpected problem and should not be silently treated as the known XFAIL." >&2 exit 1 ;; esac From c2748f0dc154dd6f2bff2495b40d8ea175cee46c Mon Sep 17 00:00:00 2001 From: Richard Wheeler <18647491+PythonWillRule@users.noreply.github.com> Date: Sat, 25 Jul 2026 19:30:55 -0400 Subject: [PATCH 18/23] ci: fix set -e aborting before the XFAIL case statement (direct_err capture needs || true, tcc's failure is expected) --- .github/workflows/build-and-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 6beba0d..220a2b8 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -176,7 +176,7 @@ jobs: -I vsrc/thirdparty/libgc/include \ thirdparty/tcc/lib/libgc.a \ -lpthread \ - -o /tmp/hello_xfail_probe 2>&1) + -o /tmp/hello_xfail_probe 2>&1) || true case "$output" in *"PASS crash"*"FAIL gc_alloc (compile error)"*"FAIL hello (compile error)"*) From 340d9f4f2af00c7e3369f588f61e7d78a26bf2e1 Mon Sep 17 00:00:00 2001 From: Richard Wheeler <18647491+PythonWillRule@users.noreply.github.com> Date: Sat, 25 Jul 2026 23:19:11 -0400 Subject: [PATCH 19/23] ci: validate both gc_alloc.c and hello.c's direct errors in the libgc.a XFAIL, not just one Fixes P1 finding from pullrequestreview-4780815399 on vlang/tccbin#75: checking only hello.c's direct compiler error let a regression isolated to gc_alloc.c alone hide behind the same "PASS crash, FAIL gc_alloc, FAIL hello" summary shape and pass unnoticed. Now captures and asserts the known etext/end signature for both failing tests independently. --- .github/workflows/build-and-test.yml | 43 +++++++++++++++++++--------- 1 file changed, 29 insertions(+), 14 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 220a2b8..aa8de6e 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -168,28 +168,43 @@ jobs: # references GC symbols) while gc_alloc/hello both report # "compile error", matching this same summary shape for an # unrelated reason (Codex pullrequestreview-4780219278 on - # vlang/tccbin#75). Compile hello.c directly to capture the - # real tcc stderr and assert it's specifically the known - # etext/end unresolved-symbol error. - direct_err=$(thirdparty/tcc/tcc.exe vsrc/thirdparty/tccbin_tests/shared/hello.c \ + # vlang/tccbin#75). Compile BOTH failing tests directly to + # capture their real tcc stderr and assert each is specifically + # the known etext/end unresolved-symbol error - checking only + # one of the two (e.g. hello.c) would let an unrelated + # regression isolated to the OTHER test (gc_alloc.c) hide + # behind this same summary shape and pass unnoticed (Codex + # pullrequestreview-4780815399 on vlang/tccbin#75). + direct_err_hello=$(thirdparty/tcc/tcc.exe vsrc/thirdparty/tccbin_tests/shared/hello.c \ -DGC_BUILTIN_ATOMIC=1 -DBUS_PAGE_FAULT=T_PAGEFLT -DALL_INTERIOR_POINTERS=1 \ -I vsrc/thirdparty/libgc/include \ thirdparty/tcc/lib/libgc.a \ -lpthread \ -o /tmp/hello_xfail_probe 2>&1) || true + direct_err_gc_alloc=$(thirdparty/tcc/tcc.exe vsrc/thirdparty/tccbin_tests/shared/gc_alloc.c \ + -DGC_BUILTIN_ATOMIC=1 -DBUS_PAGE_FAULT=T_PAGEFLT -DALL_INTERIOR_POINTERS=1 \ + -I vsrc/thirdparty/libgc/include \ + thirdparty/tcc/lib/libgc.a \ + -lpthread \ + -o /tmp/gc_alloc_xfail_probe 2>&1) || true + + is_known_etext_end() { + case "$1" in + *"undefined symbol 'etext'"*|*"undefined symbol 'end'"*) return 0 ;; + *) return 1 ;; + esac + } case "$output" in *"PASS crash"*"FAIL gc_alloc (compile error)"*"FAIL hello (compile error)"*) - case "$direct_err" in - *"undefined symbol 'etext'"*|*"undefined symbol 'end'"*) - echo "known XFAIL: etext/end still unresolved on FreeBSD tcc, as expected - not blocking CI" - ;; - *) - echo "libgc.a lane failed with the known summary shape, but the direct hello.c compile error does NOT mention an unresolved etext/end symbol - this looks like a different, unexpected regression:" >&2 - echo "$direct_err" >&2 - exit 1 - ;; - esac + if is_known_etext_end "$direct_err_hello" && is_known_etext_end "$direct_err_gc_alloc"; then + echo "known XFAIL: etext/end still unresolved on FreeBSD tcc for both gc_alloc.c and hello.c, as expected - not blocking CI" + else + echo "libgc.a lane failed with the known summary shape, but at least one of gc_alloc.c/hello.c's direct compile errors does NOT mention an unresolved etext/end symbol - this looks like a different, unexpected regression:" >&2 + echo "hello.c: $direct_err_hello" >&2 + echo "gc_alloc.c: $direct_err_gc_alloc" >&2 + exit 1 + fi ;; *) echo "libgc.a lane failed, but NOT with the known/expected summary (PASS crash, FAIL gc_alloc/hello with compile error) - this looks like a different, unexpected problem and should not be silently treated as the known XFAIL." >&2 From 5cf3efee104802a148e752dcaba67bcc9b8027c8 Mon Sep 17 00:00:00 2001 From: Richard Wheeler <18647491+PythonWillRule@users.noreply.github.com> Date: Sun, 26 Jul 2026 06:16:02 -0400 Subject: [PATCH 20/23] ci: reject additional linker errors alongside the known etext/end signature in the XFAIL check Fixes P1 finding from pullrequestreview-4780907186 on vlang/tccbin#75: the etext/end substring check accepted the XFAIL even if a regression added a NEW unresolved symbol alongside the known ones. This bug is narrow (only etext/end, unlike macos-amd64's whole-archive-unparseable case) so an exact match is correct: reject if any undefined-symbol line names something other than etext/end. --- .github/workflows/build-and-test.yml | 13 ++++++++++++- 1 file changed, 12 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index aa8de6e..970e812 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -188,11 +188,22 @@ jobs: -lpthread \ -o /tmp/gc_alloc_xfail_probe 2>&1) || true + # Unlike macos-amd64's whole-archive-unparseable bug, this + # FreeBSD bug is narrow: tcc's linker only ever fails to define + # the two plain BSD-style symbols (etext, end) that BDWGC + # references directly - nothing else in the archive is + # affected. So an exact match here is the correct check: reject + # if any unresolved-reference line names a symbol OTHER than + # etext/end, since that would mean a genuinely different, + # additional regression rode along with the known bug (Codex + # pullrequestreview-4780907186 on vlang/tccbin#75). is_known_etext_end() { case "$1" in - *"undefined symbol 'etext'"*|*"undefined symbol 'end'"*) return 0 ;; + *"undefined symbol 'etext'"*|*"undefined symbol 'end'"*) ;; *) return 1 ;; esac + other=$(printf '%s\n' "$1" | grep -oE "undefined symbol '[^']+'" | grep -v -E "undefined symbol '(etext|end)'") + [ -z "$other" ] } case "$output" in From ea3b81b4aad8861e63c1ffd673c560016a0801ec Mon Sep 17 00:00:00 2001 From: Richard Wheeler <18647491+PythonWillRule@users.noreply.github.com> Date: Sun, 26 Jul 2026 07:36:45 -0400 Subject: [PATCH 21/23] ci: fix 2 more Codex findings (broader exclusivity check, positive no-GC check) Fixes both findings from pullrequestreview-4781468264 on vlang/tccbin#75: - P2: the libgc.a XFAIL's exclusivity check now matches on tcc's `tcc: error:` line prefix instead of only "undefined symbol" lines, so a wholly different KIND of tcc error riding alongside the known etext/end error can no longer hide behind the check - verified empirically: the old narrower check accepted a mocked known-symbol- plus-unrelated-error case, the new one correctly rejects it - P2: added a positive no-GC check (compile+run a trivial non-crashing program, require exit 0) alongside the existing crash.c-must-SIGSEGV check, so a broken startup path that crashes EVERY program can't hide behind "the crash happened as expected" - verified empirically against a mocked always-crashing tcc: old logic would have passed, new logic correctly fails Same class of gap also fixed on the sibling macos-amd64 workflow (pullrequestreview-4781470066 on vlang/tccbin#74). --- .github/workflows/build-and-test.yml | 38 +++++++++++++++++++++++++++- 1 file changed, 37 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 970e812..674c474 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -131,6 +131,32 @@ jobs: fi echo "no-GC compile+crash check passed (killed by SIGSEGV as expected)" + # crash.c exiting 139 only proves SOME crash happened - if a + # broken libtcc1.a/crt or startup path made EVERY program + # segfault immediately (before ever reaching the intentional + # null-pointer dereference), this check would still see exit + # 139 and wrongly call it "expected" (Codex pullrequestreview- + # 4781468264 on vlang/tccbin#75). The GC-backed lane below + # can't provide this positive check either, since it's + # expected to fail at link time. Compile and run a trivial, + # non-crashing program with the same no-GC flags, requiring it + # to actually complete and exit 0 - proving the toolchain can + # still produce a genuinely working binary, not just one that + # crashes regardless of source. + cat > /tmp/nogc_trivial.c <<'TRIVIALEOF' + int main(void) { return 0; } + TRIVIALEOF + thirdparty/tcc/tcc.exe /tmp/nogc_trivial.c -o /tmp/nogc_trivial + set +e + /tmp/nogc_trivial + trivial_code=$? + set -e + if [ "$trivial_code" -ne 0 ]; then + echo "expected the trivial no-GC program to exit 0, got $trivial_code - the no-GC toolchain path may be broken (e.g. crashing at startup) even though the crash.c check above happened to pass" >&2 + exit 1 + fi + echo "trivial no-GC success check passed (exit=0)" + # continue-on-error alone would also swallow an unrelated failure # (a corrupted libgc.a, a bad checkout, run.sh going missing) as if # it were the known etext/end failure, and the blocking crash-only @@ -202,7 +228,17 @@ jobs: *"undefined symbol 'etext'"*|*"undefined symbol 'end'"*) ;; *) return 1 ;; esac - other=$(printf '%s\n' "$1" | grep -oE "undefined symbol '[^']+'" | grep -v -E "undefined symbol '(etext|end)'") + # Filtering only "undefined symbol '...'" lines and checking + # their NAMES misses a wholly DIFFERENT kind of tcc error + # (invalid object, relocation error, etc.) riding alongside + # the known one - such a line simply wouldn't match the + # "undefined symbol" pattern at extraction, so `other` would + # stay empty and this would wrongly accept the XFAIL (Codex + # pullrequestreview-4781468264 on vlang/tccbin#75). Match on + # tcc's actual error-line prefix instead, so ANY tcc error + # line that isn't specifically etext/end gets caught, not + # just a differently-named undefined symbol. + other=$(printf '%s\n' "$1" | grep -E '^tcc: error:' | grep -v -E "undefined symbol '(etext|end)'") [ -z "$other" ] } From 5d8211f34950a7a5ab39bfed9c5e3f72b77ae2de Mon Sep 17 00:00:00 2001 From: Richard Wheeler <18647491+PythonWillRule@users.noreply.github.com> Date: Sun, 26 Jul 2026 13:02:19 -0400 Subject: [PATCH 22/23] ci: preserve XFAIL probe exit codes, not just the captured text Fixes P2 finding from pullrequestreview-4781865117 on vlang/tccbin#75: the libgc.a XFAIL's direct-error probes used `|| true`, discarding the probe's own exit code entirely - a regression that made tcc print the expected etext/end diagnostic and then crash/abort (SIGSEGV, SIGABRT) rather than exiting cleanly would still pass, since only the captured text was checked. Now captures the real exit code alongside the text and rejects any signal-terminated exit (128+signal) even when the expected text is present. Verified empirically: a mocked "expected text + SIGSEGV exit" case passed under the old logic and is correctly rejected now. --- .github/workflows/build-and-test.yml | 30 ++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 674c474..26e1dc3 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -201,18 +201,22 @@ jobs: # regression isolated to the OTHER test (gc_alloc.c) hide # behind this same summary shape and pass unnoticed (Codex # pullrequestreview-4780815399 on vlang/tccbin#75). + set +e direct_err_hello=$(thirdparty/tcc/tcc.exe vsrc/thirdparty/tccbin_tests/shared/hello.c \ -DGC_BUILTIN_ATOMIC=1 -DBUS_PAGE_FAULT=T_PAGEFLT -DALL_INTERIOR_POINTERS=1 \ -I vsrc/thirdparty/libgc/include \ thirdparty/tcc/lib/libgc.a \ -lpthread \ - -o /tmp/hello_xfail_probe 2>&1) || true + -o /tmp/hello_xfail_probe 2>&1) + direct_code_hello=$? direct_err_gc_alloc=$(thirdparty/tcc/tcc.exe vsrc/thirdparty/tccbin_tests/shared/gc_alloc.c \ -DGC_BUILTIN_ATOMIC=1 -DBUS_PAGE_FAULT=T_PAGEFLT -DALL_INTERIOR_POINTERS=1 \ -I vsrc/thirdparty/libgc/include \ thirdparty/tcc/lib/libgc.a \ -lpthread \ - -o /tmp/gc_alloc_xfail_probe 2>&1) || true + -o /tmp/gc_alloc_xfail_probe 2>&1) + direct_code_gc_alloc=$? + set -e # Unlike macos-amd64's whole-archive-unparseable bug, this # FreeBSD bug is narrow: tcc's linker only ever fails to define @@ -224,6 +228,20 @@ jobs: # additional regression rode along with the known bug (Codex # pullrequestreview-4780907186 on vlang/tccbin#75). is_known_etext_end() { + # $1 = captured stderr text, $2 = the probe's own exit code. + # A regression could make tcc print the expected etext/end + # diagnostic and then crash/abort rather than exiting + # cleanly with its normal compile-error status - the earlier + # `|| true` discarded that exit code entirely, so a shell + # "Segmentation fault" or similar abnormal termination + # alongside the expected text would still pass (Codex + # pullrequestreview-4781865117 on vlang/tccbin#75). A POSIX + # shell reports a signal-terminated process as exit code + # 128+signal; reject those instead of treating any nonzero + # exit as "the expected compile-error status". + if [ "$2" -gt 128 ]; then + return 1 + fi case "$1" in *"undefined symbol 'etext'"*|*"undefined symbol 'end'"*) ;; *) return 1 ;; @@ -244,12 +262,12 @@ jobs: case "$output" in *"PASS crash"*"FAIL gc_alloc (compile error)"*"FAIL hello (compile error)"*) - if is_known_etext_end "$direct_err_hello" && is_known_etext_end "$direct_err_gc_alloc"; then + if is_known_etext_end "$direct_err_hello" "$direct_code_hello" && is_known_etext_end "$direct_err_gc_alloc" "$direct_code_gc_alloc"; then echo "known XFAIL: etext/end still unresolved on FreeBSD tcc for both gc_alloc.c and hello.c, as expected - not blocking CI" else - echo "libgc.a lane failed with the known summary shape, but at least one of gc_alloc.c/hello.c's direct compile errors does NOT mention an unresolved etext/end symbol - this looks like a different, unexpected regression:" >&2 - echo "hello.c: $direct_err_hello" >&2 - echo "gc_alloc.c: $direct_err_gc_alloc" >&2 + echo "libgc.a lane failed with the known summary shape, but at least one of gc_alloc.c/hello.c's direct compile errors does NOT mention an unresolved etext/end symbol (or exited abnormally) - this looks like a different, unexpected regression:" >&2 + echo "hello.c: exit=$direct_code_hello: $direct_err_hello" >&2 + echo "gc_alloc.c: exit=$direct_code_gc_alloc: $direct_err_gc_alloc" >&2 exit 1 fi ;; From d9212d5e25be98aa260b5ade791cc76f4c301145 Mon Sep 17 00:00:00 2001 From: Richard Wheeler <18647491+PythonWillRule@users.noreply.github.com> Date: Sun, 26 Jul 2026 13:07:28 -0400 Subject: [PATCH 23/23] ci: test the actual PR merge commit, not just the head branch tip in isolation Fixes P2 finding from pullrequestreview-4781865117 on vlang/tccbin#75: cloning pull_request.head.sha tested the PR's own branch tree in isolation, never the merge result GitHub would actually produce against the current target branch. A PR replacing tcc.exe could pass against its own tree while the actual merge (combined with whatever the target branch has since gained, e.g. a different libtcc1.a from a merged sibling PR) was never tested at all - the required check stays green for a combination that was never verified. Now uses github.sha + github.event.repository.clone_url uniformly for all 3 trigger types: for pull_request events, github.sha is GitHub's own synthesized merge commit, which exists only in the base repo (never a contributor's fork) - so the clone URL switches from the fork to the base repo accordingly. github.sha stays fixed for a run's entire lifetime once the triggering event fires, so this remains exactly as race-safe against a mid-queue push as the previous head.sha-based approach (the original P1 this replaced, from pullrequestreview-4780048339), while also testing what will actually be merged instead of the head tree alone. macos-amd64 doesn't need this fix: it already uses plain actions/checkout@v4 with no explicit ref, which already defaults to checking out the pull_request merge commit automatically. --- .github/workflows/build-and-test.yml | 51 +++++++++++++++++----------- 1 file changed, 32 insertions(+), 19 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 26e1dc3..b4fe3aa 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -10,26 +10,39 @@ on: jobs: build: runs-on: ubuntu-latest - # For a pull_request event, clone the PR's own head repo+commit (so a - # PR that updates tcc.exe/libgc.a is actually tested) instead of the - # unrelated target branch's current tip - a hardcoded - # `git clone --branch thirdparty-freebsd-amd64 .../vlang/tccbin.git` - # would silently test only the already-merged target branch - # regardless of what the PR proposes. push/workflow_dispatch have no - # PR context, so they fall back to the event's own repository/commit - # (not a branch *name*, which is mutable: another push landing while - # this run is queued/starting would otherwise make the resolved - # value, a ref name, silently resolve to a different commit than the - # one that triggered this run - Codex pullrequestreview-4780048339 on - # vlang/tccbin#75). Set at job level (matching update_tccbin.yml's - # own working BSD job env, which only ever references - # github.*/secrets.*, never steps.* - step-level env on the "Start - # VM" step was tried first and empirically did NOT get forwarded - # into the VM by environment_variables, unlike this job-level - # placement). + # `github.sha` and `github.event.repository.clone_url` are used + # uniformly across all 3 trigger event types, and correctly cover + # each: + # - pull_request: `github.sha` is GitHub's own synthesized MERGE + # commit (what the target branch would actually look like if + # this PR were merged right now), not the PR branch's own head - + # testing only the head tree in isolation could pass a PR whose + # OWN commit works fine, while the actual merge result (combined + # with whatever the target branch has since gained) is broken + # (Codex pullrequestreview-4781865117 on vlang/tccbin#75). That + # merge commit exists ONLY as an object in the base repo + # (vlang/tccbin, exposed via `refs/pull//merge`) - never in a + # contributor's fork - so this must clone from + # `github.event.repository.clone_url` (the base repo), not the + # fork's URL, regardless of where the PR originated. + # - push/workflow_dispatch: `github.sha`/`github.event.repository` + # are simply the pushed/dispatched commit and the repo it lives + # in - already exactly what should be tested. + # In every case, `github.sha` is fixed for this run's entire + # lifetime once the triggering event fires (a later push creates a + # brand new run with its own new `github.sha`, it doesn't mutate + # this one) - so this is exactly as race-safe against a + # mid-queue push as the earlier head.sha-based approach was (Codex + # pullrequestreview-4780048339 on vlang/tccbin#75), while also + # testing the actual merge result instead of the head tree alone. + # Set at job level (matching update_tccbin.yml's own working BSD + # job env, which only ever references github.*/secrets.*, never + # steps.* - step-level env on the "Start VM" step was tried first + # and empirically did NOT get forwarded into the VM by + # environment_variables, unlike this job-level placement). env: - TCCBIN_CLONE_URL: ${{ github.event.pull_request.head.repo.clone_url || github.event.repository.clone_url }} - TCCBIN_CLONE_SHA: ${{ github.event.pull_request.head.sha || github.sha }} + TCCBIN_CLONE_URL: ${{ github.event.repository.clone_url }} + TCCBIN_CLONE_SHA: ${{ github.sha }} steps: # cross-platform-actions/action boots a real FreeBSD VM inside this # Linux runner - the same action vlang/v's own update_tccbin.yml