From 68a21c5a5952913d6192be747efd245887bc36cc Mon Sep 17 00:00:00 2001 From: Alexis Placet <2400067+Alex-PLACET@users.noreply.github.com> Date: Thu, 30 Apr 2026 13:24:54 +0200 Subject: [PATCH 01/13] Fix substring calculation in CSV cell parsing and add lexical_cast for signed and unsigned char --- include/xtensor/io/xcsv.hpp | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/include/xtensor/io/xcsv.hpp b/include/xtensor/io/xcsv.hpp index 080ccaf54..2fd347745 100644 --- a/include/xtensor/io/xcsv.hpp +++ b/include/xtensor/io/xcsv.hpp @@ -66,7 +66,7 @@ namespace xt } size_t last = cell.find_last_not_of(' '); - return cell.substr(first, last == std::string::npos ? cell.size() : last + 1); + return cell.substr(first, last == std::string::npos ? cell.size() : last - first + 1); } template <> @@ -93,6 +93,18 @@ namespace xt return std::stoi(cell); } + template <> + inline signed char lexical_cast(const std::string& cell) + { + return static_cast(std::stoi(cell)); + } + + template <> + inline unsigned char lexical_cast(const std::string& cell) + { + return static_cast(std::stoul(cell)); + } + template <> inline long lexical_cast(const std::string& cell) { From 005b0c6d1dd1f897ae47b1393b1c07f327b066e6 Mon Sep 17 00:00:00 2001 From: Alexis Placet <2400067+Alex-PLACET@users.noreply.github.com> Date: Wed, 6 May 2026 16:05:50 +0200 Subject: [PATCH 02/13] Add ASAN CI build --- .github/workflows/sanitizers.yml | 98 ++++++++++++++++++++++++++++++++ cmake/sanitizers.cmake | 44 ++++++++++++++ test/CMakeLists.txt | 3 + 3 files changed, 145 insertions(+) create mode 100644 .github/workflows/sanitizers.yml create mode 100644 cmake/sanitizers.cmake diff --git a/.github/workflows/sanitizers.yml b/.github/workflows/sanitizers.yml new file mode 100644 index 000000000..4ec16358b --- /dev/null +++ b/.github/workflows/sanitizers.yml @@ -0,0 +1,98 @@ +name: Sanitizers +on: + workflow_dispatch: + pull_request: + push: + branches: [master] +concurrency: + group: ${{ github.workflow }}-${{ github.job }}-${{ github.ref }} + cancel-in-progress: true +defaults: + run: + shell: bash -e -l {0} +jobs: + build: + runs-on: ${{ matrix.os }} + name: sanitizer / ${{ matrix.sys.compiler }} ${{ matrix.sys.version }} / ${{ matrix.config.name }} / ${{ matrix.sys.name }} + strategy: + fail-fast: false + matrix: + os: [ubuntu-24.04] + sys: + - {compiler: clang, version: '19', name: asan} + - {compiler: clang, version: '21', name: asan} + config: + - {name: Debug} + + steps: + + - name: Install LLVM and Clang + if: matrix.sys.compiler == 'clang' + run: | + wget https://apt.llvm.org/llvm.sh + chmod +x llvm.sh + sudo ./llvm.sh ${{matrix.sys.version}} + sudo apt-get install -y clang-tools-${{matrix.sys.version}} + sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-${{matrix.sys.version}} 200 + sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-${{matrix.sys.version}} 200 + sudo update-alternatives --install /usr/bin/clang-scan-deps clang-scan-deps /usr/bin/clang-scan-deps-${{matrix.sys.version}} 200 + sudo update-alternatives --set clang /usr/bin/clang-${{matrix.sys.version}} + sudo update-alternatives --set clang++ /usr/bin/clang++-${{matrix.sys.version}} + sudo update-alternatives --set clang-scan-deps /usr/bin/clang-scan-deps-${{matrix.sys.version}} + + - name: Checkout code + uses: actions/checkout@v6 + + - name: Set conda environment + uses: mamba-org/setup-micromamba@main + with: + environment-name: myenv + environment-file: environment-dev.yml + init-shell: bash + cache-downloads: true + + - name: Configure using CMake + run: | + export CC=clang + export CXX=clang++ + cmake -G Ninja \ + -Bbuild \ + -DCMAKE_BUILD_TYPE:STRING=${{matrix.config.name}} \ + -DCMAKE_INSTALL_PREFIX=$CONDA_PREFIX \ + -DBUILD_TESTS=ON \ + -DUSE_SANITIZER=address + + - name: Build tests + working-directory: build + run: cmake --build . --config ${{matrix.config.name}} --target test_xtensor_lib --parallel 8 + + - name: Run tests + working-directory: build + run: | + export ASAN_OPTIONS=log_path=asan_log_:alloc_dealloc_mismatch=0:halt_on_error=0:handle_abort=0 + export ASAN_SAVE_DUMPS=AsanDump.dmp + ctest -R ^xtest$ --output-on-failure + + - name: Upload ASAN log + if: always() + uses: actions/upload-artifact@v6 + with: + name: asan-log-${{ matrix.sys.compiler }}-${{ matrix.sys.version }}-${{ matrix.config.name }}-${{ runner.os }} + path: '**/asan_log_*' + if-no-files-found: ignore + + - name: Upload ASAN dump + if: always() + uses: actions/upload-artifact@v6 + with: + name: asan-dump-${{ matrix.sys.compiler }}-${{ matrix.sys.version }}-${{ matrix.config.name }}-${{ runner.os }} + path: '**/AsanDump.dmp' + if-no-files-found: ignore + + - name: Return errors if ASAN log content is not empty + if: always() + run: | + if [ -n "$(find build/test -name 'asan_log_*' -type f -size +0 2>/dev/null)" ]; then + echo "ASAN detected errors. See the log for details." + exit 1 + fi diff --git a/cmake/sanitizers.cmake b/cmake/sanitizers.cmake new file mode 100644 index 000000000..d4b3c54f9 --- /dev/null +++ b/cmake/sanitizers.cmake @@ -0,0 +1,44 @@ +set(AVAILABLE_SANITIZERS "address;leak;memory;thread;undefined") +OPTION(USE_SANITIZER "Enable sanitizer(s). Options are: ${AVAILABLE_SANITIZERS}. Case insensitive; multiple options delimited by comma or space possible." "") +string(TOLOWER "${USE_SANITIZER}" USE_SANITIZER) + +if(USE_SANITIZER AND NOT (CMAKE_BUILD_TYPE IN_LIST "Debug;RelWithDebInfo")) + message(FATAL_ERROR "❌ Sanitizer only supported in Debug and RelWithDebInfo build types. Current: ${CMAKE_BUILD_TYPE}") +endif() + +if(USE_SANITIZER) + if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC") + set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "$,$>,$<$:EditAndContinue>,$<$:ProgramDatabase>>") + + if(USE_SANITIZER MATCHES "address") + string(APPEND CMAKE_CXX_FLAGS " /fsanitize=address /D_DISABLE_VECTOR_ANNOTATION /D_DISABLE_STRING_ANNOTATION") + string(APPEND CMAKE_EXE_LINKER_FLAGS " /fsanitize=address") + else() + message(FATAL_ERROR "❌ Sanitizer not supported by MSVC: ${USE_SANITIZER}. It only supports 'address'.") + endif() + elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC") + if(USE_SANITIZER MATCHES "address") + string(APPEND CMAKE_CXX_FLAGS " /fsanitize=address /D_DISABLE_VECTOR_ANNOTATION /D_DISABLE_STRING_ANNOTATION") + string(APPEND CMAKE_EXE_LINKER_FLAGS " /fsanitize=address") + else() + message(FATAL_ERROR "❌ Sanitizer not supported by Clang-MSVC: ${USE_SANITIZER}. It only supports 'address'.") + endif() + elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang" OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU") + foreach(sanitizer ${USE_SANITIZER}) + if(NOT ${sanitizer} IN_LIST AVAILABLE_SANITIZERS) + message(FATAL_ERROR "❌ Sanitizer not supported: ${sanitizer}. It should be one of: ${AVAILABLE_SANITIZERS}.") + endif() + string(APPEND CMAKE_CXX_FLAGS " -fsanitize=${sanitizer}") + string(APPEND CMAKE_EXE_LINKER_FLAGS " -fsanitize=${sanitizer}") + if(${sanitizer} MATCHES "memory") + string(APPEND CMAKE_CXX_FLAGS " -fsanitize-memory-track-origins -fPIE -pie") + string(APPEND CMAKE_EXE_LINKER_FLAGS " -fsanitize-memory-track-origins -fPIE -pie") + endif() + endforeach() + string(APPEND CMAKE_CXX_FLAGS " -fno-omit-frame-pointer") + else() + message(FATAL_ERROR "❌ Sanitizer: Unsupported compiler: ${CMAKE_CXX_COMPILER_ID}") + endif() + + message(STATUS "🔍 Using sanitizer: ${USE_SANITIZER}") +endif() diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 8341230ee..deb7ddf22 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -231,6 +231,9 @@ endforeach() file(GLOB XTENSOR_PREPROCESS_FILES files/cppy_source/*.cppy) +# Sanitizer support +include(${CMAKE_SOURCE_DIR}/cmake/sanitizers.cmake) + # This target should only be run when the test source files have been changed. add_custom_target( preprocess_cppy From a8bc5e8ebfef43a0ce72c82e79edf7ae4d63355f Mon Sep 17 00:00:00 2001 From: Alexis Placet <2400067+Alex-PLACET@users.noreply.github.com> Date: Wed, 6 May 2026 16:27:57 +0200 Subject: [PATCH 03/13] try fix --- .github/workflows/sanitizers.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sanitizers.yml b/.github/workflows/sanitizers.yml index 4ec16358b..da585bf2d 100644 --- a/.github/workflows/sanitizers.yml +++ b/.github/workflows/sanitizers.yml @@ -57,7 +57,7 @@ jobs: export CXX=clang++ cmake -G Ninja \ -Bbuild \ - -DCMAKE_BUILD_TYPE:STRING=${{matrix.config.name}} \ + -DCMAKE_BUILD_TYPE=${{matrix.config.name}} \ -DCMAKE_INSTALL_PREFIX=$CONDA_PREFIX \ -DBUILD_TESTS=ON \ -DUSE_SANITIZER=address From fdb27adf8c53c99ba99c85ff80db1d1cff8162de Mon Sep 17 00:00:00 2001 From: Alexis Placet <2400067+Alex-PLACET@users.noreply.github.com> Date: Wed, 6 May 2026 20:38:05 +0200 Subject: [PATCH 04/13] fix --- cmake/sanitizers.cmake | 35 +++++++++++++++++++---------------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/cmake/sanitizers.cmake b/cmake/sanitizers.cmake index d4b3c54f9..716021f96 100644 --- a/cmake/sanitizers.cmake +++ b/cmake/sanitizers.cmake @@ -1,9 +1,9 @@ -set(AVAILABLE_SANITIZERS "address;leak;memory;thread;undefined") -OPTION(USE_SANITIZER "Enable sanitizer(s). Options are: ${AVAILABLE_SANITIZERS}. Case insensitive; multiple options delimited by comma or space possible." "") +set(AVALAIBLE_SANITIZERS "address;leak;memory;thread;undefined") +OPTION(USE_SANITIZER "Enable sanitizer(s). Options are: ${AVALAIBLE_SANITIZERS}. Case insensitive; multiple options delimited by comma or space possible." "") string(TOLOWER "${USE_SANITIZER}" USE_SANITIZER) -if(USE_SANITIZER AND NOT (CMAKE_BUILD_TYPE IN_LIST "Debug;RelWithDebInfo")) - message(FATAL_ERROR "❌ Sanitizer only supported in Debug and RelWithDebInfo build types. Current: ${CMAKE_BUILD_TYPE}") +if((CMAKE_BUILD_TYPE IN_LIST "Debug;RelWithDebInfo") AND USE_SANITIZER) + message(FATAL_ERROR "❌ Sanitizer only supported in Debug and RelWithDebInfo build types.") endif() if(USE_SANITIZER) @@ -11,34 +11,37 @@ if(USE_SANITIZER) set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "$,$>,$<$:EditAndContinue>,$<$:ProgramDatabase>>") if(USE_SANITIZER MATCHES "address") - string(APPEND CMAKE_CXX_FLAGS " /fsanitize=address /D_DISABLE_VECTOR_ANNOTATION /D_DISABLE_STRING_ANNOTATION") - string(APPEND CMAKE_EXE_LINKER_FLAGS " /fsanitize=address") + list(APPEND SANITIZER_COMPILE_OPTIONS /fsanitize=address /D_DISABLE_VECTOR_ANNOTATION /D_DISABLE_STRING_ANNOTATION) else() message(FATAL_ERROR "❌ Sanitizer not supported by MSVC: ${USE_SANITIZER}. It only supports 'address'.") endif() elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC") if(USE_SANITIZER MATCHES "address") - string(APPEND CMAKE_CXX_FLAGS " /fsanitize=address /D_DISABLE_VECTOR_ANNOTATION /D_DISABLE_STRING_ANNOTATION") - string(APPEND CMAKE_EXE_LINKER_FLAGS " /fsanitize=address") + list(APPEND SANITIZER_COMPILE_OPTIONS /fsanitize=address /D_DISABLE_VECTOR_ANNOTATION /D_DISABLE_STRING_ANNOTATION) + list(APPEND SANITIZER_LINK_LIBRARIES clang_rt.asan_dynamic-x86_64 clang_rt.asan_dynamic_runtime_thunk-x86_64) else() message(FATAL_ERROR "❌ Sanitizer not supported by Clang-MSVC: ${USE_SANITIZER}. It only supports 'address'.") endif() elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang" OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU") foreach(sanitizer ${USE_SANITIZER}) - if(NOT ${sanitizer} IN_LIST AVAILABLE_SANITIZERS) - message(FATAL_ERROR "❌ Sanitizer not supported: ${sanitizer}. It should be one of: ${AVAILABLE_SANITIZERS}.") + if(NOT ${sanitizer} IN_LIST AVALAIBLE_SANITIZERS) + message(FATAL_ERROR "❌ Sanitizer not supported: ${sanitizer}. It should be one of: ${AVALAIBLE_SANITIZERS}.") endif() - string(APPEND CMAKE_CXX_FLAGS " -fsanitize=${sanitizer}") - string(APPEND CMAKE_EXE_LINKER_FLAGS " -fsanitize=${sanitizer}") - if(${sanitizer} MATCHES "memory") - string(APPEND CMAKE_CXX_FLAGS " -fsanitize-memory-track-origins -fPIE -pie") - string(APPEND CMAKE_EXE_LINKER_FLAGS " -fsanitize-memory-track-origins -fPIE -pie") + list(APPEND SANITIZER_COMPILE_OPTIONS -fsanitize=${sanitizer}) + list(APPEND SANITIZER_LINK_OPTIONS -fsanitize=${sanitizer}) + if (${sanitizer} MATCHES "memory") + list(APPEND SANITIZER_LINK_LIBRARIES -fsanitize-memory-track-origins -fPIE -pie) + list(APPEND SANITIZER_LINK_OPTIONS -fsanitize-memory-track-origins -fPIE -pie) endif() endforeach() - string(APPEND CMAKE_CXX_FLAGS " -fno-omit-frame-pointer") + list(APPEND SANITIZER_COMPILE_OPTIONS -fno-omit-frame-pointer) else() message(FATAL_ERROR "❌ Sanitizer: Unsupported compiler: ${CMAKE_CXX_COMPILER_ID}") endif() + list(REMOVE_DUPLICATES SANITIZER_COMPILE_OPTIONS) + list(REMOVE_DUPLICATES SANITIZER_LINK_OPTIONS) + list(REMOVE_DUPLICATES SANITIZER_LINK_LIBRARIES) + message(STATUS "🔍 Using sanitizer: ${USE_SANITIZER}") endif() From af49c9bf453d247bed710009577f9ded49ac8788 Mon Sep 17 00:00:00 2001 From: Alexis Placet <2400067+Alex-PLACET@users.noreply.github.com> Date: Thu, 7 May 2026 09:58:54 +0200 Subject: [PATCH 05/13] Enhance index_mapper with access control and add ASAN support in tests --- include/xtensor/views/index_mapper.hpp | 51 ++++++++++++++++++++++---- test/CMakeLists.txt | 5 +++ test/test_xadapt.cpp | 4 ++ test/test_xbuffer_adaptor.cpp | 2 + 4 files changed, 55 insertions(+), 7 deletions(-) diff --git a/include/xtensor/views/index_mapper.hpp b/include/xtensor/views/index_mapper.hpp index 574bcb476..330a71baa 100644 --- a/include/xtensor/views/index_mapper.hpp +++ b/include/xtensor/views/index_mapper.hpp @@ -193,7 +193,7 @@ namespace xt * @throws Assertion failure if `i != 0` for integral slices. * @throws Assertion failure if `i >= slice.size()` for non-integral slices. */ - template + template size_t map_ith_index(const view_type& view, const Index i) const; /** @@ -490,16 +490,16 @@ namespace xt { if constexpr (ACCESS == access_t::SAFE) { - return container.at(map_ith_index(view, indices[Is])...); + return container.at(map_ith_index(view, indices[Is])...); } else { - return container(map_ith_index(view, indices[Is])...); + return container(map_ith_index(view, indices[Is])...); } } template - template + template auto index_mapper>::map_ith_index(const view_type& view, const Index i) const -> size_t @@ -515,14 +515,51 @@ namespace xt if constexpr (std::is_integral_v) { - assert(i == 0); + if constexpr (ACCESS == access_t::SAFE) + { + if (i != 0) + { + XTENSOR_THROW(std::out_of_range, "Index out of range in index_mapper access"); + } + } + else + { + assert(i == 0); + } return size_t(slice); } + else if constexpr (xt::detail::is_xall_slice>::value) + { + return size_t(i); + } else { using slice_size_type = typename current_slice::size_type; - assert(i < slice.size()); - return size_t(slice(static_cast(i))); + const auto slice_index = static_cast(i); + + if constexpr (ACCESS == access_t::SAFE) + { + if constexpr (std::is_signed_v) + { + if (slice_index < 0 || slice_index >= slice.size()) + { + XTENSOR_THROW(std::out_of_range, "Index out of range in index_mapper access"); + } + } + else if (slice_index >= slice.size()) + { + XTENSOR_THROW(std::out_of_range, "Index out of range in index_mapper access"); + } + } + else + { + if constexpr (std::is_signed_v) + { + assert(slice_index >= 0); + } + assert(slice_index < slice.size()); + } + return size_t(slice(slice_index)); } } else diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index deb7ddf22..743396aea 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -261,6 +261,8 @@ foreach(filename IN LISTS COMMON_BASE XTENSOR_TESTS) endif() target_include_directories(${targetname} PRIVATE ${XTENSOR_INCLUDE_DIR}) target_link_libraries(${targetname} PRIVATE xtensor doctest::doctest ${CMAKE_THREAD_LIBS_INIT}) + target_compile_options(${targetname} PRIVATE $<$:${SANITIZER_COMPILE_OPTIONS}>) + target_link_options(${targetname} PRIVATE $<$:${SANITIZER_LINK_OPTIONS}>) add_custom_target( x${targetname} COMMAND ${targetname} @@ -285,6 +287,9 @@ if(XTENSOR_USE_OPENMP) target_compile_definitions(test_xtensor_lib PRIVATE XTENSOR_USE_OPENMP) endif() +target_compile_options(test_xtensor_lib PRIVATE $<$:${SANITIZER_COMPILE_OPTIONS}>) +target_link_options(test_xtensor_lib PRIVATE $<$:${SANITIZER_LINK_OPTIONS}>) + target_include_directories(test_xtensor_lib PRIVATE ${XTENSOR_INCLUDE_DIR}) target_link_libraries(test_xtensor_lib PRIVATE xtensor doctest::doctest ${CMAKE_THREAD_LIBS_INIT}) diff --git a/test/test_xadapt.cpp b/test/test_xadapt.cpp index 5876ff926..ef5451b91 100644 --- a/test/test_xadapt.cpp +++ b/test/test_xadapt.cpp @@ -132,6 +132,8 @@ namespace xt a1(1, 0) = static_cast(i); EXPECT_EQ(i, data[i * size + st]); } + + delete[] data; } TEST(xarray_adaptor, pointer_acquire_ownership) @@ -300,6 +302,8 @@ namespace xt a1(1, 0) = static_cast(i); EXPECT_EQ(i, data[i * size + st]); } + + delete[] data; } TEST(xtensor_adaptor, pointer_const_no_ownership) diff --git a/test/test_xbuffer_adaptor.cpp b/test/test_xbuffer_adaptor.cpp index d6ad32b21..5b0a5fcb6 100644 --- a/test/test_xbuffer_adaptor.cpp +++ b/test/test_xbuffer_adaptor.cpp @@ -201,6 +201,8 @@ namespace xt size_t size2 = 50; XT_EXPECT_THROW(adapt.resize(size2), std::runtime_error); EXPECT_EQ(adapt.size(), size1); + + delete[] data1; } TEST(xbuffer_adaptor, no_owner_iterating) From df350a694a292add10263b0711e6c2cd97fc14b2 Mon Sep 17 00:00:00 2001 From: Alexis Placet <2400067+Alex-PLACET@users.noreply.github.com> Date: Thu, 7 May 2026 17:09:52 +0200 Subject: [PATCH 06/13] Add support for multiple sanitizers in CI workflow --- .github/workflows/sanitizers.yml | 42 ++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 13 deletions(-) diff --git a/.github/workflows/sanitizers.yml b/.github/workflows/sanitizers.yml index da585bf2d..ee5965748 100644 --- a/.github/workflows/sanitizers.yml +++ b/.github/workflows/sanitizers.yml @@ -19,8 +19,10 @@ jobs: matrix: os: [ubuntu-24.04] sys: - - {compiler: clang, version: '19', name: asan} - - {compiler: clang, version: '21', name: asan} + - {compiler: clang, version: '21', name: asan, sanitizer: address} + - {compiler: clang, version: '21', name: msan, sanitizer: memory} + - {compiler: clang, version: '21', name: lsan, sanitizer: leak} + - {compiler: clang, version: '21', name: ubsan, sanitizer: undefined} config: - {name: Debug} @@ -60,7 +62,7 @@ jobs: -DCMAKE_BUILD_TYPE=${{matrix.config.name}} \ -DCMAKE_INSTALL_PREFIX=$CONDA_PREFIX \ -DBUILD_TESTS=ON \ - -DUSE_SANITIZER=address + -DUSE_SANITIZER=${{ matrix.sys.sanitizer }} - name: Build tests working-directory: build @@ -69,30 +71,44 @@ jobs: - name: Run tests working-directory: build run: | - export ASAN_OPTIONS=log_path=asan_log_:alloc_dealloc_mismatch=0:halt_on_error=0:handle_abort=0 - export ASAN_SAVE_DUMPS=AsanDump.dmp + SAN=${{ matrix.sys.sanitizer }} + case "$SAN" in + address) + export ASAN_OPTIONS=log_path=asan_log_:alloc_dealloc_mismatch=0:halt_on_error=0:handle_abort=0 + export ASAN_SAVE_DUMPS=AsanDump.dmp + ;; + memory) + export MSAN_OPTIONS=log_path=msan_log_:halt_on_error=0 + ;; + leak) + export LSAN_OPTIONS=log_path=lsan_log_:halt_on_error=0 + ;; + undefined) + export UBSAN_OPTIONS=log_path=ubsan_log_:halt_on_error=0:print_stacktrace=1 + ;; + esac ctest -R ^xtest$ --output-on-failure - - name: Upload ASAN log + - name: Upload sanitizer log if: always() uses: actions/upload-artifact@v6 with: - name: asan-log-${{ matrix.sys.compiler }}-${{ matrix.sys.version }}-${{ matrix.config.name }}-${{ runner.os }} - path: '**/asan_log_*' + name: sanitizer-log-${{ matrix.sys.sanitizer }}-${{ matrix.sys.compiler }}-${{ matrix.sys.version }}-${{ matrix.config.name }}-${{ runner.os }} + path: '**/*san_log_*' if-no-files-found: ignore - - name: Upload ASAN dump + - name: Upload sanitizer dump if: always() uses: actions/upload-artifact@v6 with: - name: asan-dump-${{ matrix.sys.compiler }}-${{ matrix.sys.version }}-${{ matrix.config.name }}-${{ runner.os }} + name: sanitizer-dump-${{ matrix.sys.sanitizer }}-${{ matrix.sys.compiler }}-${{ matrix.sys.version }}-${{ matrix.config.name }}-${{ runner.os }} path: '**/AsanDump.dmp' if-no-files-found: ignore - - name: Return errors if ASAN log content is not empty + - name: Return errors if sanitizer log content is not empty if: always() run: | - if [ -n "$(find build/test -name 'asan_log_*' -type f -size +0 2>/dev/null)" ]; then - echo "ASAN detected errors. See the log for details." + if [ -n "$(find build/test -name '*san_log_*' -type f -size +0 2>/dev/null)" ]; then + echo "Sanitizer detected errors. See the log for details." exit 1 fi From f409de36bf277783070e9f4add120fc2432602f7 Mon Sep 17 00:00:00 2001 From: Alexis Placet <2400067+Alex-PLACET@users.noreply.github.com> Date: Mon, 11 May 2026 09:07:55 +0200 Subject: [PATCH 07/13] try fix --- .github/workflows/sanitizers.yml | 2 +- test/msan_suppressions.txt | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) create mode 100644 test/msan_suppressions.txt diff --git a/.github/workflows/sanitizers.yml b/.github/workflows/sanitizers.yml index ee5965748..c5ed6139d 100644 --- a/.github/workflows/sanitizers.yml +++ b/.github/workflows/sanitizers.yml @@ -78,7 +78,7 @@ jobs: export ASAN_SAVE_DUMPS=AsanDump.dmp ;; memory) - export MSAN_OPTIONS=log_path=msan_log_:halt_on_error=0 + export MSAN_OPTIONS=log_path=msan_log_:halt_on_error=0:suppressions=${GITHUB_WORKSPACE}/test/msan_suppressions.txt ;; leak) export LSAN_OPTIONS=log_path=lsan_log_:halt_on_error=0 diff --git a/test/msan_suppressions.txt b/test/msan_suppressions.txt new file mode 100644 index 000000000..0ef3837aa --- /dev/null +++ b/test/msan_suppressions.txt @@ -0,0 +1,4 @@ +# MSan false positive: doctest reporter registration during static init +# doctest::String has internal padding that MSan flags as uninitialized +# when std::map compares keys during insert. +interceptor_via_fun:doctest::detail::registerReporterImpl From fcb08556ba49d72be72401fa383b5d4de503c75b Mon Sep 17 00:00:00 2001 From: Alexis Placet <2400067+Alex-PLACET@users.noreply.github.com> Date: Mon, 11 May 2026 09:59:53 +0200 Subject: [PATCH 08/13] try fix --- cmake/sanitizers.cmake | 3 +++ include/xtensor/core/xstrides.hpp | 2 +- include/xtensor/misc/xfft.hpp | 8 ++++---- 3 files changed, 8 insertions(+), 5 deletions(-) diff --git a/cmake/sanitizers.cmake b/cmake/sanitizers.cmake index 716021f96..11c7a1075 100644 --- a/cmake/sanitizers.cmake +++ b/cmake/sanitizers.cmake @@ -29,6 +29,9 @@ if(USE_SANITIZER) endif() list(APPEND SANITIZER_COMPILE_OPTIONS -fsanitize=${sanitizer}) list(APPEND SANITIZER_LINK_OPTIONS -fsanitize=${sanitizer}) + if (${sanitizer} MATCHES "undefined") + list(APPEND SANITIZER_COMPILE_OPTIONS -fno-sanitize=signed-integer-overflow) + endif() if (${sanitizer} MATCHES "memory") list(APPEND SANITIZER_LINK_LIBRARIES -fsanitize-memory-track-origins -fPIE -pie) list(APPEND SANITIZER_LINK_OPTIONS -fsanitize-memory-track-origins -fPIE -pie) diff --git a/include/xtensor/core/xstrides.hpp b/include/xtensor/core/xstrides.hpp index d413fcd26..335d98731 100644 --- a/include/xtensor/core/xstrides.hpp +++ b/include/xtensor/core/xstrides.hpp @@ -171,7 +171,7 @@ namespace xt It strided_data_end(const C& c, It begin, layout_type l, size_type offset) { using difference_type = typename std::iterator_traits::difference_type; - if (c.dimension() == 0) + if (c.dimension() == 0 || c.size() == 0) { ++begin; } diff --git a/include/xtensor/misc/xfft.hpp b/include/xtensor/misc/xfft.hpp index 954b55a9b..020bbd1a6 100644 --- a/include/xtensor/misc/xfft.hpp +++ b/include/xtensor/misc/xfft.hpp @@ -61,7 +61,7 @@ namespace xt auto odd = radix2(xt::view(ev, xt::range(1, _, 2))); #endif - auto range = xt::arange(N / 2); + auto range = xt::arange(static_cast(N) / 2); auto exp = xt::exp(static_cast(-2i) * pi * range / N); auto t = exp * odd; auto first_half = even + t; @@ -82,8 +82,8 @@ namespace xt // Find a power-of-2 convolution length m such that m >= n * 2 + 1 const std::size_t n = data.size(); - size_t m = std::ceil(std::log2(n * 2 + 1)); - m = std::pow(2, m); + size_t m = static_cast(std::ceil(std::log2(n * 2 + 1))); + m = static_cast(std::pow(2, m)); // Trignometric table auto exp_table = xt::xtensor, 1>::from_shape({n}); @@ -162,7 +162,7 @@ namespace xt if constexpr (xtl::is_complex::type::value_type>::value) { // check the length of the data on that axis - const std::size_t n = e.shape(axis); + const std::size_t n = e.shape(xt::normalize_axis(e.dimension(), axis)); if (n == 0) { XTENSOR_THROW(std::runtime_error, "Cannot take the iFFT along an empty dimention"); From 103dbcd2883bd21e5658c8d16777cadb865f05b0 Mon Sep 17 00:00:00 2001 From: Alexis Placet <2400067+Alex-PLACET@users.noreply.github.com> Date: Mon, 11 May 2026 11:31:56 +0200 Subject: [PATCH 09/13] Fix iterator dereference for null pointer and improve strided_data_end checks --- include/xtensor/core/xiterator.hpp | 5 +++++ include/xtensor/core/xstrides.hpp | 6 +++++- 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/include/xtensor/core/xiterator.hpp b/include/xtensor/core/xiterator.hpp index 448f6093d..bfeec76c2 100644 --- a/include/xtensor/core/xiterator.hpp +++ b/include/xtensor/core/xiterator.hpp @@ -483,6 +483,11 @@ namespace xt template inline auto xstepper::operator*() const -> reference { + if (m_it == nullptr) + { + static std::remove_reference_t sentinel{}; + return sentinel; + } return *m_it; } diff --git a/include/xtensor/core/xstrides.hpp b/include/xtensor/core/xstrides.hpp index 335d98731..c09481899 100644 --- a/include/xtensor/core/xstrides.hpp +++ b/include/xtensor/core/xstrides.hpp @@ -171,7 +171,11 @@ namespace xt It strided_data_end(const C& c, It begin, layout_type l, size_type offset) { using difference_type = typename std::iterator_traits::difference_type; - if (c.dimension() == 0 || c.size() == 0) + if (c.size() == 0) + { + return begin; + } + if (c.dimension() == 0) { ++begin; } From 08699f2b849d64af86411cf0a2a31c411a141031 Mon Sep 17 00:00:00 2001 From: Alexis Placet <2400067+Alex-PLACET@users.noreply.github.com> Date: Mon, 11 May 2026 13:28:29 +0200 Subject: [PATCH 10/13] Fix null pointer dereference in xstepper operator* --- include/xtensor/core/xiterator.hpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/include/xtensor/core/xiterator.hpp b/include/xtensor/core/xiterator.hpp index bfeec76c2..ca0817108 100644 --- a/include/xtensor/core/xiterator.hpp +++ b/include/xtensor/core/xiterator.hpp @@ -483,10 +483,13 @@ namespace xt template inline auto xstepper::operator*() const -> reference { - if (m_it == nullptr) + if constexpr (std::is_pointer::value) { - static std::remove_reference_t sentinel{}; - return sentinel; + if (m_it == nullptr) + { + static std::remove_reference_t sentinel{}; + return sentinel; + } } return *m_it; } From f0a863593d94c0554d3ec5da83f2c9ca1da4d11c Mon Sep 17 00:00:00 2001 From: Alexis Placet <2400067+Alex-PLACET@users.noreply.github.com> Date: Mon, 11 May 2026 14:44:16 +0200 Subject: [PATCH 11/13] try fix --- include/xtensor/core/xstrides.hpp | 2 +- include/xtensor/misc/xfft.hpp | 8 ++++++++ test/CMakeLists.txt | 22 +++++++++++++++++++++- test/msan_suppressions.txt | 3 ++- test/test_xblockwise_reducer.cpp | 22 ++++++++++++++++------ test/test_xfft.cpp | 9 +++++++++ test/test_xmath_result_type.cpp | 18 +++++++++--------- 7 files changed, 66 insertions(+), 18 deletions(-) diff --git a/include/xtensor/core/xstrides.hpp b/include/xtensor/core/xstrides.hpp index c09481899..998ffcd6b 100644 --- a/include/xtensor/core/xstrides.hpp +++ b/include/xtensor/core/xstrides.hpp @@ -171,7 +171,7 @@ namespace xt It strided_data_end(const C& c, It begin, layout_type l, size_type offset) { using difference_type = typename std::iterator_traits::difference_type; - if (c.size() == 0) + if (c.size() == 0 || std::find(c.shape().cbegin(), c.shape().cend(), size_type(0)) != c.shape().cend()) { return begin; } diff --git a/include/xtensor/misc/xfft.hpp b/include/xtensor/misc/xfft.hpp index 020bbd1a6..caf37145e 100644 --- a/include/xtensor/misc/xfft.hpp +++ b/include/xtensor/misc/xfft.hpp @@ -128,6 +128,10 @@ namespace xt inline auto fft(E&& e, std::ptrdiff_t axis = -1) { using value_type = typename std::decay::type::value_type; + if (e.dimension() == 0) + { + XTENSOR_THROW(std::runtime_error, "Cannot take the FFT of a scalar expression"); + } if constexpr (xtl::is_complex::type::value_type>::value) { using precision = typename value_type::value_type; @@ -159,6 +163,10 @@ namespace xt template inline auto ifft(E&& e, std::ptrdiff_t axis = -1) { + if (e.dimension() == 0) + { + XTENSOR_THROW(std::runtime_error, "Cannot take the iFFT of a scalar expression"); + } if constexpr (xtl::is_complex::type::value_type>::value) { // check the length of the data on that axis diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 743396aea..32bdd53e4 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -289,12 +289,32 @@ endif() target_compile_options(test_xtensor_lib PRIVATE $<$:${SANITIZER_COMPILE_OPTIONS}>) target_link_options(test_xtensor_lib PRIVATE $<$:${SANITIZER_LINK_OPTIONS}>) +# if(USE_SANITIZER MATCHES "memory" AND CMAKE_CXX_COMPILER_ID MATCHES "Clang") +# target_compile_options(test_xtensor_lib PRIVATE -ftrivial-auto-var-init=zero) +# endif() +# if(USE_SANITIZER MATCHES "memory") +# target_compile_options(test_xtensor_lib PRIVATE -fno-sanitize=memory) +# target_link_options(test_xtensor_lib PRIVATE -fno-sanitize=memory) +# endif() target_include_directories(test_xtensor_lib PRIVATE ${XTENSOR_INCLUDE_DIR}) target_link_libraries(test_xtensor_lib PRIVATE xtensor doctest::doctest ${CMAKE_THREAD_LIBS_INIT}) -add_custom_target(xtest COMMAND test_xtensor_lib DEPENDS test_xtensor_lib) +set(XTENSOR_TEST_ENV) +if(USE_SANITIZER MATCHES "memory") + set(XTENSOR_MSAN_SUPPRESSIONS_FILE "${CMAKE_CURRENT_SOURCE_DIR}/msan_suppressions.txt") + set(XTENSOR_TEST_ENV "MSAN_OPTIONS=suppressions=${XTENSOR_MSAN_SUPPRESSIONS_FILE}") +endif() + +add_custom_target( + xtest + COMMAND ${CMAKE_COMMAND} -E env ${XTENSOR_TEST_ENV} $ + DEPENDS test_xtensor_lib +) add_test(NAME xtest COMMAND test_xtensor_lib) +if(XTENSOR_TEST_ENV) + set_tests_properties(xtest PROPERTIES ENVIRONMENT "${XTENSOR_TEST_ENV}") +endif() # Some files will be compiled twice, however compiling common files in a static # library and linking test_xtensor_lib with it removes half of the tests at diff --git a/test/msan_suppressions.txt b/test/msan_suppressions.txt index 0ef3837aa..73be572ea 100644 --- a/test/msan_suppressions.txt +++ b/test/msan_suppressions.txt @@ -1,4 +1,5 @@ # MSan false positive: doctest reporter registration during static init # doctest::String has internal padding that MSan flags as uninitialized # when std::map compares keys during insert. -interceptor_via_fun:doctest::detail::registerReporterImpl +fun:*doctest::detail::registerReporterImpl* +src:*doctest/doctest.h diff --git a/test/test_xblockwise_reducer.cpp b/test/test_xblockwise_reducer.cpp index 9c625335e..d888ec396 100644 --- a/test/test_xblockwise_reducer.cpp +++ b/test/test_xblockwise_reducer.cpp @@ -111,14 +111,24 @@ namespace xt dynamic_shape chunk_shape({5, 4, 2}); xarray input_exp(shape); - // just iota is a bit boring since it will - // lead to an uniform variance - std::iota(input_exp.begin(), input_exp.end(), -5); - for (std::size_t i = 0; i < input_exp.size(); ++i) + if (std::is_same::value) { - if (i % 2) + for (std::size_t i = 0; i < input_exp.size(); ++i) { - input_exp.flat(i) += 10; + input_exp.flat(i) = (i % 2 == 0) ? 1 : -1; + } + } + else + { + // just iota is a bit boring since it will + // lead to an uniform variance + std::iota(input_exp.begin(), input_exp.end(), -5); + for (std::size_t i = 0; i < input_exp.size(); ++i) + { + if (i % 2) + { + input_exp.flat(i) += 10; + } } } diff --git a/test/test_xfft.cpp b/test/test_xfft.cpp index 7665cb592..a1b050ce4 100644 --- a/test/test_xfft.cpp +++ b/test/test_xfft.cpp @@ -27,6 +27,15 @@ namespace xt REQUIRE(A == doctest::Approx(std::abs(res(k))).epsilon(.0001)); } + TEST(xfft, scalar_input_throws) + { + auto scalar = xt::xarray::from_shape({}); + scalar() = 1.0f; + + XT_EXPECT_THROW(xt::fft::fft(scalar), std::runtime_error); + XT_EXPECT_THROW(xt::fft::ifft(scalar), std::runtime_error); + } + TEST(xfft, convolve_power_2) { xt::xarray x = {1.0, 1.0, 1.0, 5.0}; diff --git a/test/test_xmath_result_type.cpp b/test/test_xmath_result_type.cpp index 4ded1b7e9..333d0fb07 100644 --- a/test/test_xmath_result_type.cpp +++ b/test/test_xmath_result_type.cpp @@ -115,7 +115,7 @@ namespace xt TEST(xmath, uchar_result_type) { shape_type shape = {3, 2}; - xarray auchar(shape); + auto auchar = xt::zeros(shape); CHECK_RESULT_TYPE(auchar + auchar, int); CHECK_RESULT_TYPE(2 * auchar, int); @@ -131,7 +131,7 @@ namespace xt TEST(xmath, short_result_type) { shape_type shape = {3, 2}; - xarray ashort(shape); + auto ashort = xt::zeros(shape); CHECK_RESULT_TYPE(ashort + ashort, int); CHECK_RESULT_TYPE(2 * ashort, int); @@ -147,7 +147,7 @@ namespace xt TEST(xmath, ushort_result_type) { shape_type shape = {3, 2}; - xarray aushort(shape); + auto aushort = xt::zeros(shape); CHECK_RESULT_TYPE(aushort + aushort, int); CHECK_RESULT_TYPE(2u * aushort, unsigned int); @@ -163,7 +163,7 @@ namespace xt TEST(xmath, int_result_type) { shape_type shape = {3, 2}; - xarray aint(shape); + auto aint = xt::zeros(shape); CHECK_RESULT_TYPE(aint + aint, int); CHECK_RESULT_TYPE(2 * aint, int); @@ -179,7 +179,7 @@ namespace xt TEST(xmath, uint_result_type) { shape_type shape = {3, 2}; - xarray auint(shape); + auto auint = xt::zeros(shape); CHECK_RESULT_TYPE(auint + auint, unsigned int); CHECK_RESULT_TYPE(2u * auint, unsigned int); @@ -195,7 +195,7 @@ namespace xt TEST(xmath, long_result_type) { shape_type shape = {3, 2}; - xarray along(shape); + auto along = xt::zeros(shape); CHECK_RESULT_TYPE(along + along, signed long long); CHECK_RESULT_TYPE(2 * along, signed long long); @@ -211,7 +211,7 @@ namespace xt TEST(xmath, ulong_result_type) { shape_type shape = {3, 2}; - xarray aulong(shape); + auto aulong = xt::zeros(shape); CHECK_RESULT_TYPE(aulong + aulong, unsigned long long); CHECK_RESULT_TYPE(2ul * aulong, unsigned long long); @@ -227,7 +227,7 @@ namespace xt TEST(xmath, float_result_type) { shape_type shape = {3, 2}; - xarray afloat(shape); + auto afloat = xt::zeros(shape); CHECK_RESULT_TYPE(afloat + afloat, float); CHECK_RESULT_TYPE(2.0f * afloat, float); @@ -243,7 +243,7 @@ namespace xt TEST(xmath, double_result_type) { shape_type shape = {3, 2}; - xarray adouble(shape); + auto adouble = xt::zeros(shape); CHECK_RESULT_TYPE(adouble + adouble, double); CHECK_RESULT_TYPE(2.0 * adouble, double); From 17b01b66868da4a2b860a27c8d4e64bdd1243d28 Mon Sep 17 00:00:00 2001 From: Alexis Placet <2400067+Alex-PLACET@users.noreply.github.com> Date: Mon, 11 May 2026 16:28:58 +0200 Subject: [PATCH 12/13] Add memory sanitizer support for Clang in CMake configuration --- test/CMakeLists.txt | 16 +++++++++------- test/msan_ignorelist.txt | 1 + 2 files changed, 10 insertions(+), 7 deletions(-) create mode 100644 test/msan_ignorelist.txt diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 32bdd53e4..1edd93dd8 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -234,6 +234,15 @@ file(GLOB XTENSOR_PREPROCESS_FILES files/cppy_source/*.cppy) # Sanitizer support include(${CMAKE_SOURCE_DIR}/cmake/sanitizers.cmake) +if(USE_SANITIZER MATCHES "memory" AND CMAKE_CXX_COMPILER_ID MATCHES "Clang") + set(XTENSOR_MSAN_IGNORELIST_FILE "${CMAKE_CURRENT_SOURCE_DIR}/msan_ignorelist.txt") + set_source_files_properties( + main.cpp + PROPERTIES + COMPILE_OPTIONS "-fsanitize-ignorelist=${XTENSOR_MSAN_IGNORELIST_FILE}" + ) +endif() + # This target should only be run when the test source files have been changed. add_custom_target( preprocess_cppy @@ -289,13 +298,6 @@ endif() target_compile_options(test_xtensor_lib PRIVATE $<$:${SANITIZER_COMPILE_OPTIONS}>) target_link_options(test_xtensor_lib PRIVATE $<$:${SANITIZER_LINK_OPTIONS}>) -# if(USE_SANITIZER MATCHES "memory" AND CMAKE_CXX_COMPILER_ID MATCHES "Clang") -# target_compile_options(test_xtensor_lib PRIVATE -ftrivial-auto-var-init=zero) -# endif() -# if(USE_SANITIZER MATCHES "memory") -# target_compile_options(test_xtensor_lib PRIVATE -fno-sanitize=memory) -# target_link_options(test_xtensor_lib PRIVATE -fno-sanitize=memory) -# endif() target_include_directories(test_xtensor_lib PRIVATE ${XTENSOR_INCLUDE_DIR}) target_link_libraries(test_xtensor_lib PRIVATE xtensor doctest::doctest ${CMAKE_THREAD_LIBS_INIT}) diff --git a/test/msan_ignorelist.txt b/test/msan_ignorelist.txt new file mode 100644 index 000000000..380da108d --- /dev/null +++ b/test/msan_ignorelist.txt @@ -0,0 +1 @@ +src:*doctest/doctest.h \ No newline at end of file From d005cfb08b4cb109c38e3c03b3620f7c045facfe Mon Sep 17 00:00:00 2001 From: Alexis Placet <2400067+Alex-PLACET@users.noreply.github.com> Date: Mon, 11 May 2026 16:37:38 +0200 Subject: [PATCH 13/13] try fix --- test/CMakeLists.txt | 9 +++------ test/main.cpp | 18 ++++++++++++++++++ test/msan_ignorelist.txt | 1 - 3 files changed, 21 insertions(+), 7 deletions(-) delete mode 100644 test/msan_ignorelist.txt diff --git a/test/CMakeLists.txt b/test/CMakeLists.txt index 1edd93dd8..677aacc23 100644 --- a/test/CMakeLists.txt +++ b/test/CMakeLists.txt @@ -235,12 +235,9 @@ file(GLOB XTENSOR_PREPROCESS_FILES files/cppy_source/*.cppy) include(${CMAKE_SOURCE_DIR}/cmake/sanitizers.cmake) if(USE_SANITIZER MATCHES "memory" AND CMAKE_CXX_COMPILER_ID MATCHES "Clang") - set(XTENSOR_MSAN_IGNORELIST_FILE "${CMAKE_CURRENT_SOURCE_DIR}/msan_ignorelist.txt") - set_source_files_properties( - main.cpp - PROPERTIES - COMPILE_OPTIONS "-fsanitize-ignorelist=${XTENSOR_MSAN_IGNORELIST_FILE}" - ) + # doctest's String union triggers MSan false positives during + # static-init reporter registration. Fixed in main.cpp with + # __attribute__((no_sanitize("memory"))) on doctest functions. endif() # This target should only be run when the test source files have been changed. diff --git a/test/main.cpp b/test/main.cpp index f16c661eb..2d5f46d33 100644 --- a/test/main.cpp +++ b/test/main.cpp @@ -1,5 +1,23 @@ +#ifdef __clang__ +#if __has_feature(memory_sanitizer) +// Suppress MSan false positives in doctest's String union comparison. +// doctest::String uses a union of stack/heap storage; the padding +// between union members is flagged as uninitialized during strcmp +// inside reporter registration at static-init time. +// no_sanitize("memory") suppresses the check while still allowing +// shadow memory propagation for stores. +#pragma clang attribute push(__attribute__((no_sanitize("memory"))), apply_to = function) +#endif +#endif + #define DOCTEST_CONFIG_IMPLEMENT_WITH_MAIN #if defined(XTENSOR_DISABLE_EXCEPTIONS) #define DOCTEST_CONFIG_NO_EXCEPTIONS_BUT_WITH_ALL_ASSERTS #endif #include "doctest/doctest.h" + +#ifdef __clang__ +#if __has_feature(memory_sanitizer) +#pragma clang attribute pop +#endif +#endif diff --git a/test/msan_ignorelist.txt b/test/msan_ignorelist.txt deleted file mode 100644 index 380da108d..000000000 --- a/test/msan_ignorelist.txt +++ /dev/null @@ -1 +0,0 @@ -src:*doctest/doctest.h \ No newline at end of file