Skip to content

feat(engine): UBSan gate blocking + clang-tidy baseline (E2 slice 1)#15

Merged
dnplkndll merged 2 commits into
modernizationfrom
engine-e2s1-harden-ci-gates
Jun 18, 2026
Merged

feat(engine): UBSan gate blocking + clang-tidy baseline (E2 slice 1)#15
dnplkndll merged 2 commits into
modernizationfrom
engine-e2s1-harden-ci-gates

Conversation

@dnplkndll

@dnplkndll dnplkndll commented Jun 18, 2026

Copy link
Copy Markdown

What changed

The mechanical close-out of Engine track E1's static-analysis gate: make the UBSan gate blocking and add a clang-tidy baseline. Both sanitizers are now blocking + clean; static analysis is wired and reporting.

UBSan → blocking

The advisory baseline (#14) left exactly 2 distinct UBSan sites across the entire golden suite (post-merge advisory run: 156 occurrences, timeline.h:293 ×78 and model.h:8667 ×78) — both the iterator operator* null-binding idiom: a reference formed to a null end() sentinel that's never dereferenced (same UB the standard library has for *v.end()).

  • Both operator* are marked FREPPLE_NO_SANITIZE_NULL — a new __attribute__((no_sanitize("null"))) macro in utils.h (GCC/Clang, no-op in normal builds; g++ has no runtime-suppressions file so the attribute is the portable route). The full golden suite is then UBSan-clean.
  • engine-ubsan.yml flips to halt_on_error=1 + abort — a new UB site now fails CI, same contract as engine-asan.yml.

Verified locally (ubuntu g++ container): the attribute compiles with no warning, 0 UBSan findings remain across the timeline/problem-list/forecast-heavy tests + the operationdependency path.

clang-tidy baseline (E1 gate item 3)

  • .clang-tidy — bug-finders only: clang-analyzer-* + high-signal bugprone-*; style/readability/modernize off, plus the two noisy checks (unhandled-self-assignment, exception-escape) excluded.
  • engine-clang-tidy.yml — advisory gate (parse-only, never fails), runs on PRs into modernization + push, reports findings and uploads the report.
  • Baseline (full src/, 57 TUs): 54 distinct findings (the raw line count over-states it ~3× because HeaderFilterRegex re-reports a header finding per including TU). The ~10 high-signal items — NullDereference, CallAndMessage, integer-division, NewDelete, uninitialised reads — are the E2 triage work-list before the gate tightens to "no new findings".

Docs

  • ubsan-baseline.md: Finding 2 resolved, gate posture → blocking.
  • clang-tidy-baseline.md: new — config rationale, the real distinct-finding breakdown, advisory→blocking path.
  • MODERNIZATION_PLAN.md: E1 gate — sanitizer + clang-tidy items checked (the engine review report is the one open E1 item).

Self-review fixes (2nd commit)

A bugbot-style pass on my own clang-tidy gate caught two bugs, fixed in fix(ci): clang-tidy gate - per-file logs + distinct-finding dedup:

  • Interleaving: parallel clang-tidy processes shared one redirect → garbled lines. Now each TU writes its own log, then concatenated.
  • Misleading count: header findings counted once per including TU → "1076" was meaningless. Now deduped to distinct findings (54) in the summary, raw shown alongside.

Validation

  • -DFREPPLE_SANITIZER=undefined Debug build with the annotations: compiles clean (no attribute warning), representative suite 0 UBSan findings.
  • clang-tidy: config parses, 57 TUs analyze, dedup verified end-to-end (57 TUs → 54 distinct).
  • build (ubuntu24 ×2) green on the PR — macro + annotations compile in Release, golden output unchanged. The blocking engine-ubsan/engine-asan gates run post-merge on modernization (the prior advisory run already proved those were the only 2 sites).
  • No UI surface in this change → no PR screenshots.

Note

Per convention, not auto-merging — needs your go-ahead. After this, E1 has just the engine review report left; E2 proper (pegging tests 2→12, structural-invariant assertions, stress baseline, clang-tidy diff-gate) is the larger follow-on.

Harden the engine CI gates - the mechanical close-out of Engine track E1's
static-analysis gate.

UBSan -> blocking:
- The advisory baseline's only remaining findings were the iterator operator*
  null-binding idiom (timeline.h:293, model.h:8667) - a reference formed to a
  null end()-sentinel that is never dereferenced (same UB as *v.end()). Mark
  both with FREPPLE_NO_SANITIZE_NULL (new no_sanitize("null") macro in utils.h;
  g++/clang, no-op in normal builds), leaving the full golden suite UBSan-clean.
- engine-ubsan.yml flips to halt_on_error=1 + abort - a new UB site now fails
  CI, the same contract as engine-asan. Verified locally: g++ accepts the
  attribute (no warning) and 0 findings remain across the timeline/problem/
  forecast-heavy tests.

clang-tidy baseline (E1 gate item 3):
- .clang-tidy: bug-finder check set (clang-analyzer-* + high-signal bugprone-*),
  style/readability off; the two noisy checks (unhandled-self-assignment,
  exception-escape) excluded.
- engine-clang-tidy.yml: advisory gate (parse-only, never fails) that reports
  the finding count + breakdown and uploads the report. Tightens to "no new
  findings on changed files" in E2.

Docs: ubsan-baseline.md updated (Finding 2 resolved, gate now blocking);
clang-tidy-baseline.md added; MODERNIZATION_PLAN E1 gate - sanitizer + tidy
items checked (review report still open).
Self-review of the advisory clang-tidy gate caught two issues:

- Parallel clang-tidy processes all redirected to the same clang-tidy.out;
  concurrent writes can interleave and garble lines. Write each TU's output to
  its own log under .tidy-logs/, then concatenate.
- The reported "1076 warnings" was meaningless: with HeaderFilterRegex a header
  finding is emitted once per including TU. Dedup by the warning line
  (path:line:col + check, byte-identical across TUs) so the summary reports
  DISTINCT findings (54) alongside the raw count (~182), with a deduped
  per-check breakdown.

Update clang-tidy-baseline.md with the real full-src numbers (54 distinct) and
the actual breakdown - the ~10 high-signal triage items (NullDereference,
CallAndMessage, integer-division, NewDelete, uninitialised) are the E2 work-list.
@dnplkndll dnplkndll merged commit 5074c50 into modernization Jun 18, 2026
7 checks passed
@dnplkndll dnplkndll deleted the engine-e2s1-harden-ci-gates branch June 18, 2026 12:55
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant