Skip to content

Commit 787d724

Browse files
authored
Merge pull request #3321 from eseiler/fix/tsan
[INFRA] Sanitizer CI
2 parents 5c60129 + b883049 commit 787d724

File tree

15 files changed

+160
-39
lines changed

15 files changed

+160
-39
lines changed

.clang-format

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,4 +274,5 @@ WhitespaceSensitiveMacros:
274274
- STRINGIZE
275275
- SEQAN3_WORKAROUND_GCC_BOGUS_MEMCPY_START
276276
- SEQAN3_WORKAROUND_GCC_BOGUS_MEMCPY_STOP
277+
- reduction
277278
...

.github/workflows/ci_misc.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ jobs:
6060
mkdir build && cd build
6161
cmake ../test/${{ matrix.build }} -DCMAKE_BUILD_TYPE=Release \
6262
-DCMAKE_CXX_FLAGS="${{ matrix.cxx_flags }}" \
63-
-DSEQAN3_BENCHMARK_MIN_TIME=0.01
63+
-DSEQAN3_BENCHMARK_MIN_TIME=0.01s
6464
case "${{ matrix.build }}" in
6565
snippet) make gtest_main;;
6666
performance) make benchmark_main;;

.github/workflows/ci_sanitizer.yml

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
# SPDX-FileCopyrightText: 2006-2024, Knut Reinert & Freie Universität Berlin
2+
# SPDX-FileCopyrightText: 2016-2024, Knut Reinert & MPI für molekulare Genetik
3+
# SPDX-License-Identifier: CC0-1.0
4+
5+
name: Sanitizer
6+
7+
on:
8+
schedule:
9+
- cron: "0 6 * * SAT"
10+
workflow_dispatch:
11+
12+
concurrency:
13+
group: sanitizer-actions
14+
cancel-in-progress: true
15+
16+
env:
17+
SEQAN3_NO_VERSION_CHECK: 1
18+
TZ: Europe/Berlin
19+
TSAN_OPTIONS: ignore_noninstrumented_modules=1
20+
UBSAN_OPTIONS: print_stacktrace=1
21+
22+
defaults:
23+
run:
24+
shell: bash -Eeuxo pipefail {0}
25+
26+
jobs:
27+
build:
28+
name: ${{ matrix.name }} ${{ matrix.build_type }} ${{ matrix.os }}
29+
runs-on: ${{ matrix.os }}
30+
if: github.repository_owner == 'seqan' || github.event_name == 'workflow_dispatch'
31+
env:
32+
ASAN_OPTIONS: strict_string_checks=1:detect_stack_use_after_return=1:check_initialization_order=1:strict_init_order=1:detect_leaks=${{ contains(matrix.os, 'macos') && '0' || '1' }}
33+
strategy:
34+
fail-fast: false
35+
matrix:
36+
name: [ASan, TSan, UBSan]
37+
os: [ubuntu-latest, macos-14]
38+
build_type: [Release, RelWithDebInfo, Debug]
39+
exclude:
40+
# macOS llvm packages do not contain libarcher, which is required for TSan to handle OpenMP.
41+
# TSan runs on ubuntu with clang. Packages there contain libarcher.
42+
- name: "TSan"
43+
os: macos-14
44+
45+
include:
46+
- os: macos-14
47+
compiler: clang-19
48+
- os: ubuntu-latest
49+
compiler: gcc-14
50+
image: ghcr.io/seqan/gcc-14
51+
52+
- name: "TSan"
53+
os: ubuntu-latest
54+
compiler: clang-19
55+
image: ghcr.io/seqan/clang-19
56+
cxx_flags: "-fsanitize=thread"
57+
ctest_excludes: "-E async_input_buffer_snippet"
58+
59+
- name: "ASan"
60+
os: ubuntu-latest
61+
cxx_flags: "-fsanitize=address -Wno-maybe-uninitialized"
62+
- name: "ASan"
63+
os: macos-14
64+
cxx_flags: "-fsanitize=address"
65+
66+
- name: "UBSan"
67+
os: ubuntu-latest
68+
cxx_flags: "-fsanitize=undefined,float-divide-by-zero -Wno-maybe-uninitialized -Wno-stringop-overflow"
69+
- name: "UBSan"
70+
os: macos-14
71+
cxx_flags: "-fsanitize=undefined,float-divide-by-zero,local-bounds,nullability"
72+
ctest_excludes: "-E tmp_directory_snippet_cmp_output"
73+
74+
container:
75+
# If an image is defined for a matrix entry, use it.
76+
# Otherwise, use the "empty"/'' image which means do not use a container at all.
77+
image: ${{ matrix.image || '' }}
78+
volumes:
79+
- /home/runner:/home/runner
80+
steps:
81+
- name: Checkout
82+
uses: actions/checkout@v4
83+
84+
- name: Setup compiler
85+
if: contains(matrix.os, 'macos')
86+
uses: seqan/actions/setup-compiler@main
87+
with:
88+
compiler: ${{ matrix.compiler }}
89+
90+
- name: Configure tests
91+
run: |
92+
mkdir build && cd build
93+
cmake ../test/analyse -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} \
94+
-DCMAKE_CXX_FLAGS="-fno-omit-frame-pointer ${{ matrix.cxx_flags }} -fno-sanitize-recover=all" \
95+
-DSEQAN3_BENCHMARK_MIN_TIME=0.01s \
96+
-DSEQAN3_WITH_SEQAN2_CI=OFF
97+
make gtest_main benchmark_main
98+
99+
- name: Build tests
100+
working-directory: build
101+
run: make -k
102+
103+
- name: Run tests
104+
working-directory: build
105+
continue-on-error: true
106+
id: test
107+
run: ctest . -j --output-on-failure --no-tests=error ${{ matrix.ctest_excludes }}
108+
109+
# Rerun failed tests with **one** thread. Some snippets touch the same file and fail in parallel.
110+
- name: Rerun failed tests
111+
if: steps.test.outcome == 'failure'
112+
working-directory: build
113+
run: ctest . -j1 --output-on-failure --no-tests=error --rerun-failed

.github/workflows/cron_avx2.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ jobs:
5151
mkdir build && cd build
5252
cmake ../test/${{ matrix.build }} -DCMAKE_BUILD_TYPE=Release \
5353
-DCMAKE_CXX_FLAGS="-mavx2 ${{ matrix.cxx_flags }}" \
54-
-DSEQAN3_BENCHMARK_MIN_TIME=0.01
54+
-DSEQAN3_BENCHMARK_MIN_TIME=0.01s
5555
case "${{ matrix.build }}" in
5656
unit) make gtest_main;;
5757
snippet) make gtest_main;;

.github/workflows/cron_latest_libraries.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ jobs:
5959
mkdir build && cd build
6060
cmake ../test/${{ matrix.build }} -DCMAKE_BUILD_TYPE=Release \
6161
-DCMAKE_CXX_FLAGS="${{ matrix.cxx_flags }}" \
62-
-DSEQAN3_BENCHMARK_MIN_TIME=0.01
62+
-DSEQAN3_BENCHMARK_MIN_TIME=0.01s
6363
case "${{ matrix.build }}" in
6464
unit) make gtest_main;;
6565
snippet) make gtest_main;;

include/seqan3/core/debug_stream/debug_stream_type.hpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ namespace seqan3
2828
//!\ingroup core_debug_stream
2929
//!\implements seqan3::enum_bitwise_operators
3030
//!\sa seqan3::enum_bitwise_operators enables combining enum values.
31-
enum fmtflags2
31+
enum class fmtflags2 : int8_t
3232
{
3333
none = 0, //!< No flag is set.
3434
utf8 = 1, //!< Enables use of non-ASCII UTF8 characters in formatted output.

include/seqan3/io/structure_file/format_vienna.hpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -200,8 +200,14 @@ class format_vienna
200200
using alph_type = typename std::ranges::range_value_t<structure_type>::structure_alphabet_type;
201201
// We need the structure_length parameter to count the length of the structure while reading
202202
// because we cannot infer it from the (already resized) structure_seq object.
203-
auto res = std::ranges::copy(read_structure<alph_type>(stream_view), std::ranges::begin(structure));
203+
auto range = read_structure<alph_type>(stream_view);
204+
// Use std::views::take to avoid going out of bounds if the structure is longer than the sequence.
205+
auto res = std::ranges::copy(range | std::views::take(std::ranges::distance(seq)),
206+
std::ranges::begin(structure));
204207
structure_length = std::ranges::distance(std::ranges::begin(structure), res.out);
208+
// If the structure is longer than the sequence, there are characters left.
209+
// std::ranges::distance will also consume the characters in the stream.
210+
structure_length += std::ranges::distance(range);
205211

206212
if constexpr (!detail::decays_to_ignore_v<bpp_type>)
207213
detail::bpp_from_rna_structure<alph_type>(bpp, structure);

include/seqan3/utility/math.hpp

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -123,9 +123,25 @@ base_t pow(base_t base, exp_t exp)
123123
if (base == 0)
124124
return 0;
125125

126+
auto check = [base](base_t result)
127+
{
128+
if (base > 0)
129+
{
130+
return result > std::numeric_limits<base_t>::max() / base;
131+
}
132+
else if (result < 0) // and base < 0
133+
{
134+
return result < std::numeric_limits<base_t>::max() / base;
135+
}
136+
else // base < 0 and result > 0
137+
{
138+
return base < std::numeric_limits<base_t>::min() / result;
139+
}
140+
};
141+
126142
for (exp_t i = 0; i < exp; ++i)
127143
{
128-
if ((base < 0 ? std::numeric_limits<base_t>::min() : std::numeric_limits<base_t>::max()) / base < result)
144+
if (check(result))
129145
{
130146
std::string error_message{"Calculating " + std::to_string(base) + '^' + std::to_string(exp)
131147
+ " will result in an "

test/performance/CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ include (../seqan3-test.cmake)
1010
CPMGetPackage (benchmark)
1111

1212
set (SEQAN3_BENCHMARK_MIN_TIME
13-
"1"
13+
"1s"
1414
CACHE STRING "Set --benchmark_min_time= for each bechmark. Timings are unreliable in CI.")
1515

1616
macro (seqan3_benchmark benchmark_cpp)

test/performance/alignment/global_affine_alignment_parallel_benchmark.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ void seqan3_affine_dna4_omp_for(benchmark::State & state)
113113
int64_t total = 0;
114114
for (auto _ : state)
115115
{
116-
# pragma omp parallel for num_threads(std::thread::hardware_concurrency()) schedule(guided)
116+
# pragma omp parallel for num_threads(std::thread::hardware_concurrency()) schedule(guided) reduction(+:total)
117117
for (size_t i = 0; i < zip.size(); ++i)
118118
{
119119
auto rng = align_pairwise(zip[i], affine_cfg | result_t{});
@@ -182,7 +182,7 @@ void seqan2_affine_dna4_omp_for(benchmark::State & state)
182182
int64_t total = 0;
183183
for (auto _ : state)
184184
{
185-
# pragma omp parallel for num_threads(std::thread::hardware_concurrency()) schedule(guided)
185+
# pragma omp parallel for num_threads(std::thread::hardware_concurrency()) schedule(guided) reduction(+:total)
186186
for (size_t i = 0; i < seqan2::length(vec1); ++i)
187187
{
188188
if constexpr (score_only)

0 commit comments

Comments
 (0)