Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .clang-format
Original file line number Diff line number Diff line change
Expand Up @@ -274,4 +274,5 @@ WhitespaceSensitiveMacros:
- STRINGIZE
- SEQAN3_WORKAROUND_GCC_BOGUS_MEMCPY_START
- SEQAN3_WORKAROUND_GCC_BOGUS_MEMCPY_STOP
- reduction
...
2 changes: 1 addition & 1 deletion .github/workflows/ci_misc.yml
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ jobs:
mkdir build && cd build
cmake ../test/${{ matrix.build }} -DCMAKE_BUILD_TYPE=Release \
-DCMAKE_CXX_FLAGS="${{ matrix.cxx_flags }}" \
-DSEQAN3_BENCHMARK_MIN_TIME=0.01
-DSEQAN3_BENCHMARK_MIN_TIME=0.01s
case "${{ matrix.build }}" in
snippet) make gtest_main;;
performance) make benchmark_main;;
Expand Down
113 changes: 113 additions & 0 deletions .github/workflows/ci_sanitizer.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
# SPDX-FileCopyrightText: 2006-2024, Knut Reinert & Freie Universität Berlin
# SPDX-FileCopyrightText: 2016-2024, Knut Reinert & MPI für molekulare Genetik
# SPDX-License-Identifier: CC0-1.0

name: Sanitizer

on:
schedule:
- cron: "0 6 * * SAT"
workflow_dispatch:

concurrency:
group: sanitizer-actions
cancel-in-progress: true

env:
SEQAN3_NO_VERSION_CHECK: 1
TZ: Europe/Berlin
TSAN_OPTIONS: ignore_noninstrumented_modules=1
UBSAN_OPTIONS: print_stacktrace=1

defaults:
run:
shell: bash -Eeuxo pipefail {0}

jobs:
build:
name: ${{ matrix.name }} ${{ matrix.build_type }} ${{ matrix.os }}
runs-on: ${{ matrix.os }}
if: github.repository_owner == 'seqan' || github.event_name == 'workflow_dispatch'
env:
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' }}
strategy:
fail-fast: false
matrix:
name: [ASan, TSan, UBSan]
os: [ubuntu-latest, macos-14]
build_type: [Release, RelWithDebInfo, Debug]
exclude:
# macOS llvm packages do not contain libarcher, which is required for TSan to handle OpenMP.
# TSan runs on ubuntu with clang. Packages there contain libarcher.
- name: "TSan"
os: macos-14

include:
- os: macos-14
compiler: clang-19
- os: ubuntu-latest
compiler: gcc-14
image: ghcr.io/seqan/gcc-14

- name: "TSan"
os: ubuntu-latest
compiler: clang-19
image: ghcr.io/seqan/clang-19
cxx_flags: "-fsanitize=thread"
ctest_excludes: "-E async_input_buffer_snippet"

- name: "ASan"
os: ubuntu-latest
cxx_flags: "-fsanitize=address -Wno-maybe-uninitialized"
- name: "ASan"
os: macos-14
cxx_flags: "-fsanitize=address"

- name: "UBSan"
os: ubuntu-latest
cxx_flags: "-fsanitize=undefined,float-divide-by-zero -Wno-maybe-uninitialized -Wno-stringop-overflow"
- name: "UBSan"
os: macos-14
cxx_flags: "-fsanitize=undefined,float-divide-by-zero,local-bounds,nullability"
ctest_excludes: "-E tmp_directory_snippet_cmp_output"

container:
# If an image is defined for a matrix entry, use it.
# Otherwise, use the "empty"/'' image which means do not use a container at all.
image: ${{ matrix.image || '' }}
volumes:
- /home/runner:/home/runner
steps:
- name: Checkout
uses: actions/checkout@v4

- name: Setup compiler
if: contains(matrix.os, 'macos')
uses: seqan/actions/setup-compiler@main
with:
compiler: ${{ matrix.compiler }}

- name: Configure tests
run: |
mkdir build && cd build
cmake ../test/analyse -DCMAKE_BUILD_TYPE=${{ matrix.build_type }} \
-DCMAKE_CXX_FLAGS="-fno-omit-frame-pointer ${{ matrix.cxx_flags }} -fno-sanitize-recover=all" \
-DSEQAN3_BENCHMARK_MIN_TIME=0.01s \
-DSEQAN3_WITH_SEQAN2_CI=OFF
make gtest_main benchmark_main

- name: Build tests
working-directory: build
run: make -k

- name: Run tests
working-directory: build
continue-on-error: true
id: test
run: ctest . -j --output-on-failure --no-tests=error ${{ matrix.ctest_excludes }}

# Rerun failed tests with **one** thread. Some snippets touch the same file and fail in parallel.
- name: Rerun failed tests
if: steps.test.outcome == 'failure'
working-directory: build
run: ctest . -j1 --output-on-failure --no-tests=error --rerun-failed
2 changes: 1 addition & 1 deletion .github/workflows/cron_avx2.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@ jobs:
mkdir build && cd build
cmake ../test/${{ matrix.build }} -DCMAKE_BUILD_TYPE=Release \
-DCMAKE_CXX_FLAGS="-mavx2 ${{ matrix.cxx_flags }}" \
-DSEQAN3_BENCHMARK_MIN_TIME=0.01
-DSEQAN3_BENCHMARK_MIN_TIME=0.01s
case "${{ matrix.build }}" in
unit) make gtest_main;;
snippet) make gtest_main;;
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/cron_latest_libraries.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ jobs:
mkdir build && cd build
cmake ../test/${{ matrix.build }} -DCMAKE_BUILD_TYPE=Release \
-DCMAKE_CXX_FLAGS="${{ matrix.cxx_flags }}" \
-DSEQAN3_BENCHMARK_MIN_TIME=0.01
-DSEQAN3_BENCHMARK_MIN_TIME=0.01s
case "${{ matrix.build }}" in
unit) make gtest_main;;
snippet) make gtest_main;;
Expand Down
2 changes: 1 addition & 1 deletion include/seqan3/core/debug_stream/debug_stream_type.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ namespace seqan3
//!\ingroup core_debug_stream
//!\implements seqan3::enum_bitwise_operators
//!\sa seqan3::enum_bitwise_operators enables combining enum values.
enum fmtflags2
enum class fmtflags2 : int8_t
{
none = 0, //!< No flag is set.
utf8 = 1, //!< Enables use of non-ASCII UTF8 characters in formatted output.
Expand Down
8 changes: 7 additions & 1 deletion include/seqan3/io/structure_file/format_vienna.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -200,8 +200,14 @@ class format_vienna
using alph_type = typename std::ranges::range_value_t<structure_type>::structure_alphabet_type;
// We need the structure_length parameter to count the length of the structure while reading
// because we cannot infer it from the (already resized) structure_seq object.
auto res = std::ranges::copy(read_structure<alph_type>(stream_view), std::ranges::begin(structure));
auto range = read_structure<alph_type>(stream_view);
// Use std::views::take to avoid going out of bounds if the structure is longer than the sequence.
auto res = std::ranges::copy(range | std::views::take(std::ranges::distance(seq)),
std::ranges::begin(structure));
structure_length = std::ranges::distance(std::ranges::begin(structure), res.out);
// If the structure is longer than the sequence, there are characters left.
// std::ranges::distance will also consume the characters in the stream.
structure_length += std::ranges::distance(range);

if constexpr (!detail::decays_to_ignore_v<bpp_type>)
detail::bpp_from_rna_structure<alph_type>(bpp, structure);
Expand Down
18 changes: 17 additions & 1 deletion include/seqan3/utility/math.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,25 @@ base_t pow(base_t base, exp_t exp)
if (base == 0)
return 0;

auto check = [base](base_t result)
{
if (base > 0)
{
return result > std::numeric_limits<base_t>::max() / base;
}
else if (result < 0) // and base < 0
{
return result < std::numeric_limits<base_t>::max() / base;
}
else // base < 0 and result > 0
{
return base < std::numeric_limits<base_t>::min() / result;
}
};

for (exp_t i = 0; i < exp; ++i)
{
if ((base < 0 ? std::numeric_limits<base_t>::min() : std::numeric_limits<base_t>::max()) / base < result)
if (check(result))
{
std::string error_message{"Calculating " + std::to_string(base) + '^' + std::to_string(exp)
+ " will result in an "
Expand Down
2 changes: 1 addition & 1 deletion test/performance/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ include (../seqan3-test.cmake)
CPMGetPackage (benchmark)

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

macro (seqan3_benchmark benchmark_cpp)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -113,7 +113,7 @@ void seqan3_affine_dna4_omp_for(benchmark::State & state)
int64_t total = 0;
for (auto _ : state)
{
# pragma omp parallel for num_threads(std::thread::hardware_concurrency()) schedule(guided)
# pragma omp parallel for num_threads(std::thread::hardware_concurrency()) schedule(guided) reduction(+:total)
for (size_t i = 0; i < zip.size(); ++i)
{
auto rng = align_pairwise(zip[i], affine_cfg | result_t{});
Expand Down Expand Up @@ -182,7 +182,7 @@ void seqan2_affine_dna4_omp_for(benchmark::State & state)
int64_t total = 0;
for (auto _ : state)
{
# pragma omp parallel for num_threads(std::thread::hardware_concurrency()) schedule(guided)
# pragma omp parallel for num_threads(std::thread::hardware_concurrency()) schedule(guided) reduction(+:total)
for (size_t i = 0; i < seqan2::length(vec1); ++i)
{
if constexpr (score_only)
Expand Down
27 changes: 6 additions & 21 deletions test/performance/range/container_assignment_benchmark.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,8 @@ struct assignment_functor
{
template <typename container_t>
requires (id == tag::assignment_operator)
static constexpr void call(container_t & to, container_t const & from) noexcept(
noexcept(std::is_nothrow_assignable_v<container_t, container_t>))
static constexpr void call(container_t & to, container_t const & from)
noexcept(noexcept(std::is_nothrow_assignable_v<container_t, container_t>))
{
benchmark::DoNotOptimize(to = from);
}
Expand All @@ -53,31 +53,18 @@ struct assignment_functor
}
};

template <typename container_t>
requires requires (container_t v) { v.clear(); }
static constexpr void clear(container_t & container) noexcept(noexcept(std::declval<container_t>().clear()))
{
container.clear();
}

template <typename container_t>
requires requires (container_t v) { v.resize(1u); }
static constexpr void resize(container_t & container,
size_t const size) noexcept(noexcept(std::declval<container_t>().resize(1u)))
static constexpr void resize(container_t & container, size_t const size)
noexcept(noexcept(std::declval<container_t>().resize(1u)))
{
container.resize(size);
}

#if SEQAN3_HAS_SEQAN2
template <typename container_t>
static constexpr void clear(container_t & container) noexcept(noexcept(seqan2::clear(std::declval<container_t>())))
{
seqan2::clear(container);
}

template <typename container_t>
static constexpr void resize(container_t & container,
size_t const size) noexcept(noexcept(seqan2::resize(std::declval<container_t>(), 1u)))
static constexpr void resize(container_t & container, size_t const size)
noexcept(noexcept(seqan2::resize(std::declval<container_t>(), 1u)))
{
seqan2::resize(container, size);
}
Expand Down Expand Up @@ -107,8 +94,6 @@ static void assign(benchmark::State & state)
{
fn.call(to, from);
benchmark::ClobberMemory();
clear(to);
benchmark::ClobberMemory();
}
}

Expand Down
2 changes: 1 addition & 1 deletion test/snippet/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ macro (seqan3_snippet test_name_prefix snippet snippet_base_path)
add_test (NAME "${snippet_compare_test_target}"
COMMAND ${CMAKE_COMMAND} -DTARGET_FILE=$<TARGET_FILE:${target}>
-DSOURCE_FILE=${snippet_base_path}/${snippet} #
-P "${CMAKE_SOURCE_DIR}/compare_snippet_output.cmake")
-P "${CMAKE_CURRENT_SOURCE_DIR}/compare_snippet_output.cmake")

# disable version checker, as it interferes with comparing the snippet output
set_tests_properties ("${snippet_compare_test_target}" PROPERTIES ENVIRONMENT SEQAN3_NO_VERSION_CHECK=0)
Expand Down
4 changes: 2 additions & 2 deletions test/unit/alignment/scoring/scoring_scheme_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ TEST(nucleotide_scoring_scheme, template_argument_deduction)
}

{
std::array<std::array<int16_t, 15>, 15> m;
std::array<std::array<int16_t, 15>, 15> m{};
seqan3::nucleotide_scoring_scheme scheme{m};
EXPECT_TRUE((std::is_same_v<decltype(scheme), seqan3::nucleotide_scoring_scheme<int16_t>>));
}
Expand All @@ -83,7 +83,7 @@ TEST(aminoacid_scoring_scheme, template_argument_deduction)
}

{
std::array<std::array<int16_t, 27>, 27> m;
std::array<std::array<int16_t, 27>, 27> m{};
seqan3::aminoacid_scoring_scheme scheme{m};
EXPECT_TRUE((std::is_same_v<decltype(scheme), seqan3::aminoacid_scoring_scheme<int16_t>>));
}
Expand Down
8 changes: 4 additions & 4 deletions test/unit/contrib/parallel/buffer_queue_parallel_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -137,8 +137,8 @@ void test_buffer_queue_wait_throw(size_t initialCapacity)
if constexpr (sequential_pop_t::value)
thread_count = writer_count + 1;

// std::cout << "threads: " << thread_count << ‘\n‘;
// std::cout << "writers: " << writer_count << ‘\n‘;
// std::cout << "threads: " << thread_count << '\n';
// std::cout << "writers: " << writer_count << '\n';

ASSERT_GE(thread_count, 2u);

Expand All @@ -147,8 +147,8 @@ void test_buffer_queue_wait_throw(size_t initialCapacity)
std::vector<std::thread> workers;
std::atomic<size_t> registered_writer = 0;
std::atomic<size_t> registered_reader = 0;
seqan3::contrib::queue_op_status push_status = seqan3::contrib::queue_op_status::success;
seqan3::contrib::queue_op_status pop_status = seqan3::contrib::queue_op_status::success;
std::atomic<seqan3::contrib::queue_op_status> push_status = seqan3::contrib::queue_op_status::success;
std::atomic<seqan3::contrib::queue_op_status> pop_status = seqan3::contrib::queue_op_status::success;
for (size_t tid = 0; tid < thread_count; ++tid)
{
workers.push_back(std::thread(
Expand Down
4 changes: 2 additions & 2 deletions test/unit/range/iterator_test_template.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -499,14 +499,14 @@ inline void jump_backward_test(it_begin_t && it_begin, rng_t && rng)
// Backward copy it + (-n)
for (size_t n = 0; n < sz; ++n)
{
expect_iter_equal<test_type>(pre_end_it + (-1 * n), pre_end_rng_it - n);
expect_iter_equal<test_type>(pre_end_it + (-static_cast<std::ptrdiff_t>(n)), pre_end_rng_it - n);
expect_iter_equal<test_type>(pre_end_it, pre_end_rng_it);
}

// Backward copy friend through (-n) + it
for (size_t n = 0; n < sz; ++n)
{
expect_iter_equal<test_type>((-1 * n) + pre_end_it, pre_end_rng_it - n);
expect_iter_equal<test_type>((-static_cast<std::ptrdiff_t>(n)) + pre_end_it, pre_end_rng_it - n);
expect_iter_equal<test_type>(pre_end_it, pre_end_rng_it);
}
}
Expand Down
Loading