test-infra(vm): CI-identical smoke plus ubsan/pageheap/parallel drivers

Add vm-smoke.sh, which stages the release pair (launcher + payload) in a
profile-rooted temp dir and runs scripts/smoke-test.sh exactly as the CI
windows pr-smoke step does, so the real-Windows leg exercises the same
managed-install path. Extend win.sh with ubsan-build/ubsan-test (UBSan works
under x64-on-ARM emulation; ASan does not), a PageHeap toggle for OS-level
heap checking of the native runner, and a full-suite parallel run. Document
the honest sanitizer limits and the daily loop in the README.

Signed-off-by: Martin Vogel <martin.vogel.tech@gmail.com>
This commit is contained in:
Martin Vogel committed 2026-07-19 16:56:02 +02:00
1 parent 593d126813
commit 08b7ff54d2
3 files changed
+73 -11

No files matched your search

+14 -5
View File
@@ -72,11 +72,20 @@ vm/win.sh push-file src/cli/cli.c /c/cbm/src/cli/cli.c # WIP iteration
(ACL/owner/paths/locks — the entire Windows tail class) reproduce
faithfully. Build with `SANITIZE=` (no ASan runtime exists for
aarch64-windows).
- **CLANG64 (x86_64 = CI's arch, emulated)**: for arch-parity checks
(`win.sh asan-build` builds it). **ASan does NOT work under x64-on-ARM
emulation** (the runtime faults in process init) — verified, don't retry.
Windows sanitizer coverage therefore stays a CI-only leg; note the CI
windows failures have historically been logic failures, not ASan aborts.
- **CLANG64 (x86_64 = CI's arch, emulated)**: arch-parity checks and
**UBSan, which WORKS under emulation** (validated: builds, runs, and
reports a planted signed-overflow with file:line) — `win.sh ubsan-build`
+ `ubsan-test <suites>`. UBSan needs no interceptors, which is why it
survives emulation.
- **ASan does NOT exist on this VM in either arch** — verified, don't
retry: the aarch64-windows compiler-rt ships no sanitizer runtimes at
all (MSVC's ARM64 ASan is a VS-2026 preview tied to the MSVC CRT), and
the x86_64 ASan runtime faults during process-init under x64-on-ARM
emulation. ASan coverage stays a CI-only leg; note the CI windows
failures have historically been logic failures, not ASan aborts.
- **PageHeap** (`win.sh pageheap on|off`): OS-level page-granular heap
overflow/UAF detection for the native ARM64 test-runner — a
toolchain-agnostic partial ASan substitute that works on real Windows.
- The bootstrap mirrors the GitHub-runner default-owner policy
(`NoDefaultAdminOwner=0`) so CI-only ownership refusals reproduce locally.
- Environment shape (runner temp paths, runneradmin profile) is
+27
View File
@@ -0,0 +1,27 @@
#!/usr/bin/env bash
# vm-smoke.sh — run the PR smoke inside the Windows VM exactly as CI does.
#
# Mirrors .github/workflows/pr.yml's windows pr-smoke step: stage the release
# pair (launcher as codebase-memory-mcp.exe + CLI as .payload.exe) in a
# profile-rooted temp dir — MSYS2 /tmp is intentionally rejected by the
# launcher (shared writable ancestor), and so is anything under the msys
# install tree — then run scripts/smoke-test.sh against the staged launcher.
#
# Run inside the VM's CLANGARM64 shell from the repo root:
# bash test-infrastructure/vm/vm-smoke.sh
# Or from the host: test-infrastructure/vm/win.sh smoke
set -euo pipefail
cd "$(dirname "$0")/../.."
[ -x build/c/codebase-memory-mcp.exe ] || { echo "build first (win.sh build)" >&2; exit 2; }
PROFILE_ROOT="$(cygpath -u "$USERPROFILE")"
SMOKE_DIR="$(mktemp -d "$PROFILE_ROOT/cbm-vm-smoke.XXXXXX")"
trap 'rm -rf "$SMOKE_DIR"' EXIT
cp build/c/codebase-memory-mcp-launcher.exe "$SMOKE_DIR/codebase-memory-mcp.exe"
cp build/c/codebase-memory-mcp.exe "$SMOKE_DIR/codebase-memory-mcp.payload.exe"
CBM_CACHE_DIR="$(cygpath -m "$SMOKE_DIR/cache")" \
SMOKE_TEMP_ROOT="$SMOKE_DIR" \
scripts/smoke-test.sh "$SMOKE_DIR/codebase-memory-mcp.exe"
+32 -6
View File
@@ -14,7 +14,9 @@
# win.sh smoke-install # real managed-install E2E (Phase 8 class)
# win.sh sh <command...> # arbitrary command in CLANGARM64 env
# win.sh push-file <local> <vm> # scp one file into the VM (WIP iteration)
# win.sh asan-build # x86_64 CLANG64 build WITH ASan (CI arch)
# win.sh test-par # full suite, parallel on all VM cores
# win.sh ubsan-build|ubsan-test # UBSan at CI's x86_64 arch (emulated; works)
# win.sh pageheap on|off # OS heap verification for native runs
set -euo pipefail
CONFIG="${HOME}/.claude/cbm-vm/config"
@@ -42,7 +44,7 @@ update)
exec "$0" build
;;
build)
vm clangarm64 "cd /c/cbm && make -j${JOBS} -f Makefile.cbm CC=clang CXX=clang++ SANITIZE= cbm build/c/test-runner > /tmp/win-build.log 2>&1 && echo BUILD_OK || (echo BUILD_FAIL; tail -20 /tmp/win-build.log; exit 1)"
vm clangarm64 "cd /c/cbm && make -j${JOBS} -f Makefile.cbm CC='ccache clang' CXX='ccache clang++' SANITIZE= cbm build/c/test-runner > /tmp/win-build.log 2>&1 && echo BUILD_OK || (echo BUILD_FAIL; tail -20 /tmp/win-build.log; exit 1)"
;;
test)
[ $# -ge 1 ] || { echo "usage: win.sh test <suite...>" >&2; exit 2; }
@@ -65,10 +67,34 @@ push-file)
dest="${2/#\/c\//C:\/}"
scp -i "$KEY" -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null "$1" "${USER_}@${HOST}:${dest}"
;;
asan-build)
# x86_64 (CI's exact arch) with ASan, runs under Windows-on-ARM emulation.
# Slower; use when a finding needs sanitizer confirmation or CI-arch parity.
vm clang64 "cd /c/cbm && make -j${JOBS} -f Makefile.cbm CC=clang CXX=clang++ build/c/test-runner > /tmp/win-asan-build.log 2>&1 && echo ASAN_BUILD_OK || (echo ASAN_BUILD_FAIL; tail -20 /tmp/win-asan-build.log; exit 1)"
ubsan-build)
# x86_64 (CI's exact arch) with UBSan, runs under Windows-on-ARM emulation.
# Validated: UBSan needs no interceptors, so it builds, runs, AND reports
# correctly under emulation. (ASan does NOT: no aarch64 runtime exists and
# the x86_64 runtime faults in emulated process-init — ASan stays CI-only.)
vm clang64 "cd /c/cbm && make -j${JOBS} -f Makefile.cbm CC=clang CXX=clang++ SANITIZE='-fsanitize=undefined -fno-omit-frame-pointer' build/c/test-runner > /tmp/win-ubsan-build.log 2>&1 && echo UBSAN_BUILD_OK || (echo UBSAN_BUILD_FAIL; tail -20 /tmp/win-ubsan-build.log; exit 1)"
;;
ubsan-test)
[ $# -ge 1 ] || { echo "usage: win.sh ubsan-test <suite...>" >&2; exit 2; }
vm clang64 "cd /c/cbm && ./build/c/test-runner $* 2>&1 | tail -40"
;;
pageheap)
# OS-level heap verification (page-granular overflow/UAF detection) for the
# native ARM64 test-runner — toolchain-agnostic partial ASan substitute.
# 'on' enables full PageHeap for test-runner.exe via IFEO; 'off' removes it.
case "${1:-}" in
on)
"${SSH[@]}" "reg add \"HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\test-runner.exe\" /v GlobalFlag /t REG_DWORD /d 0x02000000 /f && reg add \"HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\test-runner.exe\" /v PageHeapFlags /t REG_DWORD /d 0x3 /f && echo PAGEHEAP_ON"
;;
off)
"${SSH[@]}" "reg delete \"HKLM\\SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Image File Execution Options\\test-runner.exe\" /f && echo PAGEHEAP_OFF"
;;
*) echo "usage: win.sh pageheap on|off" >&2; exit 2 ;;
esac
;;
test-par)
# Full-suite parallel run on all VM cores via the repo's parallel harness.
vm clangarm64 "cd /c/cbm && bash scripts/run-tests-parallel.sh build/c/test-runner 2>&1 | tail -25"
;;
*)
echo "unknown command: $cmd (see header for usage)" >&2; exit 2