Skip to content

CI: switch ThreadSanitizer to a gcc-based, fully instrumented build#554

Merged
dennisklein merged 13 commits into
devfrom
tsan-gcc
Jun 10, 2026
Merged

CI: switch ThreadSanitizer to a gcc-based, fully instrumented build#554
dennisklein merged 13 commits into
devfrom
tsan-gcc

Conversation

@dennisklein

@dennisklein dennisklein commented Jun 9, 2026

Copy link
Copy Markdown
Member

Closes #553.

The tsan job now compiles and links with gcc 15 (-fsanitize=thread) against a fully
tsan-instrumented dependency tree, and the suppressions file is gone. The full suite (188 tests)
runs green with zero suppressions.

Infrastructure

  • libstdcxx-tsan spack package (test/ci/spack_repo): gcc offers no supported switch to
    build libstdc++ with tsan and spack's gcc recipe owns the target-library flags outright, so the
    package builds only the libstdc++-v3 subtree from the matching gcc release tarball, configured
    standalone against the installed toolchain (~3 min build, cached in the buildcache).
  • Runtime substitution: the instrumented libstdc++ shares soname and symbol versions with the
    compiler's own and is selected via LD_LIBRARY_PATH per test (new FAIRMQ_TEST_LD_LIBRARY_PATH
    CMake variable) — per test on purpose, since the library carries unresolved __tsan_* symbols
    and must not be loaded into uninstrumented tools (cmake, ctest, ninja). An rpath cannot work
    here: spack-gcc's specs file injects its own rpath ahead of any user link flag.
  • test/ci/spack-tsan.yaml: mirrors spack-latest.yaml with -fsanitize=thread on the
    libzmq and libsodium nodes (per-node flags, no == propagation, so nothing can leak onto the
    gcc node). Unchanged roots keep their spec hashes and stay shared with the regular buildcache;
    libstdcxx-tsan is excluded from concretizer reuse so recipe changes always take effect.
  • ci.yml: tsan matrix entry drops clang++, -fuse-ld=lld and the lld install step;
    per-entry gcc/env keys (asan unchanged on gcc 14); a small permanent step asserts the
    instrumentation wiring, since its failure modes are silent.
  • buildcache: tsan env added to the matrix. Also fixes the push steps failing with
    PackageNotInstalledError whenever specs are satisfied from the cache (--allow-missing on
    both the gcc and the env push; a freshly built gcc still uploads its build-time deps for
    future rebuilds) — pre-existing, surfaced by the warm cache.

Findings (previously masked)

Removing the suppressions surfaced and fixed real issues:

  • fair::mq::tools::execute printed to std::cout from concurrent threads; libstdc++ keeps the
    formatted-output state (ios_base::width) in plain reads/writes, which only an instrumented
    libstdc++ can see — both accesses were invisible before.
  • SubscriptionThreadSafety test captured its loop counter by reference while the spawning loop
    kept incrementing it.
  • list(APPEND CMAKE_EXE_LINKER_FLAGS ...) in the project settings corrupted the link command
    with a semicolon as soon as anything passed linker flags externally.
  • libstdc++'s std::ctype<char> lazily caches narrow()/widen() per character with
    unsynchronized stores from header-inlined code — a true race under the memory model that no
    instrumentation can absolve; the test binaries now pre-fill the caches before threads exist
    (test/helper/LocaleWarmup.h), and Channel::Validate compiles its constant regex only once.

Definition of done from #553

  • tsan job on gcc: no clang, no -fuse-ld=lld, no lld install step
  • libzmq built with tsan instrumentation
  • libstdc++ tsan-instrumented (dedicated spack package)
  • transitive audit: libsodium instrumented; fairlogger/boost left uninstrumented (zero
    reports implicate them; instrumentable the same way if that changes)
  • suppressions file deleted, TSAN_OPTIONS wiring removed
  • tsan job green with zero suppressions and the full test suite running (188/188)

@coderabbitai

coderabbitai Bot commented Jun 10, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@dennisklein, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 8 minutes and 47 seconds. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more in the billing tab.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

We recommend that you space out your commits to avoid hitting the rate limit.

🚦 How do rate limits work?

CodeRabbit enforces hourly rate limits for each developer per organization.

Our paid plans include higher PR review limits than trial, open-source, and free plans. In all cases, reviews become available again over time. During sustained high-volume PR review activity, CodeRabbit may temporarily slow when the next review becomes available.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: aa467cfc-b792-4367-8639-eb92902c3af7

📥 Commits

Reviewing files that changed from the base of the PR and between 1603dc5 and 6cca61c.

📒 Files selected for processing (1)
  • .github/workflows/ci.yml
📝 Walkthrough

Walkthrough

This PR switches FairMQ's ThreadSanitizer CI job from clang to gcc using fully instrumented dependencies, eliminates the suppressions file, and adds libstdc++ locale cache warmup to prevent false-positive races from lazy initialization. The infrastructure includes a new spack tsan environment with a custom tsan-instrumented libstdc++ package.

Changes

ThreadSanitizer Fully-Instrumented Build and Integration

Layer / File(s) Summary
Spack tsan instrumented packages
test/ci/spack-tsan.yaml, test/ci/spack_repo/fairmq_ci/packages/libstdcxx_tsan/package.py, test/ci/spack_repo/fairmq_ci/repo.yaml
New spack environment specifies TSAN-instrumented specs (libzmq built with -fsanitize=thread, selection of libstdcxx-tsan runtime). Adds LibstdcxxTsan package building libstdc++-v3 with -fsanitize=thread and a repo manifest.
CI buildcache and spack repo infrastructure
.github/actions/setup-deps/action.yml, .github/workflows/buildcache.yml
Expose tsan env input description, add spack repo add for the fairmq_ci repo before environment creation, expand buildcache workflow trigger paths for test/ci/spack_repo/**, switch gcc:15 matrix entry to tsan, and pass --allow-missing to spack buildcache push with explanatory comments.
tsan CI job matrix and steps
.github/workflows/ci.yml, CMakeLists.txt
Sanitizers job matrix now includes per-sanitizer gcc, env, options, cxx-flags; tsan job locates spack-installed libstdcxx-tsan, sets FAIRMQ_TEST_LD_LIBRARY_PATH via GITHUB_ENV, uses sanitizer-name ccache keys, and verifies instrumented libstdc++ and libzmq symbols. Adds a CMake guard requiring CMake ≥ 3.22 when FAIRMQ_TEST_LD_LIBRARY_PATH is used.
libstdc++ locale cache warmup helper
test/helper/LocaleWarmup.h, test/helper/runTestDevice.cxx, test/runner.cxx.in, test/CMakeLists.txt
Adds WarmUpLocaleCaches() to pre-fill std::ctype<char> and iostream numeric caches and a LocaleWarmup static initializer; integrates it into test helpers and runner and makes per-test ENVIRONMENT conditional on env_mods/FAIRMQ_TEST_LD_LIBRARY_PATH and LSAN_OPTIONS.
Examples CTest env_mods propagation
examples/CMakeLists.txt, examples/custom-controller/CMakeLists.txt
Centralizes env_mods construction and applies ENVIRONMENT_MODIFICATION from it across example tests, replacing the prior lsan_options-only logic.
Build configuration and thread safety improvements
cmake/FairMQProjectSettings.cmake, fairmq/Channel.cxx, fairmq/tools/Process.cxx, test/plugin_services/_control.cxx
Switches linker flag concatenation to string(APPEND ...) with a leading space for -Wl,--enable-new-dtags, uses a static regex in Channel validation, serializes std::cout writes with a static mutex in LinePrinter::Print, and captures thread id by value in a subscription test lambda.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~25 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 25.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title 'CI: switch ThreadSanitizer to a gcc-based, fully instrumented build' is clear, concise, and accurately summarizes the primary change: replacing the clang-based tsan job with a gcc-based fully instrumented build that removes suppressions.
Description check ✅ Passed The PR description is comprehensive and directly related to the changeset, explaining the infrastructure changes, the rationale for using gcc with tsan, the new spack package for instrumented libstdc++, test findings that were fixed, and mapping to the definition of done from issue #553.
Linked Issues check ✅ Passed All objectives from issue #553 are met: tsan job uses gcc without clang/lld; libzmq and libsodium are tsan-instrumented; libstdc++ is instrumented via a dedicated spack package; suppressions file is deleted; TSAN_OPTIONS wiring is removed; full test suite runs green with zero suppressions; buildcache gets a tsan entry.
Out of Scope Changes check ✅ Passed All code changes are directly in scope for issue #553: CI infrastructure for tsan (workflows, spack configs, CMake environment handling), test utilities to preempt libstdc++ races (LocaleWarmup.h), bug fixes uncovered by instrumentation (Process.cxx stdout locking, SubscriptionThreadSafety capture), and linker-flag fixes (cmake/FairMQProjectSettings.cmake). No extraneous changes present.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.


Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@dennisklein dennisklein marked this pull request as ready for review June 10, 2026 15:16
@dennisklein

Copy link
Copy Markdown
Member Author

Note

This review was generated with Claude.

Verdict: approve with minor comments. The PR is correct in everything it actively does — no critical or major findings survived verification. All confirmed findings are robustness gaps at the edges (silent-failure modes, a coverage boundary) plus one stale comment.

What was verified correct (highlights)

  • Process.cxx cout mutex: fOut is provably single-threaded — all asio handlers run inside the one ioc.run() invocation, and concurrent execute() calls own distinct stringstreams. Locking only the cout write is exactly right.
  • LocaleWarmup: verified against gcc 15.2.0's locale_facets.h/ctype.cc — the signed-char loop is safe (unsigned-char indexing internally), widen() fully initializes via _M_widen_init, and the stream round-trip does install the numpunct caches.
  • CMake env plumbing: path_list_prepend:/set: land in ENVIRONMENT_MODIFICATION via cmake/GTestHelper.cmake:81, so the operators are valid. The list(APPEND)string(APPEND) linker-flags fix is correct.
  • CI: spack-bash runs with set -e -o pipefail (verified in spack/setup-spack@v3 source), so the verify step fails loudly in every broken scenario constructed. --allow-missing only skips specs that could never be pushed. Empty FAIRMQ_TEST_LD_LIBRARY_PATH= in the asan job is harmless.
  • Spack package: repo API v2 layout exact, both tarball checksums byte-identical to spack's builtin gcc package, URL substitution works for 14.3.0, the gthr-default.h trick is genuinely required by libstdc++-v3's configure-time gthreads probe, and reuse: exclude does what the comment claims.
  • Suppressions accounting: all nine deleted suppression entries have either a code fix or a credible instrumentation-based resolution; no dangling references anywhere in the tree.

Findings

Should fix before merge

  1. Stale comment — test/ci/spack-tsan.yaml:17. The comment says the instrumented libstdc++ is "selected via rpath on the test executables", but the mechanism everywhere else (ci.yml, package.py docstring, test/CMakeLists.txt) is the per-test LD_LIBRARY_PATH prepend — the ci.yml comment even explains why rpath can't work. Reword to "injected per test via LD_LIBRARY_PATH (see FAIRMQ_TEST_LD_LIBRARY_PATH in test/CMakeLists.txt)".

  2. Silent drop on CMake < 3.22 — test/ci/spack-tsan.yaml:21. The ENVIRONMENT_MODIFICATION mapping in cmake/GTestHelper.cmake:81 is guarded by CMAKE_VERSION >= 3.22 and silently skipped otherwise, while spack-tsan.yaml only requires cmake@3.15:. A concretizer picking 3.15–3.21 would give a green tsan job that runs every test against the uninstrumented libstdc++. Cheap fix: require cmake@3.22: in the env, and/or message(FATAL_ERROR ...) in test/CMakeLists.txt when FAIRMQ_TEST_LD_LIBRARY_PATH is set on an older CMake.

Worth considering

  1. gcc ↔ libstdcxx-tsan lockstep is comment-enforced only — ci.yml:134. Drift can happen without any repo change: the weekly fresh-concretization buildcache run will move gcc@15 to 15.3.0 when spack-packages picks it up, while libstdcxx-tsan stays at 15.2.0 (excluded from reuse, and 15.2.0 is the only 15.x in the recipe). If the newer compiler emits references to new GLIBCXX_* versions, every test dies at load with a cryptic version error; in the benign case the mismatch passes silently. The verify step won't catch it (ldd still resolves to the tsan prefix). Suggestion: assert spack find --format '{version}' libstdcxx-tsan equals g++ -dumpfullversion in the verify step.

  2. Verify step checks loader resolution, not ctest plumbing — ci.yml:140. It sets LD_LIBRARY_PATH manually for ldd, so it proves "if the path were set, the right library wins" but not that the property actually reaches the tests (the same silent-drop path as finding 2). ctest --test-dir build --show-only=json-v1 | grep -q libstdcxx-tsan would close the loop — test properties appear in that output.

  3. Example. tests lost the suppressions but got no replacement — examples/CMakeLists.txt:79*. The deleted suppressions were job-wide via TSAN_OPTIONS; the warmup and FAIRMQ_TEST_LD_LIBRARY_PATH cover only test/. Example binaries are tsan-instrumented (global Debug flags) and run in the same ctest invocation, so the ToString-class locale-cache races could in principle fire there — unsuppressed, unwarmed, uninstrumented runtime. The 188/188 green run says it hasn't fired in practice, but races are timing-dependent. Either extend the wiring or note in the job why examples are out of scope.

Take or leave

  1. Warmup misses _M_narrow_ok (test/helper/LocaleWarmup.h:30): the single-char narrow() fills the per-char cache but only the range overload calls _M_narrow_init() and sets the flag. No current code path calls the range overload (verified by grepping all libstdc++ header callers), so it's latent — one ct.narrow(from, from+256, '?', to) call would future-proof it.
  2. Pre-existing, adjacent: ENABLE_SANITIZER_UNDEFINED_BEHAVIOUR=ON in ci.yml (British spelling) never matched the CMake option ..._BEHAVIOR (cmake/FairMQProjectSettings.cmake:83) — the "asan+lsan+ubsan" job has never enabled UBSan. Not this PR's fault (dates to 2025-11-27), but it's a one-character fix in the block being edited; probably better as a separate PR since it'll likely surface new findings.
  3. Doc nit: spack-tsan.yaml explains the libzmq/libsodium instrumentation thoroughly but is silent on why boost/fairlogger stay uninstrumented — that rationale currently lives only in the PR description.

One claimed finding ("LSAN + FAIRMQ_TEST_LD_LIBRARY_PATH combined breaks test discovery") was refuted during verification — the two-entry ENVIRONMENT_MODIFICATION list flattens correctly through gtest_discover_tests.

- concurrent execute() calls print captured subprocess lines to
  std::cout from multiple threads; the standard allows that, but
  libstdc++ maintains the formatted-output state (ios_base::width)
  with plain reads and writes -- a data race ThreadSanitizer reports
  once libstdc++ itself is instrumented
- a mutex around the insertion also keeps whole lines from
  interleaving
- the subscriber threads captured the loop counter by reference while
  the spawning loop kept incrementing it: a genuine data race
- depending on timing, threads could also end up with duplicate
  subscriber names; capture the counter by value instead
- the pattern is constant; compiling it on every Validate() call is
  wasted work and, when channels are validated from multiple threads,
  needlessly exercises libstdc++'s lazily-populated ctype caches
- std::ctype<char> caches narrow()/widen() results per character in
  plain char arrays of the global classic-locale facet, written without
  synchronization from header-inlined code (locale_facets.h); two
  threads exercising an uncached character concurrently (e.g. compiling
  a std::regex in Channel::Validate) constitute a true data race that
  ThreadSanitizer rightfully reports
- the stores are real and unsynchronized, so a tsan-instrumented
  libstdc++ cannot help here; instead fill the caches before any thread
  is spawned, which turns every later access into a pure read
- warm the lazily-installed num_put/num_get caches used by stream
  insertion/extraction as well, via a small format/parse round-trip
- wire the warm-up into the gtest runner main() and, via a static
  initializer, into the test device runner
- CMAKE_EXE_LINKER_FLAGS and CMAKE_SHARED_LINKER_FLAGS are command-line
  strings; list(APPEND) inserts a semicolon once the variable is
  non-empty, which splits the link command at the shell level
- latent until now because nothing passed linker flags on the cmake
  command line
- introduce FAIRMQ_TEST_LD_LIBRARY_PATH, which prepends a directory to
  each test's environment via ctest, so the tests can run against an
  alternative runtime library (e.g. a tsan-instrumented libstdc++)
- LD_LIBRARY_PATH rather than an injected rpath: an rpath added via the
  linker flags cannot precede the rpath spack's gcc adds through its
  specs file, so the compiler's own libstdc++ would keep winning the
  runtime search order
- scoped per test on purpose: an instrumented library has unresolved
  __tsan_* symbols and must not be loaded into uninstrumented tools
  like cmake, ctest or ninja
- fail the configuration instead of silently dropping the injection on
  CMake < 3.22 (ENVIRONMENT_MODIFICATION)
- cover the example tests too; they share the instrumented runtime but
  not the locale-cache warmup (their main() is the installed public
  header). The custom-controller env block was dead before: it tested
  lsan_options, which only ever existed in the add_example() function
  scope, so the test also never received the LSan suppressions
- buildcache push expands its selection into the full dependency
  closure, build-time dependencies included; specs that were satisfied
  from the buildcache do not have those installed locally, and the push
  fails with PackageNotInstalledError
- both push sites (the early gcc node push and the env-level push) only
  ever ran in fresh-build scenarios before, so the failure surfaced once
  the cache was warm
- pass --allow-missing to skip what is not installed (a best-effort push
  of everything that is); a freshly built gcc thus still uploads its
  build-time dependencies, which a future gcc rebuild can then pull as
  binaries
- gcc ships no supported switch to build libstdc++ with -fsanitize=thread,
  and spack's gcc recipe filters all flags out of the target-library build
  (CXXFLAGS_FOR_TARGET is owned by its generated --with-build-config=spack
  makefile), so provide a dedicated libstdcxx-tsan package in a custom repo
- build only the libstdc++-v3 subtree from the matching gcc release tarball,
  configured standalone against the already-installed toolchain (recipe
  modeled on https://iree.dev/developers/debugging/sanitizers/), instead of
  rebuilding all of gcc
- the result is a drop-in runtime replacement for the compiler's libstdc++
  (same soname and symbol versions), to be loaded only by the instrumented
  test executables
- normalize the install layout after make install: the standalone build puts
  the runtime libraries into the multilib os dir (lib64 on x86_64) regardless
  of --libdir, and --with-toolexeclibdir only applies to cross builds
- register the repo in the setup-deps action before creating the env
- mirror spack-latest.yaml, with -fsanitize=thread on the libzmq and
  libsodium nodes so tsan can observe the happens-before edges established
  inside libzmq's lock-free queues, plus the libstdcxx-tsan root spec
- flags are applied per node instead of via the propagating '==' operator,
  which could reach the gcc node and trigger a compiler rebuild
- unchanged roots (fairlogger, boost, ninja, cmake) keep their spec hashes,
  so they are shared with the regular buildcache entries; the instrumented
  nodes hash differently and coexist in the content-addressed cache
- exclude libstdcxx-tsan from concretizer reuse so recipe changes always
  take effect; unchanged recipes still hit the buildcache because the spec
  hash is identical
- add the tsan env to the buildcache matrix (rebuilding also on spack_repo
  changes) so the instrumented binaries are cached instead of rebuilt on
  every CI run

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In @.github/workflows/ci.yml:
- Line 103: Replace tag-only GitHub Action refs with full commit SHAs: find each
occurrence of "hendrikmuhs/ccache-action@v1" and "threeal/cmake-action@v2" in
the workflow and pin them to the corresponding commit SHA (e.g.,
"hendrikmuhs/ccache-action@<full-sha>" and "threeal/cmake-action@<full-sha>");
update all instances (the three "hendrikmuhs/ccache-action@v1" entries and the
two "threeal/cmake-action@v2" entries) so the workflow uses the exact commit
SHAs instead of tag-only refs.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 125301c7-b51b-433c-bce3-26c57eae3050

📥 Commits

Reviewing files that changed from the base of the PR and between 5abb7f0 and 80d575c.

📒 Files selected for processing (18)
  • .github/actions/setup-deps/action.yml
  • .github/workflows/buildcache.yml
  • .github/workflows/ci.yml
  • CMakeLists.txt
  • cmake/FairMQProjectSettings.cmake
  • examples/CMakeLists.txt
  • examples/custom-controller/CMakeLists.txt
  • fairmq/Channel.cxx
  • fairmq/tools/Process.cxx
  • test/CMakeLists.txt
  • test/ci/spack-tsan.yaml
  • test/ci/spack_repo/fairmq_ci/packages/libstdcxx_tsan/package.py
  • test/ci/spack_repo/fairmq_ci/repo.yaml
  • test/helper/LocaleWarmup.h
  • test/helper/runTestDevice.cxx
  • test/plugin_services/_control.cxx
  • test/runner.cxx.in
  • test/thread_sanitizer_suppressions.txt
💤 Files with no reviewable changes (1)
  • test/thread_sanitizer_suppressions.txt
✅ Files skipped from review due to trivial changes (2)
  • cmake/FairMQProjectSettings.cmake
  • test/ci/spack_repo/fairmq_ci/repo.yaml
🚧 Files skipped from review as they are similar to previous changes (9)
  • test/helper/runTestDevice.cxx
  • test/CMakeLists.txt
  • .github/actions/setup-deps/action.yml
  • test/plugin_services/_control.cxx
  • fairmq/tools/Process.cxx
  • test/helper/LocaleWarmup.h
  • fairmq/Channel.cxx
  • test/runner.cxx.in
  • test/ci/spack-tsan.yaml

Comment thread .github/workflows/ci.yml Outdated
- build with the spack gcc toolchain like every other job: no clang++, no
  -fuse-ld=lld and no lld install step (the GNU BFD failure on tsan objects
  was specific to clang's tsan runtime)
- use gcc 15 for the freshest libtsan runtime; the asan entry stays on
  gcc 14, so the matrix now carries per-entry gcc and spack env names
- consume the tsan spack env and load the instrumented libstdc++ into each
  test's environment via FAIRMQ_TEST_LD_LIBRARY_PATH (it shares the soname
  of the compiler's own, so it substitutes process-wide at load time)
- use -fno-omit-frame-pointer for readable reports; optimization comes
  from the project's Debug -Og
- verify the wiring: assert the test environment resolves libstdc++ to the
  instrumented copy and that libzmq is tsan-instrumented, since both
  failure modes are silent (the suite still passes, with reduced race
  coverage)
- every entry stood in for a library tsan could not see into; with libzmq,
  libsodium and libstdc++ now tsan-instrumented in the tsan CI job, the
  happens-before edges they establish are visible and nothing is left to
  suppress
- suppressions were blunt (a race: entry matches any frame in the stack),
  so they could also mask real races passing through those frames
- ENABLE_SANITIZER_UNDEFINED_BEHAVIOUR never matched the CMake option
  ENABLE_SANITIZER_UNDEFINED_BEHAVIOR (cmake/FairMQProjectSettings.cmake),
  so the asan+lsan+ubsan job has never actually enabled UBSan
- hendrikmuhs/ccache-action: the v1 major tag also lagged behind the
  latest release (v1.2.20 instead of v1.2.23), so this is a bump too
- threeal/cmake-action: v2 == v2.1.0, pinned as-is
@dennisklein dennisklein merged commit a34fa64 into dev Jun 10, 2026
10 checks passed
@dennisklein dennisklein deleted the tsan-gcc branch June 10, 2026 17:31
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