From 6b30f18c861599b275c9f28261d17a5d733541d9 Mon Sep 17 00:00:00 2001 From: Nitesh Purohit Date: Thu, 10 Sep 2026 20:48:50 -0400 Subject: [PATCH 1/4] feat: add sanitizer profiles and validation tests - Introduced support for AddressSanitizer (ASan), UndefinedBehaviorSanitizer (UBSan), and ThreadSanitizer (TSan) profiles. - Added new CMake functions for configuring sanitizer profiles and validating suppressions. - Created test fixtures for heap misuse and data race scenarios to validate sanitizer functionality. - Implemented validation scripts to ensure proper usage of sanitizer suppressions. - Updated toolchain and build configurations to integrate sanitizer options seamlessly. closes: #74 --- .github/workflows/toolchain.yml | 39 +++--- CMakeLists.txt | 26 ++-- CMakePresets.json | 16 +++ cmake/ExpectSanitizerFailure.cmake | 28 ++++ cmake/ExpectSanitizerReleaseExclusion.cmake | 17 +++ cmake/ExpectSanitizerSuppression.cmake | 14 ++ cmake/LaghuBuildIdentity.cmake | 7 +- cmake/LaghuSanitizers.cmake | 127 ++++++++++++++++++ cmake/LaghuToolchain.cmake | 18 ++- cmake/ValidateSanitizerSuppression.cmake | 7 + tests/sanitizers/data_race.cpp | 22 +++ tests/sanitizers/heap_misuse.cpp | 7 + tests/sanitizers/negative/global.tsv | 1 + .../sanitizers/negative/invalid-sanitizer.tsv | 1 + tests/sanitizers/negative/missing-reason.tsv | 1 + tests/sanitizers/negative/third-party.tsv | 1 + tests/sanitizers/suppressions.tsv | 2 + tests/sanitizers/undefined_behavior.cpp | 8 ++ 18 files changed, 303 insertions(+), 39 deletions(-) create mode 100644 cmake/ExpectSanitizerFailure.cmake create mode 100644 cmake/ExpectSanitizerReleaseExclusion.cmake create mode 100644 cmake/ExpectSanitizerSuppression.cmake create mode 100644 cmake/LaghuSanitizers.cmake create mode 100644 cmake/ValidateSanitizerSuppression.cmake create mode 100644 tests/sanitizers/data_race.cpp create mode 100644 tests/sanitizers/heap_misuse.cpp create mode 100644 tests/sanitizers/negative/global.tsv create mode 100644 tests/sanitizers/negative/invalid-sanitizer.tsv create mode 100644 tests/sanitizers/negative/missing-reason.tsv create mode 100644 tests/sanitizers/negative/third-party.tsv create mode 100644 tests/sanitizers/suppressions.tsv create mode 100644 tests/sanitizers/undefined_behavior.cpp diff --git a/.github/workflows/toolchain.yml b/.github/workflows/toolchain.yml index 41e227c..e427ed6 100644 --- a/.github/workflows/toolchain.yml +++ b/.github/workflows/toolchain.yml @@ -58,18 +58,6 @@ jobs: --target laghu_crypto_provider_test ctest --test-dir "$RUNNER_TEMP/laghu-clang-crypto" --output-on-failure \ -R '^laghu.crypto.provider$' - - name: Verify Clang 19 crypto adapter under ASan and UBSan - if: matrix.name == 'clang-19-libc++' - run: | - cmake -S . -B "$RUNNER_TEMP/laghu-clang-crypto-sanitized" -G Ninja \ - -DCMAKE_CXX_COMPILER="${{ matrix.compiler }}" \ - -DCMAKE_CXX_FLAGS="${{ matrix.cxxflags }} -fsanitize=address,undefined -fno-omit-frame-pointer" \ - -DLAGHU_BUILD_PROFILE=CUSTOM \ - -DLAGHU_FEATURES=tls - cmake --build "$RUNNER_TEMP/laghu-clang-crypto-sanitized" \ - --target laghu_crypto_provider_test - ctest --test-dir "$RUNNER_TEMP/laghu-clang-crypto-sanitized" --output-on-failure \ - -R '^laghu.crypto.provider$' - name: Verify LibreSSL crypto adapter if: matrix.name == 'gcc-14-libstdc++' run: | @@ -168,6 +156,20 @@ jobs: aarch64-linux-gnu-ar t build/linux-aarch64-gcc/liblaghu_core.a test -f build/linux-aarch64-gcc/liblaghu_crypto.a aarch64-linux-gnu-ar t build/linux-aarch64-gcc/liblaghu_crypto.a + linux-clang-asan-ubsan: + runs-on: ubuntu-24.04 + steps: + - uses: actions/checkout@v7 + - name: Install Linux Clang ASan and UBSan toolchain + run: | + sudo rm -f /etc/apt/sources.list.d/google-chrome.list \ + /etc/apt/sources.list.d/google-chrome.sources + sudo apt-get update + sudo apt-get install --yes ninja-build clang-19 libc++-19-dev libc++abi-19-dev + - name: Run ordinary native suite under ASan and UBSan + run: | + cmake --preset linux-clang-asan-ubsan + cmake --build build/linux-clang-asan-ubsan --target laghu_verify_toolchain linux-clang-tsan: runs-on: ubuntu-24.04 steps: @@ -177,13 +179,8 @@ jobs: sudo rm -f /etc/apt/sources.list.d/google-chrome.list \ /etc/apt/sources.list.d/google-chrome.sources sudo apt-get update - sudo apt-get install --yes ninja-build clang-19 - - name: Run cancellation races under ThreadSanitizer + sudo apt-get install --yes ninja-build clang-19 libc++-19-dev libc++abi-19-dev + - name: Run concurrency targets under ThreadSanitizer run: | - cmake -S . -B "$RUNNER_TEMP/laghu-tsan" -G Ninja \ - -DCMAKE_CXX_COMPILER=clang++-19 \ - -DLAGHU_ENABLE_TSAN=ON - cmake --build "$RUNNER_TEMP/laghu-tsan" \ - --target laghu_core_deadlines_cancellation_tsan_test - ctest --test-dir "$RUNNER_TEMP/laghu-tsan" --output-on-failure \ - -R '^laghu.core.deadlines_cancellation.tsan$' + cmake --preset linux-clang-tsan + cmake --build build/linux-clang-tsan --target laghu_sanitizer_tsan_tests diff --git a/CMakeLists.txt b/CMakeLists.txt index e640a72..f4db7a9 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -3,8 +3,6 @@ cmake_minimum_required(VERSION 3.28) project(laghu LANGUAGES CXX) -option(LAGHU_ENABLE_TSAN "Build the Linux Clang ThreadSanitizer deadline race target" OFF) - if(CMAKE_SOURCE_DIR STREQUAL CMAKE_BINARY_DIR) message(FATAL_ERROR "Laghu requires an out-of-tree build. Configure with -S -B .") @@ -26,12 +24,14 @@ include(cmake/LaghuDependencyDag.cmake) include(cmake/LaghuApiBoundaries.cmake) include(cmake/LaghuDependencies.cmake) include(cmake/LaghuFeatures.cmake) +include(cmake/LaghuSanitizers.cmake) include(cmake/LaghuBuildVariants.cmake) include(cmake/LaghuBuildIdentity.cmake) include(cmake/LaghuTestRegistration.cmake) include(cmake/LaghuToolchain.cmake) laghu_configure_toolchain() +laghu_configure_sanitizer_profile() laghu_configure_build_variant() laghu_configure_dependency_registry() laghu_configure_dependency_modes() @@ -257,19 +257,7 @@ if(TARGET laghu_crypto) laghu_add_native_test(laghu.crypto.entropy_seam laghu_crypto_entropy_seam_test) endif() -if(LAGHU_ENABLE_TSAN) - if(NOT CMAKE_SYSTEM_NAME STREQUAL "Linux" OR NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang") - message(FATAL_ERROR "Laghu TSan target requires Linux Clang") - endif() - add_executable(laghu_core_deadlines_cancellation_tsan_test tests/core/deadlines_cancellation.cpp) - laghu_apply_first_party_contract(laghu_core_deadlines_cancellation_tsan_test) - laghu_configure_api_consumer(laghu_core_deadlines_cancellation_tsan_test core) - target_compile_options(laghu_core_deadlines_cancellation_tsan_test PRIVATE -fsanitize=thread) - target_link_options(laghu_core_deadlines_cancellation_tsan_test PRIVATE -fsanitize=thread) - target_link_libraries(laghu_core_deadlines_cancellation_tsan_test PRIVATE laghu_core Threads::Threads) - laghu_add_native_test(laghu.core.deadlines_cancellation.tsan - laghu_core_deadlines_cancellation_tsan_test) -endif() +laghu_add_sanitizer_fixture_targets() add_executable(laghu_os_iovec_translation_test tests/os/iovec_translation.cpp) laghu_apply_first_party_contract(laghu_os_iovec_translation_test) @@ -325,9 +313,17 @@ if(TARGET laghu_crypto_provider_test) list(APPEND laghu_verify_targets laghu_crypto laghu_crypto_provider_test laghu_crypto_entropy_seam_test) endif() +foreach(target IN ITEMS laghu_sanitizer_heap_misuse_fixture + laghu_sanitizer_undefined_behavior_fixture) + if(TARGET "${target}") + list(APPEND laghu_verify_targets "${target}") + endif() +endforeach() add_custom_target(laghu_verify_toolchain COMMAND "${CMAKE_CTEST_COMMAND}" --output-on-failure DEPENDS ${laghu_verify_targets} USES_TERMINAL COMMENT "Running Laghu's configured toolchain contract") + +laghu_add_sanitizer_test_target() diff --git a/CMakePresets.json b/CMakePresets.json index dfd66f0..21c43ab 100644 --- a/CMakePresets.json +++ b/CMakePresets.json @@ -25,6 +25,22 @@ "CMAKE_CXX_FLAGS": "-stdlib=libc++" } }, + { + "name": "linux-clang-asan-ubsan", + "displayName": "Linux Clang ASan and UBSan", + "inherits": "linux-clang", + "cacheVariables": { + "LAGHU_SANITIZER_PROFILE": "ASAN_UBSAN" + } + }, + { + "name": "linux-clang-tsan", + "displayName": "Linux Clang ThreadSanitizer", + "inherits": "linux-clang", + "cacheVariables": { + "LAGHU_SANITIZER_PROFILE": "TSAN" + } + }, { "name": "macos-appleclang", "displayName": "macOS Apple Clang", diff --git a/cmake/ExpectSanitizerFailure.cmake b/cmake/ExpectSanitizerFailure.cmake new file mode 100644 index 0000000..97af013 --- /dev/null +++ b/cmake/ExpectSanitizerFailure.cmake @@ -0,0 +1,28 @@ +# SPDX-License-Identifier: AGPL-3.0-only +if(NOT DEFINED EXECUTABLE OR NOT DEFINED EXPECTED) + message(FATAL_ERROR "Laghu sanitizer fixture expectation requires EXECUTABLE and EXPECTED") +endif() + +set(command "${CMAKE_COMMAND}" -E env) +foreach(environment IN ITEMS "${ENVIRONMENT_1}" "${ENVIRONMENT_2}") + if(NOT environment STREQUAL "") + list(APPEND command "${environment}") + endif() +endforeach() +list(APPEND command "${EXECUTABLE}") +execute_process(COMMAND ${command} + RESULT_VARIABLE result + OUTPUT_VARIABLE output + ERROR_VARIABLE diagnostics) +set(combined "${output}${diagnostics}") +if(result EQUAL 0) + message(FATAL_ERROR "Laghu sanitizer fixture expectation failed: fixture=${EXPECTED}; result=success") +endif() +if(EXPECTED STREQUAL "heap_misuse" AND NOT combined MATCHES "AddressSanitizer") + message(FATAL_ERROR "Laghu sanitizer fixture expectation failed: fixture=heap_misuse; report=missing_address_sanitizer") +elseif(EXPECTED STREQUAL "undefined_behavior" AND + NOT combined MATCHES "runtime error: signed integer overflow") + message(FATAL_ERROR "Laghu sanitizer fixture expectation failed: fixture=undefined_behavior; report=missing_undefined_sanitizer") +elseif(EXPECTED STREQUAL "data_race" AND NOT combined MATCHES "ThreadSanitizer") + message(FATAL_ERROR "Laghu sanitizer fixture expectation failed: fixture=data_race; report=missing_thread_sanitizer") +endif() diff --git a/cmake/ExpectSanitizerReleaseExclusion.cmake b/cmake/ExpectSanitizerReleaseExclusion.cmake new file mode 100644 index 0000000..aa29c6f --- /dev/null +++ b/cmake/ExpectSanitizerReleaseExclusion.cmake @@ -0,0 +1,17 @@ +# SPDX-License-Identifier: AGPL-3.0-only +if(NOT DEFINED ARCHIVE OR NOT DEFINED EXECUTABLE OR NOT DEFINED NM) + message(FATAL_ERROR "Laghu sanitizer release exclusion requires ARCHIVE EXECUTABLE and NM") +endif() + +foreach(artifact IN ITEMS "${ARCHIVE}" "${EXECUTABLE}") + execute_process(COMMAND "${NM}" -g "${artifact}" + RESULT_VARIABLE result + OUTPUT_VARIABLE symbols + ERROR_VARIABLE diagnostics) + if(NOT result EQUAL 0) + message(FATAL_ERROR "Laghu sanitizer release exclusion failed: artifact=${artifact}; nm=${diagnostics}") + endif() + if(symbols MATCHES "laghu_sanitizer_") + message(FATAL_ERROR "Laghu sanitizer release exclusion failed: artifact=${artifact}; test_symbol=present") + endif() +endforeach() diff --git a/cmake/ExpectSanitizerSuppression.cmake b/cmake/ExpectSanitizerSuppression.cmake new file mode 100644 index 0000000..8d58968 --- /dev/null +++ b/cmake/ExpectSanitizerSuppression.cmake @@ -0,0 +1,14 @@ +# SPDX-License-Identifier: AGPL-3.0-only +if(NOT DEFINED MANIFEST) + message(FATAL_ERROR "Laghu sanitizer suppression expectation requires MANIFEST") +endif() + +execute_process( + COMMAND "${CMAKE_COMMAND}" "-DMANIFEST=${MANIFEST}" + -P "${CMAKE_CURRENT_LIST_DIR}/ValidateSanitizerSuppression.cmake" + RESULT_VARIABLE result + OUTPUT_VARIABLE output + ERROR_VARIABLE diagnostics) +if(result EQUAL 0) + message(FATAL_ERROR "Laghu sanitizer suppression expectation failed: manifest=${MANIFEST}; rejection=missing") +endif() diff --git a/cmake/LaghuBuildIdentity.cmake b/cmake/LaghuBuildIdentity.cmake index ac14468..a6d1e8d 100644 --- a/cmake/LaghuBuildIdentity.cmake +++ b/cmake/LaghuBuildIdentity.cmake @@ -32,6 +32,7 @@ function(laghu_build_identity_input_hashes output) cmake/LaghuDependencies.cmake cmake/LaghuDependencyDag.cmake cmake/LaghuFeatures.cmake + cmake/LaghuSanitizers.cmake cmake/LaghuToolchain.cmake src/cli/main.cpp src/cli/private/laghu/cli/internal/build_manifest.hpp @@ -59,7 +60,8 @@ function(laghu_build_identity_input_hashes output) src/core/private/laghu/core/internal/mapping_operations.hpp src/os/io_operations.cpp src/os/private/laghu/os/internal/io_operations.hpp - tests/warnings/suppressions.tsv) + tests/warnings/suppressions.tsv + tests/sanitizers/suppressions.tsv) list(FIND LAGHU_EFFECTIVE_FEATURES tls tls_feature_index) if(NOT tls_feature_index EQUAL -1) list(APPEND inputs @@ -110,6 +112,7 @@ function(laghu_build_identity_verbose output build_id compiler requested effecti "product.name=laghu" "product.version=${LAGHU_PRODUCT_VERSION}" "profile=${LAGHU_BUILD_PROFILE}" + "sanitizer.profile=${LAGHU_SANITIZER_PROFILE}" "schema_version=${LAGHU_BUILD_MANIFEST_SCHEMA_VERSION}" "standard_library.id=${LAGHU_STANDARD_LIBRARY_ID}" "standard_library.version=${LAGHU_STANDARD_LIBRARY_VERSION}" @@ -166,7 +169,7 @@ function(laghu_configure_build_identity) laghu_build_identity_dependencies(dependencies_json dependency_names) set(preimage - "{\"schema_version\":\"${LAGHU_BUILD_MANIFEST_SCHEMA_VERSION}\",\"product\":{\"name\":\"laghu\",\"version\":\"${product_version}\"},\"build_inputs\":${inputs_json},\"compiler\":{\"executable\":\"${compiler}\",\"id\":\"${CMAKE_CXX_COMPILER_ID}\",\"version\":\"${CMAKE_CXX_COMPILER_VERSION}\"},\"standard_library\":{\"id\":\"${LAGHU_STANDARD_LIBRARY_ID}\",\"version\":\"${LAGHU_STANDARD_LIBRARY_VERSION}\"},\"target\":{\"os\":\"${CMAKE_SYSTEM_NAME}\",\"architecture\":\"${CMAKE_SYSTEM_PROCESSOR}\"},\"profile\":\"${LAGHU_BUILD_PROFILE}\",\"features\":{\"requested\":${requested_json},\"effective\":${effective_json}},\"dependencies\":${dependencies_json}}") + "{\"schema_version\":\"${LAGHU_BUILD_MANIFEST_SCHEMA_VERSION}\",\"product\":{\"name\":\"laghu\",\"version\":\"${product_version}\"},\"build_inputs\":${inputs_json},\"compiler\":{\"executable\":\"${compiler}\",\"id\":\"${CMAKE_CXX_COMPILER_ID}\",\"version\":\"${CMAKE_CXX_COMPILER_VERSION}\"},\"standard_library\":{\"id\":\"${LAGHU_STANDARD_LIBRARY_ID}\",\"version\":\"${LAGHU_STANDARD_LIBRARY_VERSION}\"},\"target\":{\"os\":\"${CMAKE_SYSTEM_NAME}\",\"architecture\":\"${CMAKE_SYSTEM_PROCESSOR}\"},\"profile\":\"${LAGHU_BUILD_PROFILE}\",\"sanitizer_profile\":\"${LAGHU_SANITIZER_PROFILE}\",\"features\":{\"requested\":${requested_json},\"effective\":${effective_json}},\"dependencies\":${dependencies_json}}") string(SHA256 build_id "${preimage}") set(manifest "${preimage}") string(REGEX REPLACE "}$" ",\"build_id\":\"${build_id}\"}" manifest "${manifest}") diff --git a/cmake/LaghuSanitizers.cmake b/cmake/LaghuSanitizers.cmake new file mode 100644 index 0000000..80c2c19 --- /dev/null +++ b/cmake/LaghuSanitizers.cmake @@ -0,0 +1,127 @@ +# SPDX-License-Identifier: AGPL-3.0-only +include_guard(GLOBAL) + +set(LAGHU_SANITIZER_PROFILE "NONE" CACHE STRING + "Laghu sanitizer profile: NONE, ASAN_UBSAN, or TSAN") +set_property(CACHE LAGHU_SANITIZER_PROFILE PROPERTY STRINGS NONE ASAN_UBSAN TSAN) + +function(laghu_sanitizer_fail detail) + message(FATAL_ERROR "Laghu sanitizer profile failed: ${detail}") +endfunction() + +function(laghu_validate_sanitizer_suppressions manifest) + if(NOT EXISTS "${manifest}") + laghu_sanitizer_fail("manifest=${manifest}; file is required") + endif() + file(STRINGS "${manifest}" lines) + foreach(line IN LISTS lines) + if(line MATCHES "^[ \t]*#" OR line STREQUAL "") + continue() + endif() + string(REPLACE "\t" ";" fields "${line}") + list(LENGTH fields field_count) + if(NOT field_count EQUAL 4) + laghu_sanitizer_fail("manifest=${manifest}; expected=sanitizer-platform-target_or_source-reason") + endif() + list(GET fields 0 sanitizer) + list(GET fields 1 platform) + list(GET fields 2 target_or_source) + list(GET fields 3 reason) + if(NOT sanitizer STREQUAL "address" AND NOT sanitizer STREQUAL "undefined" AND + NOT sanitizer STREQUAL "thread") + laghu_sanitizer_fail("sanitizer=${sanitizer}; expected=address-undefined-or-thread") + endif() + if(NOT platform STREQUAL "linux") + laghu_sanitizer_fail("platform=${platform}; expected=linux") + endif() + if(target_or_source MATCHES "(^|/)(all|global|third_party|vendor|external)(/|$)" OR + target_or_source MATCHES "[*?]") + laghu_sanitizer_fail("target_or_source=${target_or_source}; global_or_third_party_suppression_is_forbidden") + endif() + if(NOT target_or_source MATCHES "^(laghu_[A-Za-z0-9_]+|src/(core|config|protocol|tls|proxy|cache|control|cli|observability|os)/[A-Za-z0-9_./-]+\\.(cpp|cc|cxx))$") + laghu_sanitizer_fail("target_or_source=${target_or_source}; expected=one_laghu_target_or_governed_source") + endif() + if(reason STREQUAL "") + laghu_sanitizer_fail("target_or_source=${target_or_source}; technical reason is required") + endif() + endforeach() +endfunction() + +function(laghu_configure_sanitizer_profile) + if(NOT LAGHU_SANITIZER_PROFILE STREQUAL "NONE" AND + NOT LAGHU_SANITIZER_PROFILE STREQUAL "ASAN_UBSAN" AND + NOT LAGHU_SANITIZER_PROFILE STREQUAL "TSAN") + laghu_sanitizer_fail("profile=${LAGHU_SANITIZER_PROFILE}; expected=NONE-ASAN_UBSAN-or-TSAN") + endif() + laghu_validate_sanitizer_suppressions("${CMAKE_SOURCE_DIR}/tests/sanitizers/suppressions.tsv") + + set(compile_options) + set(link_options) + if(NOT LAGHU_SANITIZER_PROFILE STREQUAL "NONE") + if(NOT CMAKE_SYSTEM_NAME STREQUAL "Linux" OR NOT CMAKE_CXX_COMPILER_ID MATCHES "Clang") + laghu_sanitizer_fail("profile=${LAGHU_SANITIZER_PROFILE}; requires=linux_clang") + endif() + if(LAGHU_SANITIZER_PROFILE STREQUAL "ASAN_UBSAN") + set(compile_options -fsanitize=address,undefined -fno-omit-frame-pointer) + set(link_options -fsanitize=address,undefined) + else() + set(compile_options -fsanitize=thread -fno-omit-frame-pointer) + set(link_options -fsanitize=thread) + endif() + endif() + set(LAGHU_SANITIZER_COMPILE_OPTIONS "${compile_options}" CACHE INTERNAL + "Laghu sanitizer compile options") + set(LAGHU_SANITIZER_LINK_OPTIONS "${link_options}" CACHE INTERNAL + "Laghu sanitizer link options") +endfunction() + +function(laghu_add_sanitizer_fixture_targets) + if(LAGHU_SANITIZER_PROFILE STREQUAL "NONE" OR CMAKE_CROSSCOMPILING) + return() + endif() + if(LAGHU_SANITIZER_PROFILE STREQUAL "ASAN_UBSAN") + foreach(fixture IN ITEMS heap_misuse undefined_behavior) + set(target "laghu_sanitizer_${fixture}_fixture") + add_executable("${target}" "${CMAKE_SOURCE_DIR}/tests/sanitizers/${fixture}.cpp") + laghu_apply_first_party_contract("${target}") + laghu_configure_api_consumer("${target}" core) + add_test(NAME "laghu.sanitizer.fixture.${fixture}" + COMMAND "${CMAKE_COMMAND}" + "-DEXECUTABLE=$" + "-DENVIRONMENT_1=ASAN_OPTIONS=halt_on_error=1" + "-DENVIRONMENT_2=UBSAN_OPTIONS=halt_on_error=1" + "-DEXPECTED=${fixture}" + -P "${CMAKE_SOURCE_DIR}/cmake/ExpectSanitizerFailure.cmake") + endforeach() + else() + add_executable(laghu_core_deadlines_cancellation_tsan_test + tests/core/deadlines_cancellation.cpp) + laghu_apply_first_party_contract(laghu_core_deadlines_cancellation_tsan_test) + laghu_configure_api_consumer(laghu_core_deadlines_cancellation_tsan_test core) + target_link_libraries(laghu_core_deadlines_cancellation_tsan_test PRIVATE laghu_core Threads::Threads) + laghu_add_native_test(laghu.core.deadlines_cancellation.tsan + laghu_core_deadlines_cancellation_tsan_test) + + add_executable(laghu_sanitizer_data_race_fixture + "${CMAKE_SOURCE_DIR}/tests/sanitizers/data_race.cpp") + laghu_apply_first_party_contract(laghu_sanitizer_data_race_fixture) + target_link_libraries(laghu_sanitizer_data_race_fixture PRIVATE Threads::Threads) + add_test(NAME laghu.sanitizer.fixture.data_race + COMMAND "${CMAKE_COMMAND}" + "-DEXECUTABLE=$" + "-DENVIRONMENT_1=TSAN_OPTIONS=halt_on_error=1" + -DEXPECTED=data_race + -P "${CMAKE_SOURCE_DIR}/cmake/ExpectSanitizerFailure.cmake") + endif() +endfunction() + +function(laghu_add_sanitizer_test_target) + if(LAGHU_SANITIZER_PROFILE STREQUAL "TSAN" AND NOT CMAKE_CROSSCOMPILING) + add_custom_target(laghu_sanitizer_tsan_tests + COMMAND "${CMAKE_CTEST_COMMAND}" --output-on-failure + -R "^laghu\\.(core\\.deadlines_cancellation\\.tsan|sanitizer\\.fixture\\.data_race)$" + DEPENDS laghu_core_deadlines_cancellation_tsan_test laghu_sanitizer_data_race_fixture + USES_TERMINAL + COMMENT "Running Laghu concurrency tests under ThreadSanitizer") + endif() +endfunction() diff --git a/cmake/LaghuToolchain.cmake b/cmake/LaghuToolchain.cmake index 032d67a..6d67b52 100644 --- a/cmake/LaghuToolchain.cmake +++ b/cmake/LaghuToolchain.cmake @@ -273,7 +273,12 @@ function(laghu_apply_first_party_contract target) set_property(TARGET "${target}" PROPERTY CXX_EXTENSIONS OFF) set_property(TARGET "${target}" PROPERTY CXX_VISIBILITY_PRESET hidden) set_property(TARGET "${target}" PROPERTY VISIBILITY_INLINES_HIDDEN YES) - target_compile_options("${target}" PRIVATE -pedantic-errors -fno-exceptions -fno-rtti ${LAGHU_EFFECTIVE_WARNING_FLAGS}) + target_compile_options("${target}" PRIVATE + -pedantic-errors -fno-exceptions -fno-rtti ${LAGHU_EFFECTIVE_WARNING_FLAGS} + ${LAGHU_SANITIZER_COMPILE_OPTIONS}) + if(NOT LAGHU_SANITIZER_LINK_OPTIONS STREQUAL "") + target_link_options("${target}" PRIVATE ${LAGHU_SANITIZER_LINK_OPTIONS}) + endif() get_target_property(effective_options "${target}" COMPILE_OPTIONS) list(FIND effective_options -fexceptions enables_exceptions) list(FIND effective_options -frtti enables_rtti) @@ -320,6 +325,17 @@ function(laghu_add_validation_tests) foreach(fixture IN ITEMS broad-source invalid-warning missing-reason) add_test(NAME "laghu.warning.suppression_negative.${fixture}" COMMAND "${CMAKE_COMMAND}" -DMANIFEST=${CMAKE_SOURCE_DIR}/tests/warnings/negative/${fixture}.tsv -P "${CMAKE_SOURCE_DIR}/cmake/ExpectWarningSuppression.cmake") endforeach() + foreach(fixture IN ITEMS global third-party invalid-sanitizer missing-reason) + add_test(NAME "laghu.sanitizer.suppression_negative.${fixture}" COMMAND "${CMAKE_COMMAND}" + -DMANIFEST=${CMAKE_SOURCE_DIR}/tests/sanitizers/negative/${fixture}.tsv + -P "${CMAKE_SOURCE_DIR}/cmake/ExpectSanitizerSuppression.cmake") + endforeach() + add_test(NAME laghu.sanitizer.release_exclusion + COMMAND "${CMAKE_COMMAND}" + "-DARCHIVE=$" + "-DEXECUTABLE=$" + "-DNM=${CMAKE_NM}" + -P "${CMAKE_SOURCE_DIR}/cmake/ExpectSanitizerReleaseExclusion.cmake") foreach(mode IN ITEMS all_enabled baseline_unavailable) string(REPLACE "_" "-" golden_mode "${mode}") add_test(NAME "laghu.capabilities.golden.${mode}" diff --git a/cmake/ValidateSanitizerSuppression.cmake b/cmake/ValidateSanitizerSuppression.cmake new file mode 100644 index 0000000..03fb27a --- /dev/null +++ b/cmake/ValidateSanitizerSuppression.cmake @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: AGPL-3.0-only +if(NOT DEFINED MANIFEST) + message(FATAL_ERROR "Laghu sanitizer suppression validation requires MANIFEST") +endif() + +include("${CMAKE_CURRENT_LIST_DIR}/LaghuSanitizers.cmake") +laghu_validate_sanitizer_suppressions("${MANIFEST}") diff --git a/tests/sanitizers/data_race.cpp b/tests/sanitizers/data_race.cpp new file mode 100644 index 0000000..e014fb5 --- /dev/null +++ b/tests/sanitizers/data_race.cpp @@ -0,0 +1,22 @@ +// SPDX-License-Identifier: AGPL-3.0-only +#include + +namespace { + +int shared_value{}; + +void increment() noexcept { + for (int index = 0; index < 1024; ++index) { + ++shared_value; + } +} + +} // namespace + +int main() { + std::thread first{increment}; + std::thread second{increment}; + first.join(); + second.join(); + return shared_value == 0 ? 1 : 0; +} diff --git a/tests/sanitizers/heap_misuse.cpp b/tests/sanitizers/heap_misuse.cpp new file mode 100644 index 0000000..83c3ccd --- /dev/null +++ b/tests/sanitizers/heap_misuse.cpp @@ -0,0 +1,7 @@ +// SPDX-License-Identifier: AGPL-3.0-only +int main() { + int* const values = new int[1]; + values[1] = 1; + delete[] values; + return 0; +} diff --git a/tests/sanitizers/negative/global.tsv b/tests/sanitizers/negative/global.tsv new file mode 100644 index 0000000..e1b318d --- /dev/null +++ b/tests/sanitizers/negative/global.tsv @@ -0,0 +1 @@ +address linux all global suppression is forbidden diff --git a/tests/sanitizers/negative/invalid-sanitizer.tsv b/tests/sanitizers/negative/invalid-sanitizer.tsv new file mode 100644 index 0000000..c0a2092 --- /dev/null +++ b/tests/sanitizers/negative/invalid-sanitizer.tsv @@ -0,0 +1 @@ +memory linux laghu_core invalid sanitizer is forbidden diff --git a/tests/sanitizers/negative/missing-reason.tsv b/tests/sanitizers/negative/missing-reason.tsv new file mode 100644 index 0000000..7ea6a63 --- /dev/null +++ b/tests/sanitizers/negative/missing-reason.tsv @@ -0,0 +1 @@ +thread linux laghu_core diff --git a/tests/sanitizers/negative/third-party.tsv b/tests/sanitizers/negative/third-party.tsv new file mode 100644 index 0000000..000f896 --- /dev/null +++ b/tests/sanitizers/negative/third-party.tsv @@ -0,0 +1 @@ +address linux third_party/library.cpp third-party masking is forbidden diff --git a/tests/sanitizers/suppressions.tsv b/tests/sanitizers/suppressions.tsv new file mode 100644 index 0000000..b4e1cba --- /dev/null +++ b/tests/sanitizers/suppressions.tsv @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: AGPL-3.0-only +# sanitizer\tplatform\ttarget_or_source\ttechnical reason diff --git a/tests/sanitizers/undefined_behavior.cpp b/tests/sanitizers/undefined_behavior.cpp new file mode 100644 index 0000000..6490ece --- /dev/null +++ b/tests/sanitizers/undefined_behavior.cpp @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: AGPL-3.0-only +#include + +int main() { + volatile int maximum = std::numeric_limits::max(); + volatile int one = 1; + return maximum + one; +} From 18d04941d6d4dafa2d5e7f163fd0cf6f85669c79 Mon Sep 17 00:00:00 2001 From: Nitesh Purohit Date: Thu, 10 Sep 2026 21:17:59 -0400 Subject: [PATCH 2/4] feat: enhance sanitizer configurations and tests - Updated ExpectSanitizerFailure.cmake to check for specific error messages related to heap misuse and data races. - Introduced ExpectSanitizerReconfigure.cmake to validate sanitizer configurations and ensure proper flags are set. - Enhanced ExpectSanitizerReleaseExclusion.cmake to include BUILD_DIRECTORY in error checks. - Modified ExpectSanitizerSuppression.cmake to require both MANIFEST and EXPECTED_DIAGNOSTIC for validation. - Improved LaghuSanitizers.cmake to handle varying field counts in suppression manifests and added checks for technical reasons. - Added new test case for whitespace reason in sanitizer suppression. --- cmake/ExpectSanitizerFailure.cmake | 10 +++--- cmake/ExpectSanitizerReconfigure.cmake | 32 +++++++++++++++++++ cmake/ExpectSanitizerReleaseExclusion.cmake | 14 ++++++-- cmake/ExpectSanitizerSuppression.cmake | 8 +++-- cmake/LaghuSanitizers.cmake | 23 +++++++++---- cmake/LaghuToolchain.cmake | 15 ++++++++- .../sanitizers/negative/whitespace-reason.tsv | 1 + 7 files changed, 88 insertions(+), 15 deletions(-) create mode 100644 cmake/ExpectSanitizerReconfigure.cmake create mode 100644 tests/sanitizers/negative/whitespace-reason.tsv diff --git a/cmake/ExpectSanitizerFailure.cmake b/cmake/ExpectSanitizerFailure.cmake index 97af013..08931f4 100644 --- a/cmake/ExpectSanitizerFailure.cmake +++ b/cmake/ExpectSanitizerFailure.cmake @@ -18,11 +18,13 @@ set(combined "${output}${diagnostics}") if(result EQUAL 0) message(FATAL_ERROR "Laghu sanitizer fixture expectation failed: fixture=${EXPECTED}; result=success") endif() -if(EXPECTED STREQUAL "heap_misuse" AND NOT combined MATCHES "AddressSanitizer") - message(FATAL_ERROR "Laghu sanitizer fixture expectation failed: fixture=heap_misuse; report=missing_address_sanitizer") +if(EXPECTED STREQUAL "heap_misuse" AND + NOT combined MATCHES "ERROR: AddressSanitizer: heap-buffer-overflow") + message(FATAL_ERROR "Laghu sanitizer fixture expectation failed: fixture=heap_misuse; report=missing_heap_buffer_overflow") elseif(EXPECTED STREQUAL "undefined_behavior" AND NOT combined MATCHES "runtime error: signed integer overflow") message(FATAL_ERROR "Laghu sanitizer fixture expectation failed: fixture=undefined_behavior; report=missing_undefined_sanitizer") -elseif(EXPECTED STREQUAL "data_race" AND NOT combined MATCHES "ThreadSanitizer") - message(FATAL_ERROR "Laghu sanitizer fixture expectation failed: fixture=data_race; report=missing_thread_sanitizer") +elseif(EXPECTED STREQUAL "data_race" AND + NOT combined MATCHES "WARNING: ThreadSanitizer: data race") + message(FATAL_ERROR "Laghu sanitizer fixture expectation failed: fixture=data_race; report=missing_data_race") endif() diff --git a/cmake/ExpectSanitizerReconfigure.cmake b/cmake/ExpectSanitizerReconfigure.cmake new file mode 100644 index 0000000..f65ab2b --- /dev/null +++ b/cmake/ExpectSanitizerReconfigure.cmake @@ -0,0 +1,32 @@ +# SPDX-License-Identifier: AGPL-3.0-only +if(NOT DEFINED LAGHU_SOURCE) + message(FATAL_ERROR "Laghu sanitizer reconfigure expectation requires LAGHU_SOURCE") +endif() + +set(CMAKE_SOURCE_DIR "${LAGHU_SOURCE}") +set(CMAKE_SYSTEM_NAME Linux) +set(CMAKE_CXX_COMPILER_ID Clang) +include("${LAGHU_SOURCE}/cmake/LaghuSanitizers.cmake") + +set(LAGHU_SANITIZER_PROFILE ASAN_UBSAN) +laghu_configure_sanitizer_profile() +if(NOT LAGHU_SANITIZER_COMPILE_OPTIONS MATCHES "-fsanitize=address,undefined" OR + NOT LAGHU_SANITIZER_COMPILE_OPTIONS MATCHES "-fno-sanitize-recover=undefined" OR + NOT LAGHU_SANITIZER_LINK_OPTIONS STREQUAL "-fsanitize=address,undefined") + message(FATAL_ERROR "Laghu sanitizer reconfigure expectation failed: asan_ubsan_flags_missing") +endif() + +set(LAGHU_SANITIZER_PROFILE NONE) +laghu_configure_sanitizer_profile() +if(NOT LAGHU_SANITIZER_COMPILE_OPTIONS STREQUAL "" OR + NOT LAGHU_SANITIZER_LINK_OPTIONS STREQUAL "") + message(FATAL_ERROR "Laghu sanitizer reconfigure expectation failed: none_retained_stale_flags") +endif() + +set(LAGHU_SANITIZER_PROFILE TSAN) +laghu_configure_sanitizer_profile() +if(NOT LAGHU_SANITIZER_COMPILE_OPTIONS MATCHES "-fsanitize=thread" OR + LAGHU_SANITIZER_COMPILE_OPTIONS MATCHES "address" OR + NOT LAGHU_SANITIZER_LINK_OPTIONS STREQUAL "-fsanitize=thread") + message(FATAL_ERROR "Laghu sanitizer reconfigure expectation failed: tsan_retained_stale_flags") +endif() diff --git a/cmake/ExpectSanitizerReleaseExclusion.cmake b/cmake/ExpectSanitizerReleaseExclusion.cmake index aa29c6f..9829fc3 100644 --- a/cmake/ExpectSanitizerReleaseExclusion.cmake +++ b/cmake/ExpectSanitizerReleaseExclusion.cmake @@ -1,6 +1,16 @@ # SPDX-License-Identifier: AGPL-3.0-only -if(NOT DEFINED ARCHIVE OR NOT DEFINED EXECUTABLE OR NOT DEFINED NM) - message(FATAL_ERROR "Laghu sanitizer release exclusion requires ARCHIVE EXECUTABLE and NM") +if(NOT DEFINED BUILD_DIRECTORY OR NOT DEFINED ARCHIVE OR NOT DEFINED EXECUTABLE OR NOT DEFINED NM) + message(FATAL_ERROR "Laghu sanitizer release exclusion requires BUILD_DIRECTORY ARCHIVE EXECUTABLE and NM") +endif() + +if(NOT EXISTS "${ARCHIVE}" OR NOT EXISTS "${EXECUTABLE}") + execute_process(COMMAND "${CMAKE_COMMAND}" --build "${BUILD_DIRECTORY}" --target laghu_core laghu + RESULT_VARIABLE build_result + OUTPUT_VARIABLE build_output + ERROR_VARIABLE build_diagnostics) + if(NOT build_result EQUAL 0) + message(FATAL_ERROR "Laghu sanitizer release exclusion failed: build=${build_output}${build_diagnostics}") + endif() endif() foreach(artifact IN ITEMS "${ARCHIVE}" "${EXECUTABLE}") diff --git a/cmake/ExpectSanitizerSuppression.cmake b/cmake/ExpectSanitizerSuppression.cmake index 8d58968..d37a133 100644 --- a/cmake/ExpectSanitizerSuppression.cmake +++ b/cmake/ExpectSanitizerSuppression.cmake @@ -1,6 +1,6 @@ # SPDX-License-Identifier: AGPL-3.0-only -if(NOT DEFINED MANIFEST) - message(FATAL_ERROR "Laghu sanitizer suppression expectation requires MANIFEST") +if(NOT DEFINED MANIFEST OR NOT DEFINED EXPECTED_DIAGNOSTIC) + message(FATAL_ERROR "Laghu sanitizer suppression expectation requires MANIFEST and EXPECTED_DIAGNOSTIC") endif() execute_process( @@ -12,3 +12,7 @@ execute_process( if(result EQUAL 0) message(FATAL_ERROR "Laghu sanitizer suppression expectation failed: manifest=${MANIFEST}; rejection=missing") endif() +set(combined "${output}${diagnostics}") +if(NOT combined MATCHES "${EXPECTED_DIAGNOSTIC}") + message(FATAL_ERROR "Laghu sanitizer suppression expectation failed: manifest=${MANIFEST}; diagnostic=${EXPECTED_DIAGNOSTIC}; rejection=unrelated") +endif() diff --git a/cmake/LaghuSanitizers.cmake b/cmake/LaghuSanitizers.cmake index 80c2c19..e74129d 100644 --- a/cmake/LaghuSanitizers.cmake +++ b/cmake/LaghuSanitizers.cmake @@ -20,7 +20,9 @@ function(laghu_validate_sanitizer_suppressions manifest) endif() string(REPLACE "\t" ";" fields "${line}") list(LENGTH fields field_count) - if(NOT field_count EQUAL 4) + if(field_count EQUAL 3) + list(APPEND fields "") + elseif(NOT field_count EQUAL 4) laghu_sanitizer_fail("manifest=${manifest}; expected=sanitizer-platform-target_or_source-reason") endif() list(GET fields 0 sanitizer) @@ -41,8 +43,9 @@ function(laghu_validate_sanitizer_suppressions manifest) if(NOT target_or_source MATCHES "^(laghu_[A-Za-z0-9_]+|src/(core|config|protocol|tls|proxy|cache|control|cli|observability|os)/[A-Za-z0-9_./-]+\\.(cpp|cc|cxx))$") laghu_sanitizer_fail("target_or_source=${target_or_source}; expected=one_laghu_target_or_governed_source") endif() + string(STRIP "${reason}" reason) if(reason STREQUAL "") - laghu_sanitizer_fail("target_or_source=${target_or_source}; technical reason is required") + laghu_sanitizer_fail("target_or_source=${target_or_source}; technical_reason_required") endif() endforeach() endfunction() @@ -62,7 +65,8 @@ function(laghu_configure_sanitizer_profile) laghu_sanitizer_fail("profile=${LAGHU_SANITIZER_PROFILE}; requires=linux_clang") endif() if(LAGHU_SANITIZER_PROFILE STREQUAL "ASAN_UBSAN") - set(compile_options -fsanitize=address,undefined -fno-omit-frame-pointer) + set(compile_options -fsanitize=address,undefined -fno-omit-frame-pointer + -fno-sanitize-recover=undefined) set(link_options -fsanitize=address,undefined) else() set(compile_options -fsanitize=thread -fno-omit-frame-pointer) @@ -70,9 +74,9 @@ function(laghu_configure_sanitizer_profile) endif() endif() set(LAGHU_SANITIZER_COMPILE_OPTIONS "${compile_options}" CACHE INTERNAL - "Laghu sanitizer compile options") + "Laghu sanitizer compile options" FORCE) set(LAGHU_SANITIZER_LINK_OPTIONS "${link_options}" CACHE INTERNAL - "Laghu sanitizer link options") + "Laghu sanitizer link options" FORCE) endfunction() function(laghu_add_sanitizer_fixture_targets) @@ -85,6 +89,11 @@ function(laghu_add_sanitizer_fixture_targets) add_executable("${target}" "${CMAKE_SOURCE_DIR}/tests/sanitizers/${fixture}.cpp") laghu_apply_first_party_contract("${target}") laghu_configure_api_consumer("${target}" core) + if(fixture STREQUAL "heap_misuse" AND CMAKE_CXX_COMPILER_ID MATCHES "Clang") + # This isolated fixture must perform an unchecked access for ASan to detect. + set_source_files_properties("${CMAKE_SOURCE_DIR}/tests/sanitizers/heap_misuse.cpp" + PROPERTIES COMPILE_OPTIONS -Wno-unsafe-buffer-usage) + endif() add_test(NAME "laghu.sanitizer.fixture.${fixture}" COMMAND "${CMAKE_COMMAND}" "-DEXECUTABLE=$" @@ -119,7 +128,9 @@ function(laghu_add_sanitizer_test_target) if(LAGHU_SANITIZER_PROFILE STREQUAL "TSAN" AND NOT CMAKE_CROSSCOMPILING) add_custom_target(laghu_sanitizer_tsan_tests COMMAND "${CMAKE_CTEST_COMMAND}" --output-on-failure - -R "^laghu\\.(core\\.deadlines_cancellation\\.tsan|sanitizer\\.fixture\\.data_race)$" + -R "laghu.core.deadlines_cancellation.tsan" + COMMAND "${CMAKE_CTEST_COMMAND}" --output-on-failure + -R "laghu.sanitizer.fixture.data_race" DEPENDS laghu_core_deadlines_cancellation_tsan_test laghu_sanitizer_data_race_fixture USES_TERMINAL COMMENT "Running Laghu concurrency tests under ThreadSanitizer") diff --git a/cmake/LaghuToolchain.cmake b/cmake/LaghuToolchain.cmake index 6d67b52..4dba2aa 100644 --- a/cmake/LaghuToolchain.cmake +++ b/cmake/LaghuToolchain.cmake @@ -325,13 +325,26 @@ function(laghu_add_validation_tests) foreach(fixture IN ITEMS broad-source invalid-warning missing-reason) add_test(NAME "laghu.warning.suppression_negative.${fixture}" COMMAND "${CMAKE_COMMAND}" -DMANIFEST=${CMAKE_SOURCE_DIR}/tests/warnings/negative/${fixture}.tsv -P "${CMAKE_SOURCE_DIR}/cmake/ExpectWarningSuppression.cmake") endforeach() - foreach(fixture IN ITEMS global third-party invalid-sanitizer missing-reason) + foreach(fixture IN ITEMS global third-party invalid-sanitizer missing-reason whitespace-reason) + if(fixture STREQUAL "global" OR fixture STREQUAL "third-party") + set(expected_sanitizer_diagnostic global_or_third_party_suppression_is_forbidden) + elseif(fixture STREQUAL "invalid-sanitizer") + set(expected_sanitizer_diagnostic expected=address-undefined-or-thread) + else() + set(expected_sanitizer_diagnostic technical_reason_required) + endif() add_test(NAME "laghu.sanitizer.suppression_negative.${fixture}" COMMAND "${CMAKE_COMMAND}" -DMANIFEST=${CMAKE_SOURCE_DIR}/tests/sanitizers/negative/${fixture}.tsv + "-DEXPECTED_DIAGNOSTIC=${expected_sanitizer_diagnostic}" -P "${CMAKE_SOURCE_DIR}/cmake/ExpectSanitizerSuppression.cmake") endforeach() + add_test(NAME laghu.sanitizer.reconfigure + COMMAND "${CMAKE_COMMAND}" + "-DLAGHU_SOURCE=${CMAKE_SOURCE_DIR}" + -P "${CMAKE_SOURCE_DIR}/cmake/ExpectSanitizerReconfigure.cmake") add_test(NAME laghu.sanitizer.release_exclusion COMMAND "${CMAKE_COMMAND}" + "-DBUILD_DIRECTORY=${CMAKE_BINARY_DIR}" "-DARCHIVE=$" "-DEXECUTABLE=$" "-DNM=${CMAKE_NM}" diff --git a/tests/sanitizers/negative/whitespace-reason.tsv b/tests/sanitizers/negative/whitespace-reason.tsv new file mode 100644 index 0000000..3b27e22 --- /dev/null +++ b/tests/sanitizers/negative/whitespace-reason.tsv @@ -0,0 +1 @@ +thread linux laghu_core From 8e0acc7e7f694019b6e492d66641546196b13863 Mon Sep 17 00:00:00 2001 From: Nitesh Purohit Date: Thu, 10 Sep 2026 21:33:34 -0400 Subject: [PATCH 3/4] feat: enhance sanitizer validation logic - Improved the sanitizer suppression validation by adding checks for the expected number of fields. - Enhanced error handling for invalid sanitizer profiles to provide clearer feedback. - Streamlined the extraction of sanitizer details from the manifest for better readability and maintainability. --- cmake/ExpectBuildIdentityDeterminism.cmake | 8 ++++++++ cmake/LaghuSanitizers.cmake | 14 +++++++++----- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/cmake/ExpectBuildIdentityDeterminism.cmake b/cmake/ExpectBuildIdentityDeterminism.cmake index 35854dd..305b912 100644 --- a/cmake/ExpectBuildIdentityDeterminism.cmake +++ b/cmake/ExpectBuildIdentityDeterminism.cmake @@ -8,6 +8,14 @@ set(work "${CMAKE_CURRENT_BINARY_DIR}/build-identity-determinism") file(REMOVE_RECURSE "${work}") file(MAKE_DIRECTORY "${work}") file(GLOB source_entries RELATIVE "${LAGHU_SOURCE}" "${LAGHU_SOURCE}/*") +list(REMOVE_ITEM source_entries build) +file(RELATIVE_PATH active_binary_relative "${LAGHU_SOURCE}" "${CMAKE_CURRENT_BINARY_DIR}") +if(NOT active_binary_relative MATCHES "^\\.\\." AND NOT active_binary_relative STREQUAL ".") + string(REGEX MATCH "^[^/]+" active_binary_root "${active_binary_relative}") + if(NOT active_binary_root STREQUAL "") + list(REMOVE_ITEM source_entries "${active_binary_root}") + endif() +endif() foreach(copy_name IN ITEMS source-a source-b source-changed) file(MAKE_DIRECTORY "${work}/${copy_name}") foreach(entry IN LISTS source_entries) diff --git a/cmake/LaghuSanitizers.cmake b/cmake/LaghuSanitizers.cmake index e74129d..6840b60 100644 --- a/cmake/LaghuSanitizers.cmake +++ b/cmake/LaghuSanitizers.cmake @@ -21,14 +21,18 @@ function(laghu_validate_sanitizer_suppressions manifest) string(REPLACE "\t" ";" fields "${line}") list(LENGTH fields field_count) if(field_count EQUAL 3) - list(APPEND fields "") + list(GET fields 0 sanitizer) + list(GET fields 1 platform) + list(GET fields 2 target_or_source) + set(reason "") elseif(NOT field_count EQUAL 4) laghu_sanitizer_fail("manifest=${manifest}; expected=sanitizer-platform-target_or_source-reason") + else() + list(GET fields 0 sanitizer) + list(GET fields 1 platform) + list(GET fields 2 target_or_source) + list(GET fields 3 reason) endif() - list(GET fields 0 sanitizer) - list(GET fields 1 platform) - list(GET fields 2 target_or_source) - list(GET fields 3 reason) if(NOT sanitizer STREQUAL "address" AND NOT sanitizer STREQUAL "undefined" AND NOT sanitizer STREQUAL "thread") laghu_sanitizer_fail("sanitizer=${sanitizer}; expected=address-undefined-or-thread") From fdacafe2a7d0ba763edf7de462faac572ef3f13b Mon Sep 17 00:00:00 2001 From: Nitesh Purohit Date: Thu, 10 Sep 2026 22:08:28 -0400 Subject: [PATCH 4/4] feat: enhance sanitizer profiles and validation tests --- .github/workflows/toolchain.yml | 14 +++++++ README.md | 2 +- cmake/ExpectSanitizerMarkerRejection.cmake | 27 +++++++++++++ cmake/ExpectSanitizerReleaseExclusion.cmake | 33 ++++++++++------ cmake/ExpectSanitizerSuppression.cmake | 6 +-- cmake/LaghuSanitizers.cmake | 16 +++++++- cmake/LaghuToolchain.cmake | 38 ++++++++++++++++--- cmake/ValidateSanitizerSuppression.cmake | 6 +-- docs/normative/build.md | 2 +- tests/sanitizers/data_race.cpp | 7 ++++ tests/sanitizers/heap_misuse.cpp | 7 ++++ .../sanitizers/negative/current-directory.tsv | 2 + tests/sanitizers/negative/global.tsv | 1 + .../sanitizers/negative/invalid-sanitizer.tsv | 1 + tests/sanitizers/negative/missing-reason.tsv | 1 + .../negative/nonexistent-source.tsv | 2 + tests/sanitizers/negative/third-party.tsv | 1 + tests/sanitizers/negative/traversal.tsv | 2 + .../sanitizers/negative/whitespace-reason.tsv | 1 + tests/sanitizers/undefined_behavior.cpp | 7 ++++ 20 files changed, 150 insertions(+), 26 deletions(-) create mode 100644 cmake/ExpectSanitizerMarkerRejection.cmake create mode 100644 tests/sanitizers/negative/current-directory.tsv create mode 100644 tests/sanitizers/negative/nonexistent-source.tsv create mode 100644 tests/sanitizers/negative/traversal.tsv diff --git a/.github/workflows/toolchain.yml b/.github/workflows/toolchain.yml index e427ed6..2cdf7c6 100644 --- a/.github/workflows/toolchain.yml +++ b/.github/workflows/toolchain.yml @@ -170,6 +170,20 @@ jobs: run: | cmake --preset linux-clang-asan-ubsan cmake --build build/linux-clang-asan-ubsan --target laghu_verify_toolchain + - name: Run TLS crypto adapter under ASan and UBSan + run: | + cmake -S . -B "$RUNNER_TEMP/laghu-asan-crypto" -G Ninja \ + -DCMAKE_CXX_COMPILER=clang++-19 \ + -DCMAKE_CXX_FLAGS=-stdlib=libc++ \ + -DLAGHU_SANITIZER_PROFILE=ASAN_UBSAN \ + -DLAGHU_BUILD_PROFILE=CUSTOM \ + -DLAGHU_FEATURES=tls + cmake --build "$RUNNER_TEMP/laghu-asan-crypto" \ + --target laghu_crypto_provider_test laghu_crypto_entropy_seam_test + ctest --test-dir "$RUNNER_TEMP/laghu-asan-crypto" --output-on-failure \ + -R '^laghu.crypto.provider$' + ctest --test-dir "$RUNNER_TEMP/laghu-asan-crypto" --output-on-failure \ + -R '^laghu.crypto.entropy_seam$' linux-clang-tsan: runs-on: ubuntu-24.04 steps: diff --git a/README.md b/README.md index 4339955..d9fb2b2 100644 --- a/README.md +++ b/README.md @@ -16,7 +16,7 @@ cmake --build build/linux-gcc ctest --test-dir build/linux-gcc --output-on-failure ``` -Other native presets are `linux-clang`, `macos-appleclang`, and `freebsd-clang`. The `linux-aarch64-gcc` preset is compile-only and does not execute target binaries. +Other native presets are `linux-clang`, `macos-appleclang`, and `freebsd-clang`. Linux Clang sanitizer presets are `linux-clang-asan-ubsan` and `linux-clang-tsan`. The `linux-aarch64-gcc` preset is compile-only and does not execute target binaries. Stage an installation with the standard CMake interface: diff --git a/cmake/ExpectSanitizerMarkerRejection.cmake b/cmake/ExpectSanitizerMarkerRejection.cmake new file mode 100644 index 0000000..3ff5e24 --- /dev/null +++ b/cmake/ExpectSanitizerMarkerRejection.cmake @@ -0,0 +1,27 @@ +# SPDX-License-Identifier: AGPL-3.0-only +if(NOT DEFINED BUILD_DIRECTORY OR NOT DEFINED MARKER_ARTIFACT OR NOT DEFINED MARKER OR + NOT DEFINED MARKER_PREFIX OR NOT DEFINED MARKER_TARGET OR NOT DEFINED NM) + message(FATAL_ERROR "Laghu sanitizer marker rejection requires BUILD_DIRECTORY MARKER_ARTIFACT MARKER MARKER_PREFIX MARKER_TARGET and NM") +endif() + +execute_process( + COMMAND "${CMAKE_COMMAND}" + "-DBUILD_DIRECTORY=${BUILD_DIRECTORY}" + "-DARCHIVE=${MARKER_ARTIFACT}" + "-DEXECUTABLE=${MARKER_ARTIFACT}" + "-DNM=${NM}" + "-DMARKER_ARTIFACT=${MARKER_ARTIFACT}" + "-DMARKER=${MARKER}" + "-DMARKER_PREFIX=${MARKER_PREFIX}" + "-DMARKER_TARGET=${MARKER_TARGET}" + -P "${CMAKE_CURRENT_LIST_DIR}/ExpectSanitizerReleaseExclusion.cmake" + RESULT_VARIABLE result + OUTPUT_VARIABLE output + ERROR_VARIABLE diagnostics) +if(result EQUAL 0) + message(FATAL_ERROR "Laghu sanitizer marker rejection failed: marker=${MARKER}; rejection=missing") +endif() +set(combined "${output}${diagnostics}") +if(NOT combined MATCHES "test_symbol=present") + message(FATAL_ERROR "Laghu sanitizer marker rejection failed: marker=${MARKER}; rejection=unrelated") +endif() diff --git a/cmake/ExpectSanitizerReleaseExclusion.cmake b/cmake/ExpectSanitizerReleaseExclusion.cmake index 9829fc3..1594c6c 100644 --- a/cmake/ExpectSanitizerReleaseExclusion.cmake +++ b/cmake/ExpectSanitizerReleaseExclusion.cmake @@ -1,16 +1,27 @@ # SPDX-License-Identifier: AGPL-3.0-only -if(NOT DEFINED BUILD_DIRECTORY OR NOT DEFINED ARCHIVE OR NOT DEFINED EXECUTABLE OR NOT DEFINED NM) - message(FATAL_ERROR "Laghu sanitizer release exclusion requires BUILD_DIRECTORY ARCHIVE EXECUTABLE and NM") +if(NOT DEFINED BUILD_DIRECTORY OR NOT DEFINED ARCHIVE OR NOT DEFINED EXECUTABLE OR NOT DEFINED NM OR + NOT DEFINED MARKER_ARTIFACT OR NOT DEFINED MARKER OR NOT DEFINED MARKER_PREFIX OR NOT DEFINED MARKER_TARGET) + message(FATAL_ERROR "Laghu sanitizer release exclusion requires BUILD_DIRECTORY ARCHIVE EXECUTABLE NM MARKER_ARTIFACT MARKER MARKER_PREFIX and MARKER_TARGET") endif() -if(NOT EXISTS "${ARCHIVE}" OR NOT EXISTS "${EXECUTABLE}") - execute_process(COMMAND "${CMAKE_COMMAND}" --build "${BUILD_DIRECTORY}" --target laghu_core laghu - RESULT_VARIABLE build_result - OUTPUT_VARIABLE build_output - ERROR_VARIABLE build_diagnostics) - if(NOT build_result EQUAL 0) - message(FATAL_ERROR "Laghu sanitizer release exclusion failed: build=${build_output}${build_diagnostics}") - endif() +execute_process(COMMAND "${CMAKE_COMMAND}" --build "${BUILD_DIRECTORY}" --target + laghu_core laghu "${MARKER_TARGET}" + RESULT_VARIABLE build_result + OUTPUT_VARIABLE build_output + ERROR_VARIABLE build_diagnostics) +if(NOT build_result EQUAL 0) + message(FATAL_ERROR "Laghu sanitizer release exclusion failed: build=${build_output}${build_diagnostics}") +endif() + +execute_process(COMMAND "${NM}" -g "${MARKER_ARTIFACT}" + RESULT_VARIABLE marker_result + OUTPUT_VARIABLE marker_symbols + ERROR_VARIABLE marker_diagnostics) +if(NOT marker_result EQUAL 0) + message(FATAL_ERROR "Laghu sanitizer release exclusion failed: marker_artifact=${MARKER_ARTIFACT}; nm=${marker_diagnostics}") +endif() +if(NOT marker_symbols MATCHES "${MARKER}") + message(FATAL_ERROR "Laghu sanitizer release exclusion failed: marker_artifact=${MARKER_ARTIFACT}; test_symbol=missing") endif() foreach(artifact IN ITEMS "${ARCHIVE}" "${EXECUTABLE}") @@ -21,7 +32,7 @@ foreach(artifact IN ITEMS "${ARCHIVE}" "${EXECUTABLE}") if(NOT result EQUAL 0) message(FATAL_ERROR "Laghu sanitizer release exclusion failed: artifact=${artifact}; nm=${diagnostics}") endif() - if(symbols MATCHES "laghu_sanitizer_") + if(symbols MATCHES "${MARKER_PREFIX}") message(FATAL_ERROR "Laghu sanitizer release exclusion failed: artifact=${artifact}; test_symbol=present") endif() endforeach() diff --git a/cmake/ExpectSanitizerSuppression.cmake b/cmake/ExpectSanitizerSuppression.cmake index d37a133..6deb4ed 100644 --- a/cmake/ExpectSanitizerSuppression.cmake +++ b/cmake/ExpectSanitizerSuppression.cmake @@ -1,10 +1,10 @@ # SPDX-License-Identifier: AGPL-3.0-only -if(NOT DEFINED MANIFEST OR NOT DEFINED EXPECTED_DIAGNOSTIC) - message(FATAL_ERROR "Laghu sanitizer suppression expectation requires MANIFEST and EXPECTED_DIAGNOSTIC") +if(NOT DEFINED MANIFEST OR NOT DEFINED SOURCE_ROOT OR NOT DEFINED EXPECTED_DIAGNOSTIC) + message(FATAL_ERROR "Laghu sanitizer suppression expectation requires MANIFEST SOURCE_ROOT and EXPECTED_DIAGNOSTIC") endif() execute_process( - COMMAND "${CMAKE_COMMAND}" "-DMANIFEST=${MANIFEST}" + COMMAND "${CMAKE_COMMAND}" "-DMANIFEST=${MANIFEST}" "-DSOURCE_ROOT=${SOURCE_ROOT}" -P "${CMAKE_CURRENT_LIST_DIR}/ValidateSanitizerSuppression.cmake" RESULT_VARIABLE result OUTPUT_VARIABLE output diff --git a/cmake/LaghuSanitizers.cmake b/cmake/LaghuSanitizers.cmake index 6840b60..ab76c6d 100644 --- a/cmake/LaghuSanitizers.cmake +++ b/cmake/LaghuSanitizers.cmake @@ -9,10 +9,13 @@ function(laghu_sanitizer_fail detail) message(FATAL_ERROR "Laghu sanitizer profile failed: ${detail}") endfunction() -function(laghu_validate_sanitizer_suppressions manifest) +function(laghu_validate_sanitizer_suppressions manifest source_root) if(NOT EXISTS "${manifest}") laghu_sanitizer_fail("manifest=${manifest}; file is required") endif() + if(NOT IS_DIRECTORY "${source_root}") + laghu_sanitizer_fail("source_root=${source_root}; directory is required") + endif() file(STRINGS "${manifest}" lines) foreach(line IN LISTS lines) if(line MATCHES "^[ \t]*#" OR line STREQUAL "") @@ -47,6 +50,14 @@ function(laghu_validate_sanitizer_suppressions manifest) if(NOT target_or_source MATCHES "^(laghu_[A-Za-z0-9_]+|src/(core|config|protocol|tls|proxy|cache|control|cli|observability|os)/[A-Za-z0-9_./-]+\\.(cpp|cc|cxx))$") laghu_sanitizer_fail("target_or_source=${target_or_source}; expected=one_laghu_target_or_governed_source") endif() + if(target_or_source MATCHES "^src/") + if(target_or_source MATCHES "(^|/)\\.\\.?(/|$)") + laghu_sanitizer_fail("source=${target_or_source}; source_path_segments_forbidden") + endif() + if(NOT EXISTS "${source_root}/${target_or_source}") + laghu_sanitizer_fail("source=${target_or_source}; source_file_required") + endif() + endif() string(STRIP "${reason}" reason) if(reason STREQUAL "") laghu_sanitizer_fail("target_or_source=${target_or_source}; technical_reason_required") @@ -60,7 +71,8 @@ function(laghu_configure_sanitizer_profile) NOT LAGHU_SANITIZER_PROFILE STREQUAL "TSAN") laghu_sanitizer_fail("profile=${LAGHU_SANITIZER_PROFILE}; expected=NONE-ASAN_UBSAN-or-TSAN") endif() - laghu_validate_sanitizer_suppressions("${CMAKE_SOURCE_DIR}/tests/sanitizers/suppressions.tsv") + laghu_validate_sanitizer_suppressions("${CMAKE_SOURCE_DIR}/tests/sanitizers/suppressions.tsv" + "${CMAKE_SOURCE_DIR}") set(compile_options) set(link_options) diff --git a/cmake/LaghuToolchain.cmake b/cmake/LaghuToolchain.cmake index 4dba2aa..d69cb4b 100644 --- a/cmake/LaghuToolchain.cmake +++ b/cmake/LaghuToolchain.cmake @@ -325,16 +325,21 @@ function(laghu_add_validation_tests) foreach(fixture IN ITEMS broad-source invalid-warning missing-reason) add_test(NAME "laghu.warning.suppression_negative.${fixture}" COMMAND "${CMAKE_COMMAND}" -DMANIFEST=${CMAKE_SOURCE_DIR}/tests/warnings/negative/${fixture}.tsv -P "${CMAKE_SOURCE_DIR}/cmake/ExpectWarningSuppression.cmake") endforeach() - foreach(fixture IN ITEMS global third-party invalid-sanitizer missing-reason whitespace-reason) + foreach(fixture IN ITEMS global third-party invalid-sanitizer missing-reason whitespace-reason traversal current-directory nonexistent-source) if(fixture STREQUAL "global" OR fixture STREQUAL "third-party") set(expected_sanitizer_diagnostic global_or_third_party_suppression_is_forbidden) elseif(fixture STREQUAL "invalid-sanitizer") set(expected_sanitizer_diagnostic expected=address-undefined-or-thread) + elseif(fixture STREQUAL "traversal" OR fixture STREQUAL "current-directory") + set(expected_sanitizer_diagnostic source_path_segments_forbidden) + elseif(fixture STREQUAL "nonexistent-source") + set(expected_sanitizer_diagnostic source_file_required) else() set(expected_sanitizer_diagnostic technical_reason_required) endif() add_test(NAME "laghu.sanitizer.suppression_negative.${fixture}" COMMAND "${CMAKE_COMMAND}" - -DMANIFEST=${CMAKE_SOURCE_DIR}/tests/sanitizers/negative/${fixture}.tsv + "-DMANIFEST=${CMAKE_SOURCE_DIR}/tests/sanitizers/negative/${fixture}.tsv" + "-DSOURCE_ROOT=${CMAKE_SOURCE_DIR}" "-DEXPECTED_DIAGNOSTIC=${expected_sanitizer_diagnostic}" -P "${CMAKE_SOURCE_DIR}/cmake/ExpectSanitizerSuppression.cmake") endforeach() @@ -342,13 +347,36 @@ function(laghu_add_validation_tests) COMMAND "${CMAKE_COMMAND}" "-DLAGHU_SOURCE=${CMAKE_SOURCE_DIR}" -P "${CMAKE_SOURCE_DIR}/cmake/ExpectSanitizerReconfigure.cmake") - add_test(NAME laghu.sanitizer.release_exclusion - COMMAND "${CMAKE_COMMAND}" + if(TARGET laghu_sanitizer_heap_misuse_fixture) + set(laghu_sanitizer_marker_target laghu_sanitizer_heap_misuse_fixture) + set(laghu_sanitizer_marker_symbol laghu_sanitizer_fixture_heap_misuse_marker) + elseif(TARGET laghu_sanitizer_data_race_fixture) + set(laghu_sanitizer_marker_target laghu_sanitizer_data_race_fixture) + set(laghu_sanitizer_marker_symbol laghu_sanitizer_fixture_data_race_marker) + endif() + if(DEFINED laghu_sanitizer_marker_target) + set(laghu_sanitizer_release_exclusion_arguments "-DBUILD_DIRECTORY=${CMAKE_BINARY_DIR}" "-DARCHIVE=$" "-DEXECUTABLE=$" "-DNM=${CMAKE_NM}" - -P "${CMAKE_SOURCE_DIR}/cmake/ExpectSanitizerReleaseExclusion.cmake") + "-DMARKER_ARTIFACT=$" + "-DMARKER=${laghu_sanitizer_marker_symbol}" + "-DMARKER_PREFIX=laghu_sanitizer_fixture_" + "-DMARKER_TARGET=${laghu_sanitizer_marker_target}") + add_test(NAME laghu.sanitizer.release_exclusion + COMMAND "${CMAKE_COMMAND}" ${laghu_sanitizer_release_exclusion_arguments} + -P "${CMAKE_SOURCE_DIR}/cmake/ExpectSanitizerReleaseExclusion.cmake") + add_test(NAME laghu.sanitizer.release_exclusion_marker_rejected + COMMAND "${CMAKE_COMMAND}" + "-DBUILD_DIRECTORY=${CMAKE_BINARY_DIR}" + "-DMARKER_ARTIFACT=$" + "-DMARKER=${laghu_sanitizer_marker_symbol}" + "-DMARKER_PREFIX=laghu_sanitizer_fixture_" + "-DMARKER_TARGET=${laghu_sanitizer_marker_target}" + "-DNM=${CMAKE_NM}" + -P "${CMAKE_SOURCE_DIR}/cmake/ExpectSanitizerMarkerRejection.cmake") + endif() foreach(mode IN ITEMS all_enabled baseline_unavailable) string(REPLACE "_" "-" golden_mode "${mode}") add_test(NAME "laghu.capabilities.golden.${mode}" diff --git a/cmake/ValidateSanitizerSuppression.cmake b/cmake/ValidateSanitizerSuppression.cmake index 03fb27a..974edab 100644 --- a/cmake/ValidateSanitizerSuppression.cmake +++ b/cmake/ValidateSanitizerSuppression.cmake @@ -1,7 +1,7 @@ # SPDX-License-Identifier: AGPL-3.0-only -if(NOT DEFINED MANIFEST) - message(FATAL_ERROR "Laghu sanitizer suppression validation requires MANIFEST") +if(NOT DEFINED MANIFEST OR NOT DEFINED SOURCE_ROOT) + message(FATAL_ERROR "Laghu sanitizer suppression validation requires MANIFEST and SOURCE_ROOT") endif() include("${CMAKE_CURRENT_LIST_DIR}/LaghuSanitizers.cmake") -laghu_validate_sanitizer_suppressions("${MANIFEST}") +laghu_validate_sanitizer_suppressions("${MANIFEST}" "${SOURCE_ROOT}") diff --git a/docs/normative/build.md b/docs/normative/build.md index c7251de..d5aedbe 100644 --- a/docs/normative/build.md +++ b/docs/normative/build.md @@ -35,6 +35,6 @@ binary directory only and never mutates source files. ## Presets and ARM64 cross-builds -`CMakePresets.json` provides the unversioned `linux-gcc`, `linux-clang`, `macos-appleclang`, `freebsd-clang`, and `linux-aarch64-gcc` configure presets. Repository release metadata owns versioning; preset names do not repeat it. +`CMakePresets.json` provides the unversioned `linux-gcc`, `linux-clang`, `linux-clang-asan-ubsan`, `linux-clang-tsan`, `macos-appleclang`, `freebsd-clang`, and `linux-aarch64-gcc` configure presets. Repository release metadata owns versioning; preset names do not repeat it. The ARM64 preset uses `cmake/toolchains/aarch64-linux-gnu.cmake` and the Ubuntu package `g++-14-aarch64-linux-gnu`, which provides `aarch64-linux-gnu-g++-14`, `aarch64-linux-gnu-ar`, and `aarch64-linux-gnu-ranlib`. Its `try_compile` checks create static libraries, and no cross-built executable is run. diff --git a/tests/sanitizers/data_race.cpp b/tests/sanitizers/data_race.cpp index e014fb5..13b48a2 100644 --- a/tests/sanitizers/data_race.cpp +++ b/tests/sanitizers/data_race.cpp @@ -13,7 +13,14 @@ void increment() noexcept { } // namespace +extern "C" { +volatile int laghu_sanitizer_fixture_data_race_marker = 0; +} + int main() { + if (laghu_sanitizer_fixture_data_race_marker != 0) { + return 1; + } std::thread first{increment}; std::thread second{increment}; first.join(); diff --git a/tests/sanitizers/heap_misuse.cpp b/tests/sanitizers/heap_misuse.cpp index 83c3ccd..d7898d0 100644 --- a/tests/sanitizers/heap_misuse.cpp +++ b/tests/sanitizers/heap_misuse.cpp @@ -1,5 +1,12 @@ // SPDX-License-Identifier: AGPL-3.0-only +extern "C" { +volatile int laghu_sanitizer_fixture_heap_misuse_marker = 0; +} + int main() { + if (laghu_sanitizer_fixture_heap_misuse_marker != 0) { + return 1; + } int* const values = new int[1]; values[1] = 1; delete[] values; diff --git a/tests/sanitizers/negative/current-directory.tsv b/tests/sanitizers/negative/current-directory.tsv new file mode 100644 index 0000000..8527065 --- /dev/null +++ b/tests/sanitizers/negative/current-directory.tsv @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: AGPL-3.0-only +address linux src/core/./contract.cpp current-directory path segment is forbidden diff --git a/tests/sanitizers/negative/global.tsv b/tests/sanitizers/negative/global.tsv index e1b318d..916d439 100644 --- a/tests/sanitizers/negative/global.tsv +++ b/tests/sanitizers/negative/global.tsv @@ -1 +1,2 @@ +# SPDX-License-Identifier: AGPL-3.0-only address linux all global suppression is forbidden diff --git a/tests/sanitizers/negative/invalid-sanitizer.tsv b/tests/sanitizers/negative/invalid-sanitizer.tsv index c0a2092..325e453 100644 --- a/tests/sanitizers/negative/invalid-sanitizer.tsv +++ b/tests/sanitizers/negative/invalid-sanitizer.tsv @@ -1 +1,2 @@ +# SPDX-License-Identifier: AGPL-3.0-only memory linux laghu_core invalid sanitizer is forbidden diff --git a/tests/sanitizers/negative/missing-reason.tsv b/tests/sanitizers/negative/missing-reason.tsv index 7ea6a63..c3e8ed1 100644 --- a/tests/sanitizers/negative/missing-reason.tsv +++ b/tests/sanitizers/negative/missing-reason.tsv @@ -1 +1,2 @@ +# SPDX-License-Identifier: AGPL-3.0-only thread linux laghu_core diff --git a/tests/sanitizers/negative/nonexistent-source.tsv b/tests/sanitizers/negative/nonexistent-source.tsv new file mode 100644 index 0000000..2c4dab5 --- /dev/null +++ b/tests/sanitizers/negative/nonexistent-source.tsv @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: AGPL-3.0-only +address linux src/core/not-present.cpp missing source is forbidden diff --git a/tests/sanitizers/negative/third-party.tsv b/tests/sanitizers/negative/third-party.tsv index 000f896..a234ca3 100644 --- a/tests/sanitizers/negative/third-party.tsv +++ b/tests/sanitizers/negative/third-party.tsv @@ -1 +1,2 @@ +# SPDX-License-Identifier: AGPL-3.0-only address linux third_party/library.cpp third-party masking is forbidden diff --git a/tests/sanitizers/negative/traversal.tsv b/tests/sanitizers/negative/traversal.tsv new file mode 100644 index 0000000..c587cca --- /dev/null +++ b/tests/sanitizers/negative/traversal.tsv @@ -0,0 +1,2 @@ +# SPDX-License-Identifier: AGPL-3.0-only +address linux src/core/../core/contract.cpp path traversal is forbidden diff --git a/tests/sanitizers/negative/whitespace-reason.tsv b/tests/sanitizers/negative/whitespace-reason.tsv index 3b27e22..5031c7e 100644 --- a/tests/sanitizers/negative/whitespace-reason.tsv +++ b/tests/sanitizers/negative/whitespace-reason.tsv @@ -1 +1,2 @@ +# SPDX-License-Identifier: AGPL-3.0-only thread linux laghu_core diff --git a/tests/sanitizers/undefined_behavior.cpp b/tests/sanitizers/undefined_behavior.cpp index 6490ece..87faf62 100644 --- a/tests/sanitizers/undefined_behavior.cpp +++ b/tests/sanitizers/undefined_behavior.cpp @@ -1,7 +1,14 @@ // SPDX-License-Identifier: AGPL-3.0-only #include +extern "C" { +volatile int laghu_sanitizer_fixture_undefined_behavior_marker = 0; +} + int main() { + if (laghu_sanitizer_fixture_undefined_behavior_marker != 0) { + return 1; + } volatile int maximum = std::numeric_limits::max(); volatile int one = 1; return maximum + one;