Skip to content

Commit 2aec284

Browse files
committed
ci(sanitizer): das scharfe Tor konnte mit acht von neun Tests gruen melden (MF-1110)
P3-375 fragte, ob die Sanitizer-Stufen wirklich messen, was sie zu messen behaupten. Die Frage hatte DREI Teile. Zwei sind jetzt gemessen und geschlossen, einer bleibt offen und ist als solcher benannt. (1) UEBERSCHREIBT EIN TESTZIEL DIE INSTRUMENTIERUNG? NEIN. Gemessen: die Flaggen stehen global in `CMAKE_C_FLAGS`, `CMAKE_CXX_FLAGS` und `CMAKE_EXE_LINKER_FLAGS`. `tests/CMakeLists.txt` hat SECHS `target_compile_options`-Stellen, und alle sechs sind ADDITIV (`-UNDEBUG`, Warnungen, `-O3`) - keine setzt `-fno-sanitize`, keine ersetzt die globalen Flaggen; `PRIVATE`-Optionen haengen in CMake an. Kein Ziel linkt gegen eine vorgebaute Bibliothek (0 `IMPORTED`). Das ist eine ENTLASTENDE Messung, und sie gehoert genauso notiert wie ein Befund. (2) DIE EIGENTLICHE LUECKE LAG WOANDERS - UND SIE IST GESCHLOSSEN. Beide scharfen Stufen waehlen ihre Prueflinge ueber ctest --no-tests=error --tests-regex "test_a|test_b|..." mit NEUN namentlich genannten Tests. `--no-tests=error` feuert aber NUR, wenn die Regex GAR KEINEN Test trifft. Faellt einer der neun weg - umbenannt, nach `EXCLUDED_TESTS` gewandert, oder in CI schlicht nicht uebersetzt, weil der Bauschritt darueber `cmake --build ... || true` traegt -, dann laeuft das Tor mit ACHT und meldet GRUEN. Niemand zaehlte. Das ist die Gestalt von MF-1000 / Tor 64: ein Tor, das schmaler ist als sein Gegenstand, meldet zuverlaessig Erfolg. Und es ist zugleich die Aufzaehlungs-Klasse aus CLAUDE.md, die dieser Baum viermal bezahlt hat (MF-567/578/598/633). Zwei Haelften schliessen sie: * Im Workflow, VOR jedem der beiden scharfen Tore, ein eigener Zaehlschritt. Die Sollzahl ist aus der Regex ABGELEITET (Zahl der `|`-Alternativen) statt danebengeschrieben - eine zweite gepflegte Zahl waere genau die Drift, die der Schritt verhindern soll (MF-1077). Lokal abgenommen gegen das echte Build-Verzeichnis: `9 von 9` gruen, mit einem erfundenen zehnten Namen `9 von 10` ROT. * Im Baum `scripts/audit_tor_abdeckung.py`: es liest die Liste AUS DEM WORKFLOW statt eine zweite Kopie zu fuehren, prueft je Name Quelle und `EXCLUDED_TESTS`, und verlangt, dass BEIDE Stufen dieselbe Liste tragen. Selbsttest 13/13, Livelauf 0 Befunde; eingebunden in `check_consistency.py` nach dem Muster der 56 vorhandenen Tore. Rotbeweis am ECHTEN Workflow-Text, nicht an erfundenen Eingaben: ein umbenannter Name ergibt 1 Befund, eine nur in EINER Stufe geaenderte Liste 2 Befunde samt Drift-Meldung. UND DAS TOR HAT IM SELBEN COMMIT DIE EIGENE AENDERUNG GEFANGEN Seine erste Fassung griff jede `--tests-regex`-Zeile - und wurde damit sofort rot an dem Zaehlschritt, den dieser Commit einfuehrt: der ruft `ctest -N --tests-regex "$REGEX"`, und `$REGEX` ist kein Testname. Gemessen meldete es "6 Zeilen, 2 verschiedene Listen". Seither ueberspringt es Shell-Variablen UND liest zusaetzlich die `REGEX="..."`-Zuweisung, damit keine Liste aus der Messung faellt. Drei Zusagen im Selbsttest nageln genau das fest, darunter die Gegenprobe, dass Zuweisung plus Referenz GENAU EINE Liste ergeben. (3) WAS OFFEN BLEIBT, UND WARUM Ob das gebaute Binaerobjekt die Sanitizer-Laufzeit wirklich GEBUNDEN hat (`ldd | grep -E 'asan|ubsan'`). Das ist hier nicht messbar: MinGW hat keine libasan/libubsan, und die WSL2-Umgebung dieser Maschine hat keinen C++-Uebersetzer (`cc1plus` fehlt) - ein Paket nachzuinstallieren war nicht beauftragt. Aus (1) folgt, dass die Flaggen jedes Ziel ERREICHEN. Dass sie auch BINDEN, ist damit plausibel und ungemessen, und genau diese Unterscheidung ist der Punkt von P3-375. Sie steht dort so. Kennzahl: "leckende Tests null halten" - Teil (2) ist die Voraussetzung dafuer, dass diese Zahl ueberhaupt eine Aussage traegt. Claude-Session: https://claude.ai/code/session_01BHdqfaZ5RFb1HPcw7NYoEY
1 parent f3356f2 commit 2aec284

4 files changed

Lines changed: 322 additions & 1 deletion

File tree

.github/workflows/sanitizers.yml

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,33 @@ jobs:
7979
# Speicher-FEHLER sind etwas anderes als Speicher-Verlust; die
8080
# ersten werden hier scharf geprueft, die zweiten weiter unten
8181
# gemeldet.
82+
# ─────────────────────────────────────────────────────────────────
83+
# MF-1110 — VOR dem Tor zaehlen, wie viele Prueflinge es ueberhaupt
84+
# hat. `--no-tests=error` unten feuert NUR, wenn die Regex GAR
85+
# KEINEN Test trifft. Faellt einer von neun weg — umbenannt, in
86+
# EXCLUDED_TESTS gewandert, oder schlicht nicht uebersetzt, weil
87+
# der Bauschritt darueber `|| true` traegt —, dann laeuft das Tor
88+
# mit ACHT und meldet GRUEN. Niemand zaehlt.
89+
#
90+
# Die Sollzahl wird aus der Regex ABGELEITET (Zahl der
91+
# `|`-Alternativen), nicht danebengeschrieben: eine zweite
92+
# gepflegte Zahl waere genau die Drift, die das hier verhindern
93+
# soll (MF-1077). Die statische Haelfte — existieren die Namen
94+
# ueberhaupt noch? — haelt `scripts/audit_tor_abdeckung.py`.
95+
- name: Gate coverage — all named tests present (ARMED)
96+
run: |
97+
cd build
98+
REGEX="test_convert_roundtrip_measured|test_convert_identity_lossless|test_track_add_sector_owns_copies|test_convert_fuzz|test_convert_roundtrip_lossless|test_disk_open_fuzz|test_disk_write_fuzz|test_dsk_open_bounds|test_format_probe_fuzz"
99+
SOLL=$(printf '%s' "$REGEX" | tr '|' '\n' | grep -c .)
100+
IST=$(ctest -N --tests-regex "$REGEX" | grep -cE '^[[:space:]]+Test[[:space:]]+#') || true
101+
echo "scharfes ASan-Tor: $IST von $SOLL Prueflingen registriert"
102+
if [ "$IST" -ne "$SOLL" ]; then
103+
echo "::error::Das scharfe Tor haette mit $IST statt $SOLL Tests laufen und GRUEN melden koennen."
104+
echo "Registriert sind:"
105+
ctest -N --tests-regex "$REGEX" | grep -E '^[[:space:]]+Test[[:space:]]+#' || true
106+
exit 1
107+
fi
108+
82109
- name: Memory-safety gate — open path (ARMED)
83110
run: |
84111
cd build
@@ -165,6 +192,24 @@ jobs:
165192
cmake --build build --parallel $(nproc) 2>&1 || true
166193
# GUI may fail (missing headers) — tests are what matters
167194
195+
# MF-1110 — dieselbe Zaehlung wie im ASan-Auftrag; die Begruendung
196+
# steht dort. Sie gehoert in BEIDE Auftraege, weil jeder seinen
197+
# eigenen Bau hat und ein Ziel im einen uebersetzen kann und im
198+
# anderen nicht.
199+
- name: Gate coverage — all named tests present (ARMED)
200+
run: |
201+
cd build
202+
REGEX="test_convert_roundtrip_measured|test_convert_identity_lossless|test_track_add_sector_owns_copies|test_convert_fuzz|test_convert_roundtrip_lossless|test_disk_open_fuzz|test_disk_write_fuzz|test_dsk_open_bounds|test_format_probe_fuzz"
203+
SOLL=$(printf '%s' "$REGEX" | tr '|' '\n' | grep -c .)
204+
IST=$(ctest -N --tests-regex "$REGEX" | grep -cE '^[[:space:]]+Test[[:space:]]+#') || true
205+
echo "scharfes UBSan-Tor: $IST von $SOLL Prueflingen registriert"
206+
if [ "$IST" -ne "$SOLL" ]; then
207+
echo "::error::Das scharfe Tor haette mit $IST statt $SOLL Tests laufen und GRUEN melden koennen."
208+
echo "Registriert sind:"
209+
ctest -N --tests-regex "$REGEX" | grep -E '^[[:space:]]+Test[[:space:]]+#' || true
210+
exit 1
211+
fi
212+
168213
# SCHARF (MF-517) — siehe die Begruendung im ASan-Auftrag oben.
169214
- name: UB gate — open path (ARMED)
170215
run: |

0 commit comments

Comments
 (0)