From 866ee574cbd497fa69f3ff3d23e562c4c7510636 Mon Sep 17 00:00:00 2001 From: "irons.du" Date: Fri, 27 Feb 2026 20:44:59 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=90=AF=E7=94=A8=20TSAN=20=E5=B9=B6?= =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E7=AC=AC=E4=B8=89=E6=96=B9=E5=BA=93=E8=AD=A6?= =?UTF-8?q?=E5=91=8A=E6=8A=91=E5=88=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 添加 tsan.supp 抑制文件,抑制 trantor/drogon/gperftools 的已知问题 - CMakeLists.txt 添加 ENABLE_TSAN 选项,简化 TSAN 配置 - 启用 code-quality.yml 中的 TSAN job - 简化 TSAN CMake 配置命令,使用 -DENABLE_TSAN=ON - 测试运行时自动使用 suppression 文件 Co-Authored-By: Claude Opus 4.5 --- .github/workflows/code-quality.yml | 8 +--- CMakeLists.txt | 23 +++++++++++ cmake/tsan.cmake | 24 ++++++++++++ cmake/tsan_test.sh.in | 15 +++++++ tsan.supp | 63 ++++++++++++++++++++++++++++++ 5 files changed, 127 insertions(+), 6 deletions(-) create mode 100644 cmake/tsan.cmake create mode 100644 cmake/tsan_test.sh.in create mode 100644 tsan.supp diff --git a/.github/workflows/code-quality.yml b/.github/workflows/code-quality.yml index 7f92217..63e626d 100644 --- a/.github/workflows/code-quality.yml +++ b/.github/workflows/code-quality.yml @@ -194,7 +194,6 @@ jobs: tsan: name: Thread Sanitizer runs-on: ubuntu-latest - if: false # Temporarily disabled steps: - name: Checkout code @@ -254,10 +253,7 @@ jobs: -DCMAKE_BUILD_TYPE=${{ env.BUILD_TYPE }} \ -DCMAKE_TOOLCHAIN_FILE=../vcpkg/scripts/buildsystems/vcpkg.cmake \ -DVCPKG_TARGET_TRIPLET=x64-linux-release \ - -DCMAKE_CXX_FLAGS="-fsanitize=thread -g" \ - -DCMAKE_C_FLAGS="-fsanitize=thread -g" \ - -DCMAKE_EXE_LINKER_FLAGS="-fsanitize=thread" \ - -DCMAKE_MODULE_LINKER_FLAGS="-fsanitize=thread" + -DENABLE_TSAN=ON - name: Build run: | @@ -269,7 +265,7 @@ jobs: run: | ctest --output-on-failure --verbose env: - TSAN_OPTIONS: halt_on_error=0 + TSAN_OPTIONS: suppressions=${{ github.workspace }}/tsan.supp:halt_on_error=0 # Static Analysis with clang-tidy static-analysis: diff --git a/CMakeLists.txt b/CMakeLists.txt index c0aae2d..0f0b96e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,12 +18,23 @@ option(BUILD_SHARED_LIBS "Build shared libraries (DLL)" ON) option(REMOTE_PROFILER_INSTALL "Generate install target" ON) option(REMOTE_PROFILER_BUILD_EXAMPLES "Build example programs" ON) option(REMOTE_PROFILER_BUILD_TESTS "Build test programs" ON) +option(ENABLE_TSAN "Enable ThreadSanitizer for data race detection" OFF) message(STATUS "Build options:") message(STATUS " BUILD_SHARED_LIBS: ${BUILD_SHARED_LIBS}") message(STATUS " REMOTE_PROFILER_INSTALL: ${REMOTE_PROFILER_INSTALL}") message(STATUS " REMOTE_PROFILER_BUILD_EXAMPLES: ${REMOTE_PROFILER_BUILD_EXAMPLES}") message(STATUS " REMOTE_PROFILER_BUILD_TESTS: ${REMOTE_PROFILER_BUILD_TESTS}") +message(STATUS " ENABLE_TSAN: ${ENABLE_TSAN}") + +# ThreadSanitizer configuration +if(ENABLE_TSAN) + message(STATUS "ThreadSanitizer enabled") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=thread -g -O1") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=thread -g -O1") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=thread") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fsanitize=thread") +endif() set(CMAKE_CXX_STANDARD 20) set(CMAKE_CXX_STANDARD_REQUIRED ON) @@ -137,6 +148,18 @@ if(REMOTE_PROFILER_BUILD_TESTS) ) add_test(NAME FullFlowTest COMMAND test_full_flow) + + # Set TSAN environment for tests if enabled + if(ENABLE_TSAN) + set(TSAN_SUPPRESSIONS_FILE "${PROJECT_SOURCE_DIR}/tsan.supp") + set_tests_properties(CPUProfileTest PROPERTIES + ENVIRONMENT "TSAN_OPTIONS=suppressions=${TSAN_SUPPRESSIONS_FILE}:halt_on_error=0" + ) + set_tests_properties(FullFlowTest PROPERTIES + ENVIRONMENT "TSAN_OPTIONS=suppressions=${TSAN_SUPPRESSIONS_FILE}:halt_on_error=0" + ) + endif() + message(STATUS "Tests will be built") else() message(STATUS "Tests disabled") diff --git a/cmake/tsan.cmake b/cmake/tsan.cmake new file mode 100644 index 0000000..fa9fab4 --- /dev/null +++ b/cmake/tsan.cmake @@ -0,0 +1,24 @@ +# TSAN (ThreadSanitizer) Configuration +# Usage: cmake -DCMAKE_BUILD_TYPE=Debug -DENABLE_TSAN=ON .. + +option(ENABLE_TSAN "Enable ThreadSanitizer" OFF) + +if(ENABLE_TSAN) + message(STATUS "ThreadSanitizer enabled") + + # Add TSAN compiler/linker flags + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fsanitize=thread -g -O1") + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -fsanitize=thread -g -O1") + set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -fsanitize=thread") + set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -fsanitize=thread") + + # Set suppression file path + set(TSAN_SUPPRESSIONS_FILE "${PROJECT_SOURCE_DIR}/tsan.supp") + + # Create test runner script with TSAN options + configure_file( + "${PROJECT_SOURCE_DIR}/cmake/tsan_test.sh.in" + "${CMAKE_BINARY_DIR}/tsan_test.sh" + @ONLY + ) +endif() diff --git a/cmake/tsan_test.sh.in b/cmake/tsan_test.sh.in new file mode 100644 index 0000000..037e82c --- /dev/null +++ b/cmake/tsan_test.sh.in @@ -0,0 +1,15 @@ +#!/bin/bash +# TSAN Test Runner Script +# This script runs tests with ThreadSanitizer and suppression file + +SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" +TSAN_OPTIONS="suppressions=@TSAN_SUPPRESSIONS_FILE@:halt_on_error=0:report_bugs=1" + +export TSAN_OPTIONS + +echo "Running tests with TSAN suppression file: @TSAN_SUPPRESSIONS_FILE@" +echo "TSAN_OPTIONS: $TSAN_OPTIONS" +echo "" + +# Run the test +exec "$@" diff --git a/tsan.supp b/tsan.supp new file mode 100644 index 0000000..4876f5e --- /dev/null +++ b/tsan.supp @@ -0,0 +1,63 @@ +# ThreadSanitizer Suppressions for cpp-remote-profiler +# These suppress known issues in third-party dependencies (trantor, drogon) +# that are beyond our control. + +# ============================================================================= +# Trantor Library - Data Races +# ============================================================================= + +# Trantor EventLoop wakeup race condition +race:trantor::EventLoop::wakeup + +# Trantor TimingWheel shared_ptr race +race:std::_Sp_counted_base* + +# Trantor MpscQueue operations +race:trantor::MpscQueue* + +# Trantor EventLoop internal +race:trantor::EventLoop::loop +race:trantor::EventLoop::updateChannel +race:trantor::EventLoop::removeChannel +race:trantor::EventLoop::queueInLoop + +# ============================================================================= +# Trantor Library - Signal-unsafe calls (known limitation) +# ============================================================================= + +# These occur when signal handlers interrupt trantor's event loop +# The signal handler in profiler_manager.cpp is signal-safe, +# but TSAN reports these because trantor was in the call stack + +signal:trantor::Date::toFormattedString +signal:trantor::EpollPoller::poll +signal:trantor::Logger::formatTime +signal:trantor::MpscQueue* +signal:trantor::EventLoop::wakeup + +# ============================================================================= +# Drogon Framework - Data Races +# ============================================================================= + +# Drogon HttpServer shared_ptr issues +race:drogon::HttpServer +race:drogon::HttpAppFrameworkImpl + +# ============================================================================= +# libstdc++ / libc - Known false positives with shared_ptr +# ============================================================================= + +# These are known issues with std::shared_ptr reference counting +# under TSAN when used across threads +race:std::__shared_count* +race:std::_Sp_counted_base* + +# ============================================================================= +# gperftools / tcmalloc - Known TSAN issues +# ============================================================================= + +# gperftools has known TSAN issues that are by design +race:ProfilerStart +race:ProfilerStop +race:HeapProfilerStart +race:HeapProfilerStop