Skip to content

Commit 005b0c6

Browse files
committed
Add ASAN CI build
1 parent 1d158a9 commit 005b0c6

3 files changed

Lines changed: 145 additions & 0 deletions

File tree

.github/workflows/sanitizers.yml

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
name: Sanitizers
2+
on:
3+
workflow_dispatch:
4+
pull_request:
5+
push:
6+
branches: [master]
7+
concurrency:
8+
group: ${{ github.workflow }}-${{ github.job }}-${{ github.ref }}
9+
cancel-in-progress: true
10+
defaults:
11+
run:
12+
shell: bash -e -l {0}
13+
jobs:
14+
build:
15+
runs-on: ${{ matrix.os }}
16+
name: sanitizer / ${{ matrix.sys.compiler }} ${{ matrix.sys.version }} / ${{ matrix.config.name }} / ${{ matrix.sys.name }}
17+
strategy:
18+
fail-fast: false
19+
matrix:
20+
os: [ubuntu-24.04]
21+
sys:
22+
- {compiler: clang, version: '19', name: asan}
23+
- {compiler: clang, version: '21', name: asan}
24+
config:
25+
- {name: Debug}
26+
27+
steps:
28+
29+
- name: Install LLVM and Clang
30+
if: matrix.sys.compiler == 'clang'
31+
run: |
32+
wget https://apt.llvm.org/llvm.sh
33+
chmod +x llvm.sh
34+
sudo ./llvm.sh ${{matrix.sys.version}}
35+
sudo apt-get install -y clang-tools-${{matrix.sys.version}}
36+
sudo update-alternatives --install /usr/bin/clang++ clang++ /usr/bin/clang++-${{matrix.sys.version}} 200
37+
sudo update-alternatives --install /usr/bin/clang clang /usr/bin/clang-${{matrix.sys.version}} 200
38+
sudo update-alternatives --install /usr/bin/clang-scan-deps clang-scan-deps /usr/bin/clang-scan-deps-${{matrix.sys.version}} 200
39+
sudo update-alternatives --set clang /usr/bin/clang-${{matrix.sys.version}}
40+
sudo update-alternatives --set clang++ /usr/bin/clang++-${{matrix.sys.version}}
41+
sudo update-alternatives --set clang-scan-deps /usr/bin/clang-scan-deps-${{matrix.sys.version}}
42+
43+
- name: Checkout code
44+
uses: actions/checkout@v6
45+
46+
- name: Set conda environment
47+
uses: mamba-org/setup-micromamba@main
48+
with:
49+
environment-name: myenv
50+
environment-file: environment-dev.yml
51+
init-shell: bash
52+
cache-downloads: true
53+
54+
- name: Configure using CMake
55+
run: |
56+
export CC=clang
57+
export CXX=clang++
58+
cmake -G Ninja \
59+
-Bbuild \
60+
-DCMAKE_BUILD_TYPE:STRING=${{matrix.config.name}} \
61+
-DCMAKE_INSTALL_PREFIX=$CONDA_PREFIX \
62+
-DBUILD_TESTS=ON \
63+
-DUSE_SANITIZER=address
64+
65+
- name: Build tests
66+
working-directory: build
67+
run: cmake --build . --config ${{matrix.config.name}} --target test_xtensor_lib --parallel 8
68+
69+
- name: Run tests
70+
working-directory: build
71+
run: |
72+
export ASAN_OPTIONS=log_path=asan_log_:alloc_dealloc_mismatch=0:halt_on_error=0:handle_abort=0
73+
export ASAN_SAVE_DUMPS=AsanDump.dmp
74+
ctest -R ^xtest$ --output-on-failure
75+
76+
- name: Upload ASAN log
77+
if: always()
78+
uses: actions/upload-artifact@v6
79+
with:
80+
name: asan-log-${{ matrix.sys.compiler }}-${{ matrix.sys.version }}-${{ matrix.config.name }}-${{ runner.os }}
81+
path: '**/asan_log_*'
82+
if-no-files-found: ignore
83+
84+
- name: Upload ASAN dump
85+
if: always()
86+
uses: actions/upload-artifact@v6
87+
with:
88+
name: asan-dump-${{ matrix.sys.compiler }}-${{ matrix.sys.version }}-${{ matrix.config.name }}-${{ runner.os }}
89+
path: '**/AsanDump.dmp'
90+
if-no-files-found: ignore
91+
92+
- name: Return errors if ASAN log content is not empty
93+
if: always()
94+
run: |
95+
if [ -n "$(find build/test -name 'asan_log_*' -type f -size +0 2>/dev/null)" ]; then
96+
echo "ASAN detected errors. See the log for details."
97+
exit 1
98+
fi

cmake/sanitizers.cmake

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
set(AVAILABLE_SANITIZERS "address;leak;memory;thread;undefined")
2+
OPTION(USE_SANITIZER "Enable sanitizer(s). Options are: ${AVAILABLE_SANITIZERS}. Case insensitive; multiple options delimited by comma or space possible." "")
3+
string(TOLOWER "${USE_SANITIZER}" USE_SANITIZER)
4+
5+
if(USE_SANITIZER AND NOT (CMAKE_BUILD_TYPE IN_LIST "Debug;RelWithDebInfo"))
6+
message(FATAL_ERROR "❌ Sanitizer only supported in Debug and RelWithDebInfo build types. Current: ${CMAKE_BUILD_TYPE}")
7+
endif()
8+
9+
if(USE_SANITIZER)
10+
if(CMAKE_CXX_COMPILER_ID STREQUAL "MSVC")
11+
set(CMAKE_MSVC_DEBUG_INFORMATION_FORMAT "$<IF:$<AND:$<C_COMPILER_ID:MSVC>,$<CXX_COMPILER_ID:MSVC>>,$<$<CONFIG:Debug,RelWithDebInfo>:EditAndContinue>,$<$<CONFIG:Debug,RelWithDebInfo>:ProgramDatabase>>")
12+
13+
if(USE_SANITIZER MATCHES "address")
14+
string(APPEND CMAKE_CXX_FLAGS " /fsanitize=address /D_DISABLE_VECTOR_ANNOTATION /D_DISABLE_STRING_ANNOTATION")
15+
string(APPEND CMAKE_EXE_LINKER_FLAGS " /fsanitize=address")
16+
else()
17+
message(FATAL_ERROR "❌ Sanitizer not supported by MSVC: ${USE_SANITIZER}. It only supports 'address'.")
18+
endif()
19+
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_COMPILER_FRONTEND_VARIANT STREQUAL "MSVC")
20+
if(USE_SANITIZER MATCHES "address")
21+
string(APPEND CMAKE_CXX_FLAGS " /fsanitize=address /D_DISABLE_VECTOR_ANNOTATION /D_DISABLE_STRING_ANNOTATION")
22+
string(APPEND CMAKE_EXE_LINKER_FLAGS " /fsanitize=address")
23+
else()
24+
message(FATAL_ERROR "❌ Sanitizer not supported by Clang-MSVC: ${USE_SANITIZER}. It only supports 'address'.")
25+
endif()
26+
elseif(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" OR CMAKE_CXX_COMPILER_ID STREQUAL "AppleClang" OR CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
27+
foreach(sanitizer ${USE_SANITIZER})
28+
if(NOT ${sanitizer} IN_LIST AVAILABLE_SANITIZERS)
29+
message(FATAL_ERROR "❌ Sanitizer not supported: ${sanitizer}. It should be one of: ${AVAILABLE_SANITIZERS}.")
30+
endif()
31+
string(APPEND CMAKE_CXX_FLAGS " -fsanitize=${sanitizer}")
32+
string(APPEND CMAKE_EXE_LINKER_FLAGS " -fsanitize=${sanitizer}")
33+
if(${sanitizer} MATCHES "memory")
34+
string(APPEND CMAKE_CXX_FLAGS " -fsanitize-memory-track-origins -fPIE -pie")
35+
string(APPEND CMAKE_EXE_LINKER_FLAGS " -fsanitize-memory-track-origins -fPIE -pie")
36+
endif()
37+
endforeach()
38+
string(APPEND CMAKE_CXX_FLAGS " -fno-omit-frame-pointer")
39+
else()
40+
message(FATAL_ERROR "❌ Sanitizer: Unsupported compiler: ${CMAKE_CXX_COMPILER_ID}")
41+
endif()
42+
43+
message(STATUS "🔍 Using sanitizer: ${USE_SANITIZER}")
44+
endif()

test/CMakeLists.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,9 @@ endforeach()
231231

232232
file(GLOB XTENSOR_PREPROCESS_FILES files/cppy_source/*.cppy)
233233

234+
# Sanitizer support
235+
include(${CMAKE_SOURCE_DIR}/cmake/sanitizers.cmake)
236+
234237
# This target should only be run when the test source files have been changed.
235238
add_custom_target(
236239
preprocess_cppy

0 commit comments

Comments
 (0)