You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Nothing in the bank example is ever built with a sanitizer. Not the GUI, not bank_lib, not bank_tests. So #663 — a double → std::int64_t conversion that UBSan diagnoses in one line, on the path of every amount typed into the bank GUI — could not have been caught by any leg, however many times it ran.
examples/bank/CMakeLists.txt is not the problem: it calls apply_sanitizers(ladder_bank_server ${AF_SANITIZER}) when the variable is defined, and examples/bank/gui/CMakeLists.txt follows the same pattern. The option is simply never on in a sanitizer configure.
Verified by reading the three configures
Grep for the flag across every workflow, on 563502ab:
None of those five sites is a sanitizer leg, and the two jobs that are:
linux-sanitizers (ci.yml:388), matrix [clang-asan, clang-tsan, clang-ubsan], configures -DMORPH_BUILD_NET=ON -DMORPH_BUILD_OFFLINE_SQLITE=ON and nothing else. No bank, no ladder.
ladder-sanitizers (ci.yml:1446), configures clang-asan with -DMORPH_BUILD_QT=ON -DMORPH_BUILD_LADDER=ON -DMORPH_LADDER_RUNGS=all. Bank is deliberately not a rung — it is absent from examples/rungs.txt and never calls morph_add_rung() (see examples/bank/CMakeLists.txt's own long comment on why) — so MORPH_BUILD_LADDER=ON does not reach it.
apply_sanitizers is -fsanitize=address,undefined for the asan mode (cmake/compiler_options.cmake), so an ASan leg that included bank would carry UBSan with it and would have flagged #663 on the first amount any test parsed.
What it would have cost
Measured locally on a 12-core box, clang 22.1.8, Qt 6.11.2, cold build directory: cmake --build build/clang-debug --target bank_gui_tests from a configured tree is 63s wall / 334s CPU, 80 ninja edges, of which the vendored Lightweight ORM is the bulk. The configure that produces it is 70s. So this is a real cost on a hosted runner, not a free addition — which is presumably why it was never on, and is the thing a fix has to weigh rather than assume.
That leaves at least three shapes, and choosing between them is the work:
add -DMORPH_BUILD_BANK_EXAMPLE=ON -DMORPH_BUILD_BANK_GUI=ON to linux-sanitizers' clang-ubsan leg only — UBSan is what catches this class, and it avoids paying the ORM build three times;
a separate bank-sanitizers job, mirroring kanban-tsan's precedent of splitting one expensive suite out of the matrix;
decide bank is out of sanitizer scope deliberately and write that down, the way examples/bank/CMakeLists.txt already writes down why bank is not a rung.
Verification status
Reproduced: the grep above and the two sanitizer jobs' configure flags, read from ci.yml on 563502ab. The build cost is a real local measurement, not an estimate.
Not verified: whether turning bank on in a sanitizer leg surfaces other pre-existing findings. It very likely does — bank_lib has never been instrumented — and that backlog is the real cost of option 1 or 2. I did not build it under a sanitizer to find out, and whoever takes this should measure that before committing to a shape.
Not verified: whether the ORM itself is sanitizer-clean. bank_lib deliberately skips apply_warnings() because the vendored ORM headers are not -Werror clean; whether the same is true of its runtime behaviour under ASan/UBSan is unknown.
What would change the verdict
Close as invalid if a leg does instrument bank and I misread its flags. Close as wontfix if the considered answer is option 3 — but then examples/bank/CMakeLists.txt should say so beside the apply_sanitizers call it currently makes, because that call reads today as though it were reachable from CI and it is not.
Raised by #663's filer and by its triage ("Worth its own ticket if it is not already covered; I have not checked whether the sanitizer legs' option set is deliberate or incidental"). Checked here: it is incidental, not written down anywhere. Found while working #663 (PR #676). Filed, not folded.
The gap
Nothing in the bank example is ever built with a sanitizer. Not the GUI, not
bank_lib, notbank_tests. So #663 — adouble→std::int64_tconversion that UBSan diagnoses in one line, on the path of every amount typed into the bank GUI — could not have been caught by any leg, however many times it ran.examples/bank/CMakeLists.txtis not the problem: it callsapply_sanitizers(ladder_bank_server ${AF_SANITIZER})when the variable is defined, andexamples/bank/gui/CMakeLists.txtfollows the same pattern. The option is simply never on in a sanitizer configure.Verified by reading the three configures
Grep for the flag across every workflow, on
563502ab:None of those five sites is a sanitizer leg, and the two jobs that are:
linux-sanitizers(ci.yml:388), matrix[clang-asan, clang-tsan, clang-ubsan], configures-DMORPH_BUILD_NET=ON -DMORPH_BUILD_OFFLINE_SQLITE=ONand nothing else. No bank, no ladder.ladder-sanitizers(ci.yml:1446), configuresclang-asanwith-DMORPH_BUILD_QT=ON -DMORPH_BUILD_LADDER=ON -DMORPH_LADDER_RUNGS=all. Bank is deliberately not a rung — it is absent fromexamples/rungs.txtand never callsmorph_add_rung()(seeexamples/bank/CMakeLists.txt's own long comment on why) — soMORPH_BUILD_LADDER=ONdoes not reach it.apply_sanitizersis-fsanitize=address,undefinedfor theasanmode (cmake/compiler_options.cmake), so an ASan leg that included bank would carry UBSan with it and would have flagged #663 on the first amount any test parsed.What it would have cost
Measured locally on a 12-core box, clang 22.1.8, Qt 6.11.2, cold build directory:
cmake --build build/clang-debug --target bank_gui_testsfrom a configured tree is 63s wall / 334s CPU, 80 ninja edges, of which the vendored Lightweight ORM is the bulk. The configure that produces it is 70s. So this is a real cost on a hosted runner, not a free addition — which is presumably why it was never on, and is the thing a fix has to weigh rather than assume.That leaves at least three shapes, and choosing between them is the work:
-DMORPH_BUILD_BANK_EXAMPLE=ON -DMORPH_BUILD_BANK_GUI=ONtolinux-sanitizers'clang-ubsanleg only — UBSan is what catches this class, and it avoids paying the ORM build three times;bank-sanitizersjob, mirroringkanban-tsan's precedent of splitting one expensive suite out of the matrix;examples/bank/CMakeLists.txtalready writes down why bank is not a rung.Verification status
ci.ymlon563502ab. The build cost is a real local measurement, not an estimate.1e30in any amount field is UB #663 when bank is instrumented — a hand-built-fsanitize=undefined -fno-sanitize-recover=undefinedbinary over the pre-fix header givesruntime error: 1e+32 is outside the range of representable values of type 'long'.bank_libhas never been instrumented — and that backlog is the real cost of option 1 or 2. I did not build it under a sanitizer to find out, and whoever takes this should measure that before committing to a shape.bank_libdeliberately skipsapply_warnings()because the vendored ORM headers are not-Werrorclean; whether the same is true of its runtime behaviour under ASan/UBSan is unknown.What would change the verdict
Close as
invalidif a leg does instrument bank and I misread its flags. Close aswontfixif the considered answer is option 3 — but thenexamples/bank/CMakeLists.txtshould say so beside theapply_sanitizerscall it currently makes, because that call reads today as though it were reachable from CI and it is not.Raised by #663's filer and by its triage ("Worth its own ticket if it is not already covered; I have not checked whether the sanitizer legs' option set is deliberate or incidental"). Checked here: it is incidental, not written down anywhere. Found while working #663 (PR #676). Filed, not folded.
🤖 Generated with Claude Code
https://claude.ai/code/session_01VptDWG2fKr2vBnLSJcgzgW