From 8e7e595aae94beecc233b02b9269932ca1d5e55a Mon Sep 17 00:00:00 2001 From: "rahul.singh" Date: Wed, 25 Mar 2026 06:07:50 +0100 Subject: [PATCH 1/3] fix review comments: fix clang-tidy yaml and remove issue templates --- .github/PULL_REQUEST_TEMPLATE/improvement.md | 2 +- MODULE.bazel | 8 +- README.md | 1 + clang_tidy/.clang-tidy | 39 ++++++ clang_tidy/BUILD.bazel | 20 +++ clang_tidy/README.md | 56 ++++++++ clang_tidy/clang_tidy.bazelrc | 19 +++ clang_tidy/defs.bzl | 79 +++++++++++ sanitizers/BUILD.bazel | 9 +- sanitizers/README.md | 131 ++++++++++++++++++ sanitizers/private/BUILD.bazel | 7 +- sanitizers/sanitizers.bazelrc | 25 ++-- sanitizers/suppressions/lsan.supp | 8 -- .../templates/asan_ubsan_lsan.env.template | 4 +- sanitizers/templates/tsan.env.template | 2 +- tests/.bazelrc | 11 +- tests/.clang-tidy | 27 ++++ tests/BUILD.bazel | 16 ++- tests/MODULE.bazel | 22 +-- tests/tools/lint/BUILD.bazel | 17 +++ tests/tools/lint/linters.bzl | 23 +++ 21 files changed, 477 insertions(+), 49 deletions(-) create mode 100644 clang_tidy/.clang-tidy create mode 100644 clang_tidy/BUILD.bazel create mode 100644 clang_tidy/README.md create mode 100644 clang_tidy/clang_tidy.bazelrc create mode 100644 clang_tidy/defs.bzl create mode 100644 sanitizers/README.md create mode 100644 tests/.clang-tidy create mode 100644 tests/tools/lint/BUILD.bazel create mode 100644 tests/tools/lint/linters.bzl diff --git a/.github/PULL_REQUEST_TEMPLATE/improvement.md b/.github/PULL_REQUEST_TEMPLATE/improvement.md index 090ad43..7c992be 100644 --- a/.github/PULL_REQUEST_TEMPLATE/improvement.md +++ b/.github/PULL_REQUEST_TEMPLATE/improvement.md @@ -13,7 +13,7 @@ ## Related ticket > [!IMPORTANT] -> Please replace `[ISSUE-NUMBER]` with the issue-number that tracks this bug fix. If there is no such +> Please replace `[ISSUE-NUMBER]` with the issue-number that tracks this improvement. If there is no such > ticket yet, create one via [this issue template](../ISSUE_TEMPLATE/new?template=improvement.md). closes [ISSUE-NUMBER] (improvement ticket) diff --git a/MODULE.bazel b/MODULE.bazel index ac5b607..032f1a3 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -11,9 +11,15 @@ # SPDX-License-Identifier: Apache-2.0 # ******************************************************************************* -module(name = "score_cpp_policies") +module( + name = "score_cpp_policies", + version = "0.0.0", +) bazel_dep(name = "bazel_skylib", version = "1.8.2") bazel_dep(name = "platforms", version = "0.0.10") bazel_dep(name = "rules_cc", version = "0.1.5") +bazel_dep(name = "rules_shell", version = "0.6.1") + +bazel_dep(name = "aspect_rules_lint", version = "2.5.0") diff --git a/README.md b/README.md index 707ea02..58470dc 100644 --- a/README.md +++ b/README.md @@ -103,6 +103,7 @@ cd tests bazel test --config=asan_ubsan_lsan //... bazel test --config=tsan //... +bazel test --config=clang-tidy //... ``` ## Contributing diff --git a/clang_tidy/.clang-tidy b/clang_tidy/.clang-tidy new file mode 100644 index 0000000..8e5a61e --- /dev/null +++ b/clang_tidy/.clang-tidy @@ -0,0 +1,39 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +--- +# Default clang-tidy configuration for S-CORE C++ modules. +# NOTE: the set of enabled checks is yet subject to be tailored per module. +Checks: >- + -*, + clang-analyzer-*, + cert-*, + cppcoreguidelines-*, + bugprone-*, + misc-*, + performance-*, + readability-*, + modernize-* + +# NOTE: WarningsAsErrors is yet subject to be expanded per module as compliance increases. +WarningsAsErrors: >- + clang-analyzer-* + +# Exclude third-party and generated headers from analysis. +HeaderFilterRegex: '^(?!.*/third_party/).*' + +FormatStyle: file + +# NOTE: CheckOptions are yet subject to be provided for each enabled check per module. +#CheckOptions: +# none yet diff --git a/clang_tidy/BUILD.bazel b/clang_tidy/BUILD.bazel new file mode 100644 index 0000000..b8dbb4f --- /dev/null +++ b/clang_tidy/BUILD.bazel @@ -0,0 +1,20 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +exports_files( + [ + ".clang-tidy", + "clang_tidy.bazelrc", + ], + visibility = ["//visibility:public"], +) diff --git a/clang_tidy/README.md b/clang_tidy/README.md new file mode 100644 index 0000000..4113c6c --- /dev/null +++ b/clang_tidy/README.md @@ -0,0 +1,56 @@ +# Clang-Tidy Integration + +Centralized clang-tidy configuration and Bazel macros for Eclipse S-CORE C++ modules. + +## What This Provides + +- **`//clang_tidy:defs.bzl`** — `make_clang_tidy_aspect` / `make_clang_tidy_test` macros wrapping `aspect_rules_lint` +- **`clang_tidy/.clang-tidy`** — default S-CORE check set (conservative baseline, tailorable per module) +- **`clang_tidy/clang_tidy.bazelrc`** — canonical bazelrc snippet consumers import + +## Usage + +### Add Dependency + +```python +bazel_dep(name = "score_cpp_policies", version = "0.0.0") +bazel_dep(name = "toolchains_llvm", version = "1.5.0") +``` + +Set up `@llvm_toolchain` via the `llvm` extension (see `tests/MODULE.bazel` for an example). + +### Import the Bazelrc Snippet + +In your `.bazelrc`: + +```bazelrc +import %workspace%/path/to/clang_tidy.bazelrc +test:clang-tidy --aspects=//tools/lint:linters.bzl%clang_tidy_aspect +``` + +### Create `tools/lint/linters.bzl` + +```python +load("@score_cpp_policies//clang_tidy:defs.bzl", "make_clang_tidy_aspect", "make_clang_tidy_test") + +clang_tidy_aspect = make_clang_tidy_aspect( + binary = Label("@llvm_toolchain//:clang-tidy"), + configs = [Label("//:.clang-tidy")], +) + +clang_tidy_test = make_clang_tidy_test(aspect = clang_tidy_aspect) +``` + +### Add a `.clang-tidy` Config + +Place a `.clang-tidy` at your repo root. Use +[`@score_cpp_policies//clang_tidy:.clang-tidy`](.clang-tidy) as the starting point. + +### Run + +```bash +# Lint all C++ targets +bazel test --config=clang-tidy //... +``` + +Reports are written to `bazel-out/.../rules_lint_report/` as text files. diff --git a/clang_tidy/clang_tidy.bazelrc b/clang_tidy/clang_tidy.bazelrc new file mode 100644 index 0000000..7c6070f --- /dev/null +++ b/clang_tidy/clang_tidy.bazelrc @@ -0,0 +1,19 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +# ============================================================================== +# Centralized Clang-Tidy Configuration for S-CORE C++ Modules +# ============================================================================== + +test:clang-tidy --output_groups=+rules_lint_report +test:clang-tidy --extra_toolchains=@llvm_toolchain//:cc-toolchain-x86_64-linux diff --git a/clang_tidy/defs.bzl b/clang_tidy/defs.bzl new file mode 100644 index 0000000..4f0618c --- /dev/null +++ b/clang_tidy/defs.bzl @@ -0,0 +1,79 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +"""Clang-tidy support macros for S-CORE C++ modules. + +Provides macros to create a clang-tidy aspect and test rule with S-CORE defaults. +Consuming projects call make_clang_tidy_aspect() in their own linters.bzl to +create a project-specific aspect bound to their toolchain and .clang-tidy config. + +Example usage in your project's tools/lint/linters.bzl: + + load("@score_cpp_policies//clang_tidy:defs.bzl", "make_clang_tidy_aspect", "make_clang_tidy_test") + + clang_tidy_aspect = make_clang_tidy_aspect( + binary = Label("@llvm_toolchain//:clang-tidy"), + configs = [Label("//:.clang-tidy")], + ) + + clang_tidy_test = make_clang_tidy_test(aspect = clang_tidy_aspect) +""" + +load("@aspect_rules_lint//lint:clang_tidy.bzl", "lint_clang_tidy_aspect") +load("@aspect_rules_lint//lint:lint_test.bzl", "lint_test") + +def make_clang_tidy_aspect( + binary, + configs, + lint_target_headers = True, + angle_includes_are_system = True, + verbose = False): + """Creates a clang-tidy lint aspect with S-CORE defaults. + + Args: + binary: Label of the clang-tidy binary. + Must be resolved in the calling .bzl file's repository context, + e.g. Label("@llvm_toolchain//:clang-tidy"). + configs: List of Labels to .clang-tidy config files that clang-tidy needs + as inputs, e.g. [Label("//:.clang-tidy")]. + lint_target_headers: Whether to lint headers owned by analyzed targets (default: True). + angle_includes_are_system: Treat angle bracket includes as system headers (default: True). + verbose: Enable verbose clang-tidy output (default: False). + + Returns: + A clang-tidy aspect. Assign to a top-level variable in your .bzl file + so it can be referenced via --aspects= in .bazelrc. + """ + return lint_clang_tidy_aspect( + binary = binary, + configs = configs, + lint_target_headers = lint_target_headers, + angle_includes_are_system = angle_includes_are_system, + verbose = verbose, + ) + +def make_clang_tidy_test(aspect): + """Creates a clang-tidy lint test rule for per-target testing. + + Args: + aspect: The clang-tidy aspect returned by make_clang_tidy_aspect(). + + Returns: + A rule that can be instantiated in BUILD files to run clang-tidy + on individual cc_library / cc_binary / cc_test targets. + + Example usage in a BUILD file: + load("//tools/lint:linters.bzl", "clang_tidy_test") + clang_tidy_test(name = "my_lib_tidy", srcs = [":my_lib"]) + """ + return lint_test(aspect = aspect) diff --git a/sanitizers/BUILD.bazel b/sanitizers/BUILD.bazel index 0d086b2..77240d2 100644 --- a/sanitizers/BUILD.bazel +++ b/sanitizers/BUILD.bazel @@ -12,6 +12,7 @@ # ******************************************************************************* load("//sanitizers/private:expand_template.bzl", "expand_template") +load("@rules_shell//shell:sh_binary.bzl", "sh_binary") exports_files( ["sanitizers.bazelrc"], @@ -51,9 +52,13 @@ filegroup( "suppressions/lsan.supp", "suppressions/ubsan.supp", ], - "//conditions:default": [], + "//conditions:default": [ + "suppressions/asan.supp", + "suppressions/lsan.supp", + "suppressions/tsan.supp", + "suppressions/ubsan.supp", + ], }), - target_compatible_with = ["//sanitizers/constraints:any_sanitizer"], visibility = ["//visibility:public"], ) diff --git a/sanitizers/README.md b/sanitizers/README.md new file mode 100644 index 0000000..c33ff20 --- /dev/null +++ b/sanitizers/README.md @@ -0,0 +1,131 @@ +# Sanitizers + +Centralized sanitizer configurations and Bazel feature flags for Eclipse S-CORE C++ modules. + +## What This Provides + +- **Sanitizer Bazel feature flags** — ASan, UBSan, LSan, TSan as Bazel build features +- **`//sanitizers:wrapper`** — shell script that sets all sanitizer runtime options centrally +- **`sanitizers/sanitizers.bazelrc`** — canonical config that consumers import or copy +- **Suppression files** — per-sanitizer suppression lists for known false positives (GoogleTest, etc.) +- **Constraint system** — `target_compatible_with` settings for sanitizer-incompatible targets + +## Available Sanitizer Configurations + +| Config | Sanitizers | Notes | +|--------|-----------|-------| +| `--config=asan_ubsan_lsan` | ASan + UBSan + LSan | **Recommended** — catches memory errors, UB, and leaks | +| `--config=asan` | AddressSanitizer | Alias for `asan_ubsan_lsan` | +| `--config=ubsan` | UndefinedBehaviorSanitizer | Alias for `asan_ubsan_lsan` | +| `--config=lsan` | LeakSanitizer | Alias for `asan_ubsan_lsan` | +| `--config=tsan` | ThreadSanitizer | Cannot be combined with ASan | + +## Usage + +### Add Dependency + +```python +bazel_dep(name = "score_cpp_policies", version = "0.0.0") +``` + +### Configure Sanitizers + +Copy the sanitizer configs from `sanitizers/sanitizers.bazelrc` into your `.bazelrc` and adapt the paths: + +```bazelrc +# ASan + UBSan + LSan (Combined) +build:asan_ubsan_lsan --features=asan +build:asan_ubsan_lsan --features=ubsan +build:asan_ubsan_lsan --features=lsan +build:asan_ubsan_lsan --platform_suffix=asan_ubsan_lsan +test:asan_ubsan_lsan --config=with_debug_symbols +test:asan_ubsan_lsan --test_tag_filters=-no-asan,-no-lsan,-no-ubsan +test:asan_ubsan_lsan --@score_cpp_policies//sanitizers/flags:sanitizer=asan_ubsan_lsan +test:asan_ubsan_lsan --run_under=@score_cpp_policies//sanitizers:wrapper + +# Shortcuts +build:asan --config=asan_ubsan_lsan +test:asan --test_tag_filters=-no-asan +build:ubsan --config=asan_ubsan_lsan +test:ubsan --test_tag_filters=-no-ubsan +build:lsan --config=asan_ubsan_lsan +test:lsan --test_tag_filters=-no-lsan + +# ThreadSanitizer +build:tsan --features=tsan +build:tsan --platform_suffix=tsan +test:tsan --config=with_debug_symbols +test:tsan --cxxopt=-O1 +test:tsan --test_tag_filters=-no-tsan +test:tsan --@score_cpp_policies//sanitizers/flags:sanitizer=tsan +test:tsan --run_under=@score_cpp_policies//sanitizers:wrapper +``` + +> **Note**: The `--run_under=@score_cpp_policies//sanitizers:wrapper` automatically loads runtime +> options and suppressions from the module. + +### Run Tests + +```bash +# ASan + UBSan + LSan (recommended) +bazel test --config=asan_ubsan_lsan //... + +# ThreadSanitizer (separate run — cannot combine with ASan) +bazel test --config=tsan //... +``` + +## Tagging Tests for Sanitizer Compatibility + +```python +cc_test( + name = "my_test", + srcs = ["my_test.cpp"], + tags = ["no-tsan"], # skip when running --config=tsan + deps = ["@googletest//:gtest_main"], +) +``` + +| Tag | Skipped when using | +|-----|--------------------| +| `no-tsan` | `--config=tsan` | +| `no-asan` | `--config=asan` or `asan_ubsan_lsan` | +| `no-lsan` | `--config=lsan` or `asan_ubsan_lsan` | +| `no-ubsan` | `--config=ubsan` or `asan_ubsan_lsan` | + +## Suppression Files + +Default suppressions for common third-party libraries are included: + +| File | Sanitizer | Current Suppressions | +|------|-----------|---------------------| +| `sanitizers/suppressions/asan.supp` | ASan | *(empty)* | +| `sanitizers/suppressions/lsan.supp` | LSan | GoogleTest static initialization leaks | +| `sanitizers/suppressions/tsan.supp` | TSan | stdlib false positives, Rust test suppressions | +| `sanitizers/suppressions/ubsan.supp` | UBSan | *(empty)* | + +**Adding project-specific suppressions:** Currently, the wrapper loads suppressions from this +module only. For project-specific suppressions, you'll need to create a custom wrapper or extend +the environment variables in your `.bazelrc`. This is a known limitation being tracked for future +improvements. + +> **Runtime Options**: See [`templates/`](templates/) for detailed documentation of all sanitizer +> options configured by the wrapper. + +## Constraint System + +Use constraints to mark targets as incompatible with specific sanitizers: + +```python +cc_library( + name = "legacy_lib", + target_compatible_with = [ + "@score_cpp_policies//sanitizers/constraints:no_tsan", + ], +) +``` + +| Constraint | Effect | +|-----------|--------| +| `@score_cpp_policies//sanitizers/constraints:no_tsan` | Skip when `--config=tsan` | +| `@score_cpp_policies//sanitizers/constraints:no_asan_ubsan_lsan` | Skip when `--config=asan_ubsan_lsan` | +| `@score_cpp_policies//sanitizers/constraints:any_sanitizer` | Only builds with a sanitizer enabled | diff --git a/sanitizers/private/BUILD.bazel b/sanitizers/private/BUILD.bazel index f33a3e9..ad28815 100644 --- a/sanitizers/private/BUILD.bazel +++ b/sanitizers/private/BUILD.bazel @@ -12,9 +12,6 @@ # ******************************************************************************* exports_files( - [ - "expand_template.bzl", - "merge_suppressions.bzl", - ], - visibility = ["//visibility:public"], + ["expand_template.bzl"], + visibility = ["//sanitizers:__pkg__"], ) diff --git a/sanitizers/sanitizers.bazelrc b/sanitizers/sanitizers.bazelrc index 396972a..73328b6 100644 --- a/sanitizers/sanitizers.bazelrc +++ b/sanitizers/sanitizers.bazelrc @@ -25,29 +25,36 @@ # -g1: Minimal debug info (function names + line numbers) for sanitizer stack traces # GCC and Clang compatible. Note: Clang's -gline-tables-only provides column info but is not GCC-compatible. -test:with_debug_symbols --features=debug_symbols -# Disable stripping so debug symbols are preserved at the final link stage -build:with_debug_symbols --strip=never +test:with_debug_symbols --cxxopt=-g1 +test:with_debug_symbols --strip=never # AddressSanitizer + UndefinedBehaviorSanitizer + LeakSanitizer (Combined) -build:asan_ubsan_lsan --features=score_asan_ubsan_lsan +build:asan_ubsan_lsan --features=asan +build:asan_ubsan_lsan --features=ubsan +build:asan_ubsan_lsan --features=lsan build:asan_ubsan_lsan --platform_suffix=asan_ubsan_lsan -build:asan_ubsan_lsan --config=with_debug_symbols -build:asan_ubsan_lsan --@score_cpp_policies//sanitizers/flags:sanitizer=asan_ubsan_lsan +test:asan_ubsan_lsan --config=with_debug_symbols +test:asan_ubsan_lsan --test_tag_filters=-no-asan,-no-lsan,-no-ubsan +test:asan_ubsan_lsan --@score_cpp_policies//sanitizers/flags:sanitizer=asan_ubsan_lsan test:asan_ubsan_lsan --run_under=@score_cpp_policies//sanitizers:wrapper # AddressSanitizer only build:asan --config=asan_ubsan_lsan +build:asan --test_tag_filters=-no-asan # UndefinedBehaviorSanitizer only build:ubsan --config=asan_ubsan_lsan +build:ubsan --test_tag_filters=-no-ubsan # LeakSanitizer only build:lsan --config=asan_ubsan_lsan +build:lsan --test_tag_filters=-no-lsan # ThreadSanitizer (cannot be combined with ASan/LSan) -build:tsan --features=score_tsan +build:tsan --features=tsan build:tsan --platform_suffix=tsan -build:tsan --config=with_debug_symbols -build:tsan --@score_cpp_policies//sanitizers/flags:sanitizer=tsan +test:tsan --config=with_debug_symbols +test:tsan --cxxopt=-O1 +test:tsan --test_tag_filters=-no-tsan +test:tsan --@score_cpp_policies//sanitizers/flags:sanitizer=tsan test:tsan --run_under=@score_cpp_policies//sanitizers:wrapper diff --git a/sanitizers/suppressions/lsan.supp b/sanitizers/suppressions/lsan.supp index 5a20c80..043286e 100644 --- a/sanitizers/suppressions/lsan.supp +++ b/sanitizers/suppressions/lsan.supp @@ -17,14 +17,6 @@ # Suppressions that share the same justification may be organized in a single block. -# Rust's standard runtime (std::rt::lang_start) allocates thread-local storage (TLS) that is not -# cleaned up at the time LSan runs its atexit sweep. LSan reports this as a memory leak because -# TLS destructors are invoked after LSan's atexit handler, so the memory appears live but -# unreachable at leak-check time. This affects all Rust binaries regardless of async runtime used. -# Rust sanitizer support upstream: https://github.com/rust-lang/rust/issues/39699. -# We plan to re-verify the behavior and perform further analysis under Ticket-252536. -leak:std::rt::lang_start - # GoogleTest uses global singletons and static state that are intentionally # never freed. These are by design and not real leaks. leak:testing::internal::RegisterTest diff --git a/sanitizers/templates/asan_ubsan_lsan.env.template b/sanitizers/templates/asan_ubsan_lsan.env.template index 11960e8..3091a11 100644 --- a/sanitizers/templates/asan_ubsan_lsan.env.template +++ b/sanitizers/templates/asan_ubsan_lsan.env.template @@ -1,3 +1,3 @@ -ASAN_OPTIONS=allocator_may_return_null=1 allow_addr2line=1 check_initialization_order=1 detect_leaks=1 detect_stack_use_after_return=1 exitcode=55 halt_on_error=1 print_stats=1 strict_string_checks=1 verbosity=1 suppressions=%ROOT%sanitizers/suppressions/asan.supp -UBSAN_OPTIONS=allow_addr2line=1 exitcode=55 halt_on_error=1 print_stacktrace=1 verbosity=1 suppressions=%ROOT%sanitizers/suppressions/ubsan.supp +ASAN_OPTIONS=exitcode=55 allow_addr2line=1 verbosity=1 check_initialization_order=1 detect_stack_use_after_return=1 print_stats=1 halt_on_error=1 allocator_may_return_null=1 detect_leaks=1 suppressions=%ROOT%sanitizers/suppressions/asan.supp +UBSAN_OPTIONS=exitcode=55 allow_addr2line=1 verbosity=1 print_stacktrace=1 halt_on_error=1 suppressions=%ROOT%sanitizers/suppressions/ubsan.supp LSAN_OPTIONS=exitcode=55 suppressions=%ROOT%sanitizers/suppressions/lsan.supp diff --git a/sanitizers/templates/tsan.env.template b/sanitizers/templates/tsan.env.template index 8703308..338b420 100644 --- a/sanitizers/templates/tsan.env.template +++ b/sanitizers/templates/tsan.env.template @@ -1 +1 @@ -TSAN_OPTIONS=allow_addr2line=1 detect_deadlocks=1 exitcode=55 halt_on_error=1 second_deadlock_stack=1 verbosity=1 suppressions=%ROOT%sanitizers/suppressions/tsan.supp +TSAN_OPTIONS=exitcode=55 allow_addr2line=1 verbosity=1 detect_deadlocks=1 second_deadlock_stack=1 halt_on_error=1 suppressions=%ROOT%sanitizers/suppressions/tsan.supp diff --git a/tests/.bazelrc b/tests/.bazelrc index d2b7f84..d319624 100644 --- a/tests/.bazelrc +++ b/tests/.bazelrc @@ -11,12 +11,13 @@ # SPDX-License-Identifier: Apache-2.0 # ******************************************************************************* -# Import centralized sanitizer configurations +# Centralized sanitizer configurations import %workspace%/../sanitizers/sanitizers.bazelrc +# Clang-tidy: bazel test --config=clang-tidy //... +test:clang-tidy --aspects=//tools/lint:linters.bzl%clang_tidy_aspect +test:clang-tidy --output_groups=+rules_lint_report +test:clang-tidy --extra_toolchains=@llvm_toolchain//:cc-toolchain-x86_64-linux + common --registry=https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/ common --registry=https://bcr.bazel.build - -# Use LLVM toolchain for sanitizer configs (same as consuming modules) -build:asan_ubsan_lsan --extra_toolchains=@llvm_toolchain//:cc-toolchain-x86_64-linux -build:tsan --extra_toolchains=@llvm_toolchain//:cc-toolchain-x86_64-linux diff --git a/tests/.clang-tidy b/tests/.clang-tidy new file mode 100644 index 0000000..c234a7f --- /dev/null +++ b/tests/.clang-tidy @@ -0,0 +1,27 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +--- +# Clang-tidy configuration for the score_cpp_policies test workspace. +# NOTE: conservative check set so that existing sample_test.cpp passes cleanly. +Checks: > + -*, + clang-analyzer-*, + bugprone-* + +WarningsAsErrors: "" + +# Exclude third-party and googletest headers from analysis. +HeaderFilterRegex: '^(?!.*/third_party/)(?!.*/googletest/).*' + +FormatStyle: file diff --git a/tests/BUILD.bazel b/tests/BUILD.bazel index 7a4a276..7cda406 100644 --- a/tests/BUILD.bazel +++ b/tests/BUILD.bazel @@ -12,15 +12,19 @@ # ******************************************************************************* load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_test") +load("@rules_shell//shell:sh_test.bzl", "sh_test") + +# Required as input to the clang-tidy aspect (configs = [Label("//:.clang-tidy")]). +exports_files([".clang-tidy"]) # ============================================================================== -# Positive tests - verify clean code passes with all sanitizers +# Positive tests - verify clean code passes with all sanitizers and clang-tidy # ============================================================================== cc_test( name = "sample_test", srcs = ["sample_test.cpp"], - target_compatible_with = ["@score_cpp_policies//sanitizers/constraints:no_tsan"], # TSAN has known issues with googletest + tags = ["no-tsan"], # TSAN has known issues with googletest deps = [ "@googletest//:gtest", "@googletest//:gtest_main", @@ -67,7 +71,7 @@ sh_test( "55", ], data = [":asan_fail_test"], - target_compatible_with = ["@score_cpp_policies//sanitizers/constraints:no_tsan"], + tags = ["no-tsan"], ) sh_test( @@ -78,7 +82,7 @@ sh_test( "55", ], data = [":lsan_fail_test"], - target_compatible_with = ["@score_cpp_policies//sanitizers/constraints:no_tsan"], + tags = ["no-tsan"], ) sh_test( @@ -89,7 +93,7 @@ sh_test( "55", ], data = [":tsan_fail_test"], - target_compatible_with = ["@score_cpp_policies//sanitizers/constraints:no_asan_ubsan_lsan"], + tags = ["no-asan", "no-lsan", "no-ubsan"], ) sh_test( @@ -100,6 +104,6 @@ sh_test( "55", ], data = [":ubsan_fail_test"], - target_compatible_with = ["@score_cpp_policies//sanitizers/constraints:no_tsan"], + tags = ["no-tsan"], ) diff --git a/tests/MODULE.bazel b/tests/MODULE.bazel index 62d0e1b..76171ff 100644 --- a/tests/MODULE.bazel +++ b/tests/MODULE.bazel @@ -13,25 +13,29 @@ module( name = "score_cpp_policies_tests", + version = "0.0.0", ) bazel_dep(name = "googletest", version = "1.17.0.bcr.2") -bazel_dep(name = "rules_cc", version = "0.1.5") -bazel_dep(name = "toolchains_llvm", version = "1.7.0") +bazel_dep(name = "rules_cc", version = "0.2.17") +bazel_dep(name = "rules_shell", version = "0.6.1") -bazel_dep(name = "score_cpp_policies") +bazel_dep(name = "rules_go", version = "0.60.0", repo_name = "io_bazel_rules_go") + +bazel_dep(name = "score_cpp_policies", version = "") local_path_override( module_name = "score_cpp_policies", path = "..", ) -llvm = use_extension("@toolchains_llvm//toolchain/extensions:llvm.bzl", "llvm") +# LLVM toolchain for clang-tidy (provides @llvm_toolchain//:clang-tidy). +bazel_dep(name = "toolchains_llvm", version = "1.5.0") + +llvm = use_extension( + "@toolchains_llvm//toolchain/extensions:llvm.bzl", + "llvm", +) llvm.toolchain( llvm_version = "19.1.7", - extra_known_features = [ - "@score_cpp_policies//sanitizers/features:debug_symbols", - "@score_cpp_policies//sanitizers/features:asan_ubsan_lsan", - "@score_cpp_policies//sanitizers/features:tsan", - ], ) use_repo(llvm, "llvm_toolchain") diff --git a/tests/tools/lint/BUILD.bazel b/tests/tools/lint/BUILD.bazel new file mode 100644 index 0000000..206c4e4 --- /dev/null +++ b/tests/tools/lint/BUILD.bazel @@ -0,0 +1,17 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +exports_files( + ["linters.bzl"], + visibility = ["//visibility:public"], +) diff --git a/tests/tools/lint/linters.bzl b/tests/tools/lint/linters.bzl new file mode 100644 index 0000000..6e1c4e4 --- /dev/null +++ b/tests/tools/lint/linters.bzl @@ -0,0 +1,23 @@ +# ******************************************************************************* +# Copyright (c) 2026 Contributors to the Eclipse Foundation +# +# See the NOTICE file(s) distributed with this work for additional +# information regarding copyright ownership. +# +# This program and the accompanying materials are made available under the +# terms of the Apache License Version 2.0 which is available at +# https://www.apache.org/licenses/LICENSE-2.0 +# +# SPDX-License-Identifier: Apache-2.0 +# ******************************************************************************* + +"""Clang-tidy aspect and test rule for the score_cpp_policies test workspace.""" + +load("@score_cpp_policies//clang_tidy:defs.bzl", "make_clang_tidy_aspect", "make_clang_tidy_test") + +clang_tidy_aspect = make_clang_tidy_aspect( + binary = Label("@llvm_toolchain//:clang-tidy"), + configs = [Label("//:.clang-tidy")], +) + +clang_tidy_test = make_clang_tidy_test(aspect = clang_tidy_aspect) From f147fc890f3b59aa955d5c644691c0095d17467d Mon Sep 17 00:00:00 2001 From: rahulsasingh Date: Thu, 14 May 2026 06:54:19 +0200 Subject: [PATCH 2/3] Fix review comments: sanitizers.bazelrc bugs, restore lsan Rust suppression, remove dead clang_tidy.bazelrc, improve HeaderFilterRegex and docs --- clang_tidy/.clang-tidy | 2 +- clang_tidy/BUILD.bazel | 1 - clang_tidy/README.md | 19 +++++++++++++++---- clang_tidy/clang_tidy.bazelrc | 19 ------------------- sanitizers/README.md | 27 +++++++++++++++++++++++---- sanitizers/sanitizers.bazelrc | 10 +++++----- sanitizers/suppressions/lsan.supp | 4 ++++ tests/MODULE.bazel | 2 +- 8 files changed, 49 insertions(+), 35 deletions(-) delete mode 100644 clang_tidy/clang_tidy.bazelrc diff --git a/clang_tidy/.clang-tidy b/clang_tidy/.clang-tidy index 8e5a61e..19502ce 100644 --- a/clang_tidy/.clang-tidy +++ b/clang_tidy/.clang-tidy @@ -30,7 +30,7 @@ WarningsAsErrors: >- clang-analyzer-* # Exclude third-party and generated headers from analysis. -HeaderFilterRegex: '^(?!.*/third_party/).*' +HeaderFilterRegex: '^(?!.*/(third_party|bazel-out|external)/).*$' FormatStyle: file diff --git a/clang_tidy/BUILD.bazel b/clang_tidy/BUILD.bazel index b8dbb4f..b2ad96f 100644 --- a/clang_tidy/BUILD.bazel +++ b/clang_tidy/BUILD.bazel @@ -14,7 +14,6 @@ exports_files( [ ".clang-tidy", - "clang_tidy.bazelrc", ], visibility = ["//visibility:public"], ) diff --git a/clang_tidy/README.md b/clang_tidy/README.md index 4113c6c..b6921cb 100644 --- a/clang_tidy/README.md +++ b/clang_tidy/README.md @@ -6,7 +6,6 @@ Centralized clang-tidy configuration and Bazel macros for Eclipse S-CORE C++ mod - **`//clang_tidy:defs.bzl`** — `make_clang_tidy_aspect` / `make_clang_tidy_test` macros wrapping `aspect_rules_lint` - **`clang_tidy/.clang-tidy`** — default S-CORE check set (conservative baseline, tailorable per module) -- **`clang_tidy/clang_tidy.bazelrc`** — canonical bazelrc snippet consumers import ## Usage @@ -19,21 +18,29 @@ bazel_dep(name = "toolchains_llvm", version = "1.5.0") Set up `@llvm_toolchain` via the `llvm` extension (see `tests/MODULE.bazel` for an example). -### Import the Bazelrc Snippet +### Add the Bazelrc Snippet -In your `.bazelrc`: +There is no importable `.bazelrc` from an external module — `%workspace%` resolves to the +consuming workspace, not to `@score_cpp_policies`. Copy these lines into your own `.bazelrc` +instead: ```bazelrc -import %workspace%/path/to/clang_tidy.bazelrc +test:clang-tidy --output_groups=+rules_lint_report +# Pin the LLVM toolchain for clang-tidy — adjust the target for your host arch: +test:clang-tidy --extra_toolchains=@llvm_toolchain//:cc-toolchain-x86_64-linux test:clang-tidy --aspects=//tools/lint:linters.bzl%clang_tidy_aspect ``` +> **Note**: The `--extra_toolchains` line hard-codes `x86_64-linux`. On AArch64 hosts (Apple +> Silicon CI runners, etc.) replace it with `cc-toolchain-aarch64-linux`. + ### Create `tools/lint/linters.bzl` ```python load("@score_cpp_policies//clang_tidy:defs.bzl", "make_clang_tidy_aspect", "make_clang_tidy_test") clang_tidy_aspect = make_clang_tidy_aspect( + # binary MUST be a Label literal here — string labels silently resolve to the wrong repo. binary = Label("@llvm_toolchain//:clang-tidy"), configs = [Label("//:.clang-tidy")], ) @@ -46,6 +53,10 @@ clang_tidy_test = make_clang_tidy_test(aspect = clang_tidy_aspect) Place a `.clang-tidy` at your repo root. Use [`@score_cpp_policies//clang_tidy:.clang-tidy`](.clang-tidy) as the starting point. +> **Advisory checks**: The enabled checks (`cppcoreguidelines-*`, `modernize-*`, etc.) are +> advisory — only `clang-analyzer-*` is `WarningsAsErrors`. Module owners should tighten +> `WarningsAsErrors` incrementally as compliance improves. + ### Run ```bash diff --git a/clang_tidy/clang_tidy.bazelrc b/clang_tidy/clang_tidy.bazelrc deleted file mode 100644 index 7c6070f..0000000 --- a/clang_tidy/clang_tidy.bazelrc +++ /dev/null @@ -1,19 +0,0 @@ -# ******************************************************************************* -# Copyright (c) 2026 Contributors to the Eclipse Foundation -# -# See the NOTICE file(s) distributed with this work for additional -# information regarding copyright ownership. -# -# This program and the accompanying materials are made available under the -# terms of the Apache License Version 2.0 which is available at -# https://www.apache.org/licenses/LICENSE-2.0 -# -# SPDX-License-Identifier: Apache-2.0 -# ******************************************************************************* - -# ============================================================================== -# Centralized Clang-Tidy Configuration for S-CORE C++ Modules -# ============================================================================== - -test:clang-tidy --output_groups=+rules_lint_report -test:clang-tidy --extra_toolchains=@llvm_toolchain//:cc-toolchain-x86_64-linux diff --git a/sanitizers/README.md b/sanitizers/README.md index c33ff20..fefd6c6 100644 --- a/sanitizers/README.md +++ b/sanitizers/README.md @@ -1,7 +1,29 @@ + # Sanitizers Centralized sanitizer configurations and Bazel feature flags for Eclipse S-CORE C++ modules. +> **Limitation — project-specific suppressions**: The wrapper currently loads suppressions from +> this module only. There is no override mechanism for consumers to add their own suppressions +> without forking the wrapper. This is a known limitation being tracked for future improvements. +> Rust consumers must note that `leak:std::rt::lang_start` is included in `lsan.supp`; if you +> remove it from a fork, Rust TLS-on-shutdown will be flagged as a real leak. + +> **Toolchain requirement**: The sanitizer feature flags (`asan`, `ubsan`, `lsan`, `tsan`) require +> a toolchain that exposes those features, e.g. `toolchains_llvm` 1.5+. GCC toolchains do not +> expose these features by default. + ## What This Provides - **Sanitizer Bazel feature flags** — ASan, UBSan, LSan, TSan as Bazel build features @@ -103,10 +125,7 @@ Default suppressions for common third-party libraries are included: | `sanitizers/suppressions/tsan.supp` | TSan | stdlib false positives, Rust test suppressions | | `sanitizers/suppressions/ubsan.supp` | UBSan | *(empty)* | -**Adding project-specific suppressions:** Currently, the wrapper loads suppressions from this -module only. For project-specific suppressions, you'll need to create a custom wrapper or extend -the environment variables in your `.bazelrc`. This is a known limitation being tracked for future -improvements. +**Suppression files** are loaded automatically by the wrapper — no manual setup required. > **Runtime Options**: See [`templates/`](templates/) for detailed documentation of all sanitizer > options configured by the wrapper. diff --git a/sanitizers/sanitizers.bazelrc b/sanitizers/sanitizers.bazelrc index 73328b6..021fa86 100644 --- a/sanitizers/sanitizers.bazelrc +++ b/sanitizers/sanitizers.bazelrc @@ -25,8 +25,8 @@ # -g1: Minimal debug info (function names + line numbers) for sanitizer stack traces # GCC and Clang compatible. Note: Clang's -gline-tables-only provides column info but is not GCC-compatible. -test:with_debug_symbols --cxxopt=-g1 -test:with_debug_symbols --strip=never +build:with_debug_symbols --cxxopt=-g1 +build:with_debug_symbols --strip=never # AddressSanitizer + UndefinedBehaviorSanitizer + LeakSanitizer (Combined) build:asan_ubsan_lsan --features=asan @@ -40,15 +40,15 @@ test:asan_ubsan_lsan --run_under=@score_cpp_policies//sanitizers:wrapper # AddressSanitizer only build:asan --config=asan_ubsan_lsan -build:asan --test_tag_filters=-no-asan +test:asan --test_tag_filters=-no-asan # UndefinedBehaviorSanitizer only build:ubsan --config=asan_ubsan_lsan -build:ubsan --test_tag_filters=-no-ubsan +test:ubsan --test_tag_filters=-no-ubsan # LeakSanitizer only build:lsan --config=asan_ubsan_lsan -build:lsan --test_tag_filters=-no-lsan +test:lsan --test_tag_filters=-no-lsan # ThreadSanitizer (cannot be combined with ASan/LSan) build:tsan --features=tsan diff --git a/sanitizers/suppressions/lsan.supp b/sanitizers/suppressions/lsan.supp index 043286e..e590100 100644 --- a/sanitizers/suppressions/lsan.supp +++ b/sanitizers/suppressions/lsan.supp @@ -23,3 +23,7 @@ leak:testing::internal::RegisterTest leak:testing::UnitTest::GetInstance leak:testing::internal::UnitTestImpl +# Rust runtime thread-local storage cleanup on shutdown is intentionally not +# freed. Harmless when no Rust is present; required when Rust crates are linked. +leak:std::rt::lang_start + diff --git a/tests/MODULE.bazel b/tests/MODULE.bazel index 76171ff..947eff7 100644 --- a/tests/MODULE.bazel +++ b/tests/MODULE.bazel @@ -22,7 +22,7 @@ bazel_dep(name = "rules_shell", version = "0.6.1") bazel_dep(name = "rules_go", version = "0.60.0", repo_name = "io_bazel_rules_go") -bazel_dep(name = "score_cpp_policies", version = "") +bazel_dep(name = "score_cpp_policies", version = "0.0.0") local_path_override( module_name = "score_cpp_policies", path = "..", From fb9f64e571d1ed1bc60986fef51a1d83b46d74b6 Mon Sep 17 00:00:00 2001 From: rahulsasingh Date: Fri, 15 May 2026 14:13:49 +0200 Subject: [PATCH 3/3] Remove sanitizer changes --- MODULE.bazel | 1 - sanitizers/BUILD.bazel | 9 +- sanitizers/README.md | 150 ------------------ sanitizers/private/BUILD.bazel | 7 +- sanitizers/sanitizers.bazelrc | 23 +-- sanitizers/suppressions/lsan.supp | 12 +- .../templates/asan_ubsan_lsan.env.template | 4 +- sanitizers/templates/tsan.env.template | 2 +- tests/.bazelrc | 6 +- tests/BUILD.bazel | 13 +- tests/MODULE.bazel | 8 +- 11 files changed, 43 insertions(+), 192 deletions(-) delete mode 100644 sanitizers/README.md diff --git a/MODULE.bazel b/MODULE.bazel index 032f1a3..72af2a9 100644 --- a/MODULE.bazel +++ b/MODULE.bazel @@ -19,7 +19,6 @@ module( bazel_dep(name = "bazel_skylib", version = "1.8.2") bazel_dep(name = "platforms", version = "0.0.10") bazel_dep(name = "rules_cc", version = "0.1.5") -bazel_dep(name = "rules_shell", version = "0.6.1") bazel_dep(name = "aspect_rules_lint", version = "2.5.0") diff --git a/sanitizers/BUILD.bazel b/sanitizers/BUILD.bazel index 77240d2..0d086b2 100644 --- a/sanitizers/BUILD.bazel +++ b/sanitizers/BUILD.bazel @@ -12,7 +12,6 @@ # ******************************************************************************* load("//sanitizers/private:expand_template.bzl", "expand_template") -load("@rules_shell//shell:sh_binary.bzl", "sh_binary") exports_files( ["sanitizers.bazelrc"], @@ -52,13 +51,9 @@ filegroup( "suppressions/lsan.supp", "suppressions/ubsan.supp", ], - "//conditions:default": [ - "suppressions/asan.supp", - "suppressions/lsan.supp", - "suppressions/tsan.supp", - "suppressions/ubsan.supp", - ], + "//conditions:default": [], }), + target_compatible_with = ["//sanitizers/constraints:any_sanitizer"], visibility = ["//visibility:public"], ) diff --git a/sanitizers/README.md b/sanitizers/README.md deleted file mode 100644 index fefd6c6..0000000 --- a/sanitizers/README.md +++ /dev/null @@ -1,150 +0,0 @@ - -# Sanitizers - -Centralized sanitizer configurations and Bazel feature flags for Eclipse S-CORE C++ modules. - -> **Limitation — project-specific suppressions**: The wrapper currently loads suppressions from -> this module only. There is no override mechanism for consumers to add their own suppressions -> without forking the wrapper. This is a known limitation being tracked for future improvements. -> Rust consumers must note that `leak:std::rt::lang_start` is included in `lsan.supp`; if you -> remove it from a fork, Rust TLS-on-shutdown will be flagged as a real leak. - -> **Toolchain requirement**: The sanitizer feature flags (`asan`, `ubsan`, `lsan`, `tsan`) require -> a toolchain that exposes those features, e.g. `toolchains_llvm` 1.5+. GCC toolchains do not -> expose these features by default. - -## What This Provides - -- **Sanitizer Bazel feature flags** — ASan, UBSan, LSan, TSan as Bazel build features -- **`//sanitizers:wrapper`** — shell script that sets all sanitizer runtime options centrally -- **`sanitizers/sanitizers.bazelrc`** — canonical config that consumers import or copy -- **Suppression files** — per-sanitizer suppression lists for known false positives (GoogleTest, etc.) -- **Constraint system** — `target_compatible_with` settings for sanitizer-incompatible targets - -## Available Sanitizer Configurations - -| Config | Sanitizers | Notes | -|--------|-----------|-------| -| `--config=asan_ubsan_lsan` | ASan + UBSan + LSan | **Recommended** — catches memory errors, UB, and leaks | -| `--config=asan` | AddressSanitizer | Alias for `asan_ubsan_lsan` | -| `--config=ubsan` | UndefinedBehaviorSanitizer | Alias for `asan_ubsan_lsan` | -| `--config=lsan` | LeakSanitizer | Alias for `asan_ubsan_lsan` | -| `--config=tsan` | ThreadSanitizer | Cannot be combined with ASan | - -## Usage - -### Add Dependency - -```python -bazel_dep(name = "score_cpp_policies", version = "0.0.0") -``` - -### Configure Sanitizers - -Copy the sanitizer configs from `sanitizers/sanitizers.bazelrc` into your `.bazelrc` and adapt the paths: - -```bazelrc -# ASan + UBSan + LSan (Combined) -build:asan_ubsan_lsan --features=asan -build:asan_ubsan_lsan --features=ubsan -build:asan_ubsan_lsan --features=lsan -build:asan_ubsan_lsan --platform_suffix=asan_ubsan_lsan -test:asan_ubsan_lsan --config=with_debug_symbols -test:asan_ubsan_lsan --test_tag_filters=-no-asan,-no-lsan,-no-ubsan -test:asan_ubsan_lsan --@score_cpp_policies//sanitizers/flags:sanitizer=asan_ubsan_lsan -test:asan_ubsan_lsan --run_under=@score_cpp_policies//sanitizers:wrapper - -# Shortcuts -build:asan --config=asan_ubsan_lsan -test:asan --test_tag_filters=-no-asan -build:ubsan --config=asan_ubsan_lsan -test:ubsan --test_tag_filters=-no-ubsan -build:lsan --config=asan_ubsan_lsan -test:lsan --test_tag_filters=-no-lsan - -# ThreadSanitizer -build:tsan --features=tsan -build:tsan --platform_suffix=tsan -test:tsan --config=with_debug_symbols -test:tsan --cxxopt=-O1 -test:tsan --test_tag_filters=-no-tsan -test:tsan --@score_cpp_policies//sanitizers/flags:sanitizer=tsan -test:tsan --run_under=@score_cpp_policies//sanitizers:wrapper -``` - -> **Note**: The `--run_under=@score_cpp_policies//sanitizers:wrapper` automatically loads runtime -> options and suppressions from the module. - -### Run Tests - -```bash -# ASan + UBSan + LSan (recommended) -bazel test --config=asan_ubsan_lsan //... - -# ThreadSanitizer (separate run — cannot combine with ASan) -bazel test --config=tsan //... -``` - -## Tagging Tests for Sanitizer Compatibility - -```python -cc_test( - name = "my_test", - srcs = ["my_test.cpp"], - tags = ["no-tsan"], # skip when running --config=tsan - deps = ["@googletest//:gtest_main"], -) -``` - -| Tag | Skipped when using | -|-----|--------------------| -| `no-tsan` | `--config=tsan` | -| `no-asan` | `--config=asan` or `asan_ubsan_lsan` | -| `no-lsan` | `--config=lsan` or `asan_ubsan_lsan` | -| `no-ubsan` | `--config=ubsan` or `asan_ubsan_lsan` | - -## Suppression Files - -Default suppressions for common third-party libraries are included: - -| File | Sanitizer | Current Suppressions | -|------|-----------|---------------------| -| `sanitizers/suppressions/asan.supp` | ASan | *(empty)* | -| `sanitizers/suppressions/lsan.supp` | LSan | GoogleTest static initialization leaks | -| `sanitizers/suppressions/tsan.supp` | TSan | stdlib false positives, Rust test suppressions | -| `sanitizers/suppressions/ubsan.supp` | UBSan | *(empty)* | - -**Suppression files** are loaded automatically by the wrapper — no manual setup required. - -> **Runtime Options**: See [`templates/`](templates/) for detailed documentation of all sanitizer -> options configured by the wrapper. - -## Constraint System - -Use constraints to mark targets as incompatible with specific sanitizers: - -```python -cc_library( - name = "legacy_lib", - target_compatible_with = [ - "@score_cpp_policies//sanitizers/constraints:no_tsan", - ], -) -``` - -| Constraint | Effect | -|-----------|--------| -| `@score_cpp_policies//sanitizers/constraints:no_tsan` | Skip when `--config=tsan` | -| `@score_cpp_policies//sanitizers/constraints:no_asan_ubsan_lsan` | Skip when `--config=asan_ubsan_lsan` | -| `@score_cpp_policies//sanitizers/constraints:any_sanitizer` | Only builds with a sanitizer enabled | diff --git a/sanitizers/private/BUILD.bazel b/sanitizers/private/BUILD.bazel index ad28815..f33a3e9 100644 --- a/sanitizers/private/BUILD.bazel +++ b/sanitizers/private/BUILD.bazel @@ -12,6 +12,9 @@ # ******************************************************************************* exports_files( - ["expand_template.bzl"], - visibility = ["//sanitizers:__pkg__"], + [ + "expand_template.bzl", + "merge_suppressions.bzl", + ], + visibility = ["//visibility:public"], ) diff --git a/sanitizers/sanitizers.bazelrc b/sanitizers/sanitizers.bazelrc index 021fa86..396972a 100644 --- a/sanitizers/sanitizers.bazelrc +++ b/sanitizers/sanitizers.bazelrc @@ -25,36 +25,29 @@ # -g1: Minimal debug info (function names + line numbers) for sanitizer stack traces # GCC and Clang compatible. Note: Clang's -gline-tables-only provides column info but is not GCC-compatible. -build:with_debug_symbols --cxxopt=-g1 +test:with_debug_symbols --features=debug_symbols +# Disable stripping so debug symbols are preserved at the final link stage build:with_debug_symbols --strip=never # AddressSanitizer + UndefinedBehaviorSanitizer + LeakSanitizer (Combined) -build:asan_ubsan_lsan --features=asan -build:asan_ubsan_lsan --features=ubsan -build:asan_ubsan_lsan --features=lsan +build:asan_ubsan_lsan --features=score_asan_ubsan_lsan build:asan_ubsan_lsan --platform_suffix=asan_ubsan_lsan -test:asan_ubsan_lsan --config=with_debug_symbols -test:asan_ubsan_lsan --test_tag_filters=-no-asan,-no-lsan,-no-ubsan -test:asan_ubsan_lsan --@score_cpp_policies//sanitizers/flags:sanitizer=asan_ubsan_lsan +build:asan_ubsan_lsan --config=with_debug_symbols +build:asan_ubsan_lsan --@score_cpp_policies//sanitizers/flags:sanitizer=asan_ubsan_lsan test:asan_ubsan_lsan --run_under=@score_cpp_policies//sanitizers:wrapper # AddressSanitizer only build:asan --config=asan_ubsan_lsan -test:asan --test_tag_filters=-no-asan # UndefinedBehaviorSanitizer only build:ubsan --config=asan_ubsan_lsan -test:ubsan --test_tag_filters=-no-ubsan # LeakSanitizer only build:lsan --config=asan_ubsan_lsan -test:lsan --test_tag_filters=-no-lsan # ThreadSanitizer (cannot be combined with ASan/LSan) -build:tsan --features=tsan +build:tsan --features=score_tsan build:tsan --platform_suffix=tsan -test:tsan --config=with_debug_symbols -test:tsan --cxxopt=-O1 -test:tsan --test_tag_filters=-no-tsan -test:tsan --@score_cpp_policies//sanitizers/flags:sanitizer=tsan +build:tsan --config=with_debug_symbols +build:tsan --@score_cpp_policies//sanitizers/flags:sanitizer=tsan test:tsan --run_under=@score_cpp_policies//sanitizers:wrapper diff --git a/sanitizers/suppressions/lsan.supp b/sanitizers/suppressions/lsan.supp index e590100..5a20c80 100644 --- a/sanitizers/suppressions/lsan.supp +++ b/sanitizers/suppressions/lsan.supp @@ -17,13 +17,17 @@ # Suppressions that share the same justification may be organized in a single block. +# Rust's standard runtime (std::rt::lang_start) allocates thread-local storage (TLS) that is not +# cleaned up at the time LSan runs its atexit sweep. LSan reports this as a memory leak because +# TLS destructors are invoked after LSan's atexit handler, so the memory appears live but +# unreachable at leak-check time. This affects all Rust binaries regardless of async runtime used. +# Rust sanitizer support upstream: https://github.com/rust-lang/rust/issues/39699. +# We plan to re-verify the behavior and perform further analysis under Ticket-252536. +leak:std::rt::lang_start + # GoogleTest uses global singletons and static state that are intentionally # never freed. These are by design and not real leaks. leak:testing::internal::RegisterTest leak:testing::UnitTest::GetInstance leak:testing::internal::UnitTestImpl -# Rust runtime thread-local storage cleanup on shutdown is intentionally not -# freed. Harmless when no Rust is present; required when Rust crates are linked. -leak:std::rt::lang_start - diff --git a/sanitizers/templates/asan_ubsan_lsan.env.template b/sanitizers/templates/asan_ubsan_lsan.env.template index 3091a11..11960e8 100644 --- a/sanitizers/templates/asan_ubsan_lsan.env.template +++ b/sanitizers/templates/asan_ubsan_lsan.env.template @@ -1,3 +1,3 @@ -ASAN_OPTIONS=exitcode=55 allow_addr2line=1 verbosity=1 check_initialization_order=1 detect_stack_use_after_return=1 print_stats=1 halt_on_error=1 allocator_may_return_null=1 detect_leaks=1 suppressions=%ROOT%sanitizers/suppressions/asan.supp -UBSAN_OPTIONS=exitcode=55 allow_addr2line=1 verbosity=1 print_stacktrace=1 halt_on_error=1 suppressions=%ROOT%sanitizers/suppressions/ubsan.supp +ASAN_OPTIONS=allocator_may_return_null=1 allow_addr2line=1 check_initialization_order=1 detect_leaks=1 detect_stack_use_after_return=1 exitcode=55 halt_on_error=1 print_stats=1 strict_string_checks=1 verbosity=1 suppressions=%ROOT%sanitizers/suppressions/asan.supp +UBSAN_OPTIONS=allow_addr2line=1 exitcode=55 halt_on_error=1 print_stacktrace=1 verbosity=1 suppressions=%ROOT%sanitizers/suppressions/ubsan.supp LSAN_OPTIONS=exitcode=55 suppressions=%ROOT%sanitizers/suppressions/lsan.supp diff --git a/sanitizers/templates/tsan.env.template b/sanitizers/templates/tsan.env.template index 338b420..8703308 100644 --- a/sanitizers/templates/tsan.env.template +++ b/sanitizers/templates/tsan.env.template @@ -1 +1 @@ -TSAN_OPTIONS=exitcode=55 allow_addr2line=1 verbosity=1 detect_deadlocks=1 second_deadlock_stack=1 halt_on_error=1 suppressions=%ROOT%sanitizers/suppressions/tsan.supp +TSAN_OPTIONS=allow_addr2line=1 detect_deadlocks=1 exitcode=55 halt_on_error=1 second_deadlock_stack=1 verbosity=1 suppressions=%ROOT%sanitizers/suppressions/tsan.supp diff --git a/tests/.bazelrc b/tests/.bazelrc index d319624..e1930d9 100644 --- a/tests/.bazelrc +++ b/tests/.bazelrc @@ -11,7 +11,7 @@ # SPDX-License-Identifier: Apache-2.0 # ******************************************************************************* -# Centralized sanitizer configurations +# Import centralized sanitizer configurations import %workspace%/../sanitizers/sanitizers.bazelrc # Clang-tidy: bazel test --config=clang-tidy //... @@ -21,3 +21,7 @@ test:clang-tidy --extra_toolchains=@llvm_toolchain//:cc-toolchain-x86_64-linux common --registry=https://raw.githubusercontent.com/eclipse-score/bazel_registry/main/ common --registry=https://bcr.bazel.build + +# Use LLVM toolchain for sanitizer configs (same as consuming modules) +build:asan_ubsan_lsan --extra_toolchains=@llvm_toolchain//:cc-toolchain-x86_64-linux +build:tsan --extra_toolchains=@llvm_toolchain//:cc-toolchain-x86_64-linux diff --git a/tests/BUILD.bazel b/tests/BUILD.bazel index 7cda406..40f1317 100644 --- a/tests/BUILD.bazel +++ b/tests/BUILD.bazel @@ -12,19 +12,18 @@ # ******************************************************************************* load("@rules_cc//cc:defs.bzl", "cc_binary", "cc_test") -load("@rules_shell//shell:sh_test.bzl", "sh_test") # Required as input to the clang-tidy aspect (configs = [Label("//:.clang-tidy")]). exports_files([".clang-tidy"]) # ============================================================================== -# Positive tests - verify clean code passes with all sanitizers and clang-tidy +# Positive tests - verify clean code passes with all sanitizers # ============================================================================== cc_test( name = "sample_test", srcs = ["sample_test.cpp"], - tags = ["no-tsan"], # TSAN has known issues with googletest + target_compatible_with = ["@score_cpp_policies//sanitizers/constraints:no_tsan"], # TSAN has known issues with googletest deps = [ "@googletest//:gtest", "@googletest//:gtest_main", @@ -71,7 +70,7 @@ sh_test( "55", ], data = [":asan_fail_test"], - tags = ["no-tsan"], + target_compatible_with = ["@score_cpp_policies//sanitizers/constraints:no_tsan"], ) sh_test( @@ -82,7 +81,7 @@ sh_test( "55", ], data = [":lsan_fail_test"], - tags = ["no-tsan"], + target_compatible_with = ["@score_cpp_policies//sanitizers/constraints:no_tsan"], ) sh_test( @@ -93,7 +92,7 @@ sh_test( "55", ], data = [":tsan_fail_test"], - tags = ["no-asan", "no-lsan", "no-ubsan"], + target_compatible_with = ["@score_cpp_policies//sanitizers/constraints:no_asan_ubsan_lsan"], ) sh_test( @@ -104,6 +103,6 @@ sh_test( "55", ], data = [":ubsan_fail_test"], - tags = ["no-tsan"], + target_compatible_with = ["@score_cpp_policies//sanitizers/constraints:no_tsan"], ) diff --git a/tests/MODULE.bazel b/tests/MODULE.bazel index 947eff7..ad2800c 100644 --- a/tests/MODULE.bazel +++ b/tests/MODULE.bazel @@ -18,7 +18,6 @@ module( bazel_dep(name = "googletest", version = "1.17.0.bcr.2") bazel_dep(name = "rules_cc", version = "0.2.17") -bazel_dep(name = "rules_shell", version = "0.6.1") bazel_dep(name = "rules_go", version = "0.60.0", repo_name = "io_bazel_rules_go") @@ -29,7 +28,7 @@ local_path_override( ) # LLVM toolchain for clang-tidy (provides @llvm_toolchain//:clang-tidy). -bazel_dep(name = "toolchains_llvm", version = "1.5.0") +bazel_dep(name = "toolchains_llvm", version = "1.7.0") llvm = use_extension( "@toolchains_llvm//toolchain/extensions:llvm.bzl", @@ -37,5 +36,10 @@ llvm = use_extension( ) llvm.toolchain( llvm_version = "19.1.7", + extra_known_features = [ + "@score_cpp_policies//sanitizers/features:debug_symbols", + "@score_cpp_policies//sanitizers/features:asan_ubsan_lsan", + "@score_cpp_policies//sanitizers/features:tsan", + ], ) use_repo(llvm, "llvm_toolchain")