From 9b1a7c7fac09dec0252dba24bb7974e81b4ced21 Mon Sep 17 00:00:00 2001 From: astandrik Date: Tue, 18 Aug 2026 13:43:51 +0300 Subject: [PATCH 1/4] test: verify sanitizer build configuration Signed-off-by: astandrik --- scripts/msan.sh | 21 +++++++++++++++++++++ scripts/test.sh | 46 +++++++++++++++++++++++++++++++++++++++++++++- tests/test_main.c | 10 ++++++++++ 3 files changed, 76 insertions(+), 1 deletion(-) diff --git a/scripts/msan.sh b/scripts/msan.sh index d74deb55d..954608890 100755 --- a/scripts/msan.sh +++ b/scripts/msan.sh @@ -79,6 +79,27 @@ ulimit -s 262144 2>/dev/null || true export CBM_THREAD_STACK_MB="${CBM_THREAD_STACK_MB:-256}" export LD_LIBRARY_PATH="$MSAN_PREFIX/lib${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}" +expected_build_config=$'sanitized=1 test_seams=1\n' +build_config_marker="__cbm_build_config_end__" +captured_build_config="" +actual_build_config="" +build_config_probe_ok=0 +if captured_build_config="$(./build/msan/test-runner --build-config && printf '%s' "$build_config_marker")"; then + build_config_probe_ok=1 + actual_build_config="${captured_build_config%"$build_config_marker"}" +else + actual_build_config="$captured_build_config" +fi +if [ "$build_config_probe_ok" -ne 1 ] || + [ "$actual_build_config" != "$expected_build_config" ]; then + reported_build_config="${actual_build_config//$'\n'/\\n}" + printf '%s\n' 'ERROR: build config mismatch for build/msan/test-runner' >&2 + printf '%s\n' ' expected: sanitized=1 test_seams=1' >&2 + printf ' reported: %s\n' "${reported_build_config:-}" >&2 + printf '%s\n' 'Refusing to run suites; check sanitizer flags and CBM_SANITIZED_BUILD wiring.' >&2 + exit 1 +fi + echo "=== MSan lane: $(clang --version | head -1) ===" # KNOWN RED — THREE DISTINCT CAUSES, whitelisted per cause (O10) diff --git a/scripts/test.sh b/scripts/test.sh index 0dc575b04..70aa3d7ae 100755 --- a/scripts/test.sh +++ b/scripts/test.sh @@ -145,6 +145,7 @@ source "$ROOT/scripts/path-safety.sh" MAKE_ARGS=() BUILD_DIR="build/c" SANITIZE_GIVEN=0 +SANITIZE_VALUE="" prev_arg="" for arg in "$@"; do case "$arg" in @@ -154,7 +155,11 @@ for arg in "$@"; do --tsan) ;; # already handled --suites|--suites=*) ;; # already handled (value skipped via prev_arg below) BUILD_DIR=*) BUILD_DIR="${arg#BUILD_DIR=}"; MAKE_ARGS+=("$arg") ;; - SANITIZE=*) SANITIZE_GIVEN=1; MAKE_ARGS+=("$arg") ;; + SANITIZE=*) + SANITIZE_GIVEN=1 + SANITIZE_VALUE="${arg#SANITIZE=}" + MAKE_ARGS+=("$arg") + ;; *=*) if [[ "${prev_arg:-}" != "--suites" ]]; then MAKE_ARGS+=("$arg") # forward any VAR=VAL to make @@ -174,6 +179,42 @@ if [ "$SANITIZE_GIVEN" -eq 0 ] && [ "${MSYSTEM:-}" = "CLANGARM64" ]; then MAKE_ARGS+=("SANITIZE=-fsanitize=undefined -fsanitize-trap=undefined -fstack-protector-strong -fno-omit-frame-pointer") fi +EXPECTED_SANITIZED=1 +if [ "$SANITIZE_GIVEN" -eq 1 ]; then + case "$SANITIZE_VALUE" in + *[![:space:]]*) EXPECTED_SANITIZED=1 ;; + *) EXPECTED_SANITIZED=0 ;; + esac +fi + +# Refuse to run suites when the built runner disagrees with the lane that +# produced it. Exact output keeps missing, duplicate, or future unhandled +# fields fail-closed instead of silently weakening the gate. +assert_test_runner_build_config() { + local runner="$1" + local expected_sanitized="$2" + local expected="sanitized=$expected_sanitized test_seams=1" + local marker="__cbm_build_config_end__" + local captured="" + local actual="" + local probe_ok=0 + + if captured="$("$runner" --build-config && printf '%s' "$marker")"; then + probe_ok=1 + actual="${captured%"$marker"}" + else + actual="$captured" + fi + if [ "$probe_ok" -ne 1 ] || [ "$actual" != "$expected"$'\n' ]; then + local reported="${actual//$'\n'/\\n}" + printf 'ERROR: build config mismatch for %s\n' "$runner" >&2 + printf ' expected: %s\n' "$expected" >&2 + printf ' reported: %s\n' "${reported:-}" >&2 + printf '%s\n' 'Refusing to run suites; check sanitizer flags and CBM_SANITIZED_BUILD wiring.' >&2 + return 1 + fi +} + print_env "test.sh" # ── TSan mode (--tsan): the data-race gate ── @@ -182,6 +223,7 @@ print_env "test.sh" if [ "$TSAN" -eq 1 ]; then echo "=== test.sh: TSan leg (make test-tsan) ===" make -j"$NPROC" -f Makefile.cbm "$BUILD_DIR/test-runner-tsan" ${MAKE_ARGS[@]+"${MAKE_ARGS[@]}"} + assert_test_runner_build_config "$BUILD_DIR/test-runner-tsan" 1 make -f Makefile.cbm test-tsan ${MAKE_ARGS[@]+"${MAKE_ARGS[@]}"} exit "$?" fi @@ -192,6 +234,7 @@ fi if [ -n "$SUITES" ]; then echo "=== test.sh: ITERATION mode — suites: $SUITES (incremental build) ===" make -j"$NPROC" -f Makefile.cbm "$BUILD_DIR/test-runner" ${MAKE_ARGS[@]+"${MAKE_ARGS[@]}"} + assert_test_runner_build_config "$BUILD_DIR/test-runner" "$EXPECTED_SANITIZED" # shellcheck disable=SC2086 # suite list is deliberately word-split "$BUILD_DIR/test-runner" $SUITES exit "$?" @@ -275,6 +318,7 @@ BUILD_DIR="$BUILD_DIR" scripts/clean.sh # pass/fail/skip totals aggregate to the same numbers as the sequential run). # CBM_TEST_SEQUENTIAL=1 restores the single-process runner. make -j"$NPROC" -f Makefile.cbm "$BUILD_DIR/test-runner" ${MAKE_ARGS[@]+"${MAKE_ARGS[@]}"} +assert_test_runner_build_config "$BUILD_DIR/test-runner" "$EXPECTED_SANITIZED" if [ "${CBM_TEST_SEQUENTIAL:-0}" = "1" ]; then make -f Makefile.cbm test ${MAKE_ARGS[@]+"${MAKE_ARGS[@]}"} else diff --git a/tests/test_main.c b/tests/test_main.c index ba6f26d45..2a88646c7 100644 --- a/tests/test_main.c +++ b/tests/test_main.c @@ -17,6 +17,7 @@ int tf_skip_count = 0; #include "foundation/log.h" /* crash-durable worker log probe */ #include "foundation/mem.h" /* cbm_mem_init — worker budget */ #include "foundation/platform.h" /* cbm_file_exists — blocking-git marker */ +#include "foundation/sanitized.h" /* CBM_SANITIZED — --build-config contract */ #include "daemon/runtime.h" /* bounded worker response probe */ #include "daemon/ipc.h" /* Windows private-lock re-exec probe */ #include "daemon/version_cohort.h" /* Windows crash-turnover re-exec probe */ @@ -838,6 +839,15 @@ int main(int argc, char **argv) { (void)puts("codebase-memory-mcp test-runner"); return 0; } + if (argc == 2 && strcmp(argv[1], "--build-config") == 0) { +#if defined(CBM_ENABLE_TEST_SEAMS) && CBM_ENABLE_TEST_SEAMS + const int test_seams = 1; +#else + const int test_seams = 0; +#endif + (void)printf("sanitized=%d test_seams=%d\n", CBM_SANITIZED, test_seams); + return 0; + } int mcp_idxfailclosed_rc = tf_maybe_run_mcp_idxfailclosed_probe(argc, argv); if (mcp_idxfailclosed_rc >= 0) { return mcp_idxfailclosed_rc; From ba0c49911dcc57213c2b8436d158a938f6f2883a Mon Sep 17 00:00:00 2001 From: astandrik Date: Tue, 18 Aug 2026 18:38:16 +0300 Subject: [PATCH 2/4] test: preserve LF in Windows build config output Signed-off-by: astandrik --- tests/test_main.c | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/tests/test_main.c b/tests/test_main.c index 2a88646c7..19e7b620c 100644 --- a/tests/test_main.c +++ b/tests/test_main.c @@ -818,17 +818,6 @@ extern void suite_dump_verify_io(void); extern void cbm_kind_in_set_free_cache(void); int main(int argc, char **argv) { - /* Skip the multi-hundred-MB executable-image hash that computes the exact - * build fingerprint: it is tens of seconds per spawned worker/daemon under - * ASan on constrained CI runners and the sole cause of the daemon-family - * readiness-timeout flakes. Set once here; every forked child and re-exec'd - * worker inherits it, so exact-build match/mismatch still works (a - * mismatch test still passes a DIFFERENT fingerprint via argv). Honoured - * only under CBM_CLI_ENABLE_TEST_API — never in a production binary. */ - if (!getenv("CBM_TEST_BUILD_FINGERPRINT")) { - (void)cbm_setenv("CBM_TEST_BUILD_FINGERPRINT", - "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", 1); - } int blocking_git_rc = tf_maybe_run_blocking_git_probe(argc, argv); if (blocking_git_rc >= 0) { return blocking_git_rc; @@ -840,6 +829,12 @@ int main(int argc, char **argv) { return 0; } if (argc == 2 && strcmp(argv[1], "--build-config") == 0) { +#ifdef _WIN32 + if (_setmode(cbm_fileno(stdout), _O_BINARY) == -1) { + fprintf(stderr, "failed to set build-config stdout to binary mode\n"); + return 2; + } +#endif #if defined(CBM_ENABLE_TEST_SEAMS) && CBM_ENABLE_TEST_SEAMS const int test_seams = 1; #else @@ -848,6 +843,17 @@ int main(int argc, char **argv) { (void)printf("sanitized=%d test_seams=%d\n", CBM_SANITIZED, test_seams); return 0; } + /* Skip the multi-hundred-MB executable-image hash that computes the exact + * build fingerprint: it is tens of seconds per spawned worker/daemon under + * ASan on constrained CI runners and the sole cause of the daemon-family + * readiness-timeout flakes. Set once here; every forked child and re-exec'd + * worker inherits it, so exact-build match/mismatch still works (a + * mismatch test still passes a DIFFERENT fingerprint via argv). Honoured + * only under CBM_CLI_ENABLE_TEST_API — never in a production binary. */ + if (!getenv("CBM_TEST_BUILD_FINGERPRINT")) { + (void)cbm_setenv("CBM_TEST_BUILD_FINGERPRINT", + "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef", 1); + } int mcp_idxfailclosed_rc = tf_maybe_run_mcp_idxfailclosed_probe(argc, argv); if (mcp_idxfailclosed_rc >= 0) { return mcp_idxfailclosed_rc; From 0b45c444dc20806385d6dcc7079fde70098226ba Mon Sep 17 00:00:00 2001 From: astandrik Date: Wed, 19 Aug 2026 12:54:34 +0300 Subject: [PATCH 3/4] ci: retry transient CodeQL runner failure Signed-off-by: astandrik From 06aa4714ee0cf98d69d2ae787f8710761c018cda Mon Sep 17 00:00:00 2001 From: astandrik Date: Wed, 19 Aug 2026 15:57:35 +0300 Subject: [PATCH 4/4] test: include Windows CRT headers directly Signed-off-by: astandrik --- tests/test_main.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/test_main.c b/tests/test_main.c index 19e7b620c..879e3cf1c 100644 --- a/tests/test_main.c +++ b/tests/test_main.c @@ -32,6 +32,8 @@ int tf_skip_count = 0; #include #include #ifdef _WIN32 +#include +#include #include /* #798 follow-up: socket-isolation re-exec probe */ #else #include