Skip to content

Commit

Permalink
Merge pull request #245 from bluescarni/pr/msan
Browse files Browse the repository at this point in the history
Add builds with memory sanitizer
  • Loading branch information
bluescarni authored Jun 2, 2020
2 parents b03bf6b + 700b0a8 commit da5bd09
Show file tree
Hide file tree
Showing 4 changed files with 350 additions and 0 deletions.
24 changes: 24 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,11 +73,35 @@ jobs:
- run:
name: Build and test
command: bash ./tools/circleci_bionic_clang6.sh
focal_clang9_msan_00:
docker:
- image: circleci/buildpack-deps:focal
steps:
- checkout
- run:
name: Build and test
command: bash ./tools/circleci_focal_clang9_msan.sh
environment:
TEST_NSPLIT: 2
SPLIT_TEST_NUM: 0
focal_clang9_msan_01:
docker:
- image: circleci/buildpack-deps:focal
steps:
- checkout
- run:
name: Build and test
command: bash ./tools/circleci_focal_clang9_msan.sh
environment:
TEST_NSPLIT: 2
SPLIT_TEST_NUM: 1

workflows:
version: 2
all_builds:
jobs:
- focal_clang9_msan_00
- focal_clang9_msan_01
- bionic_clang6
- bionic_gcc7_conda_coverage
- bionic_gcc7_conda_release
Expand Down
5 changes: 5 additions & 0 deletions test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,11 @@ endfunction()

ADD_MPPP_TESTCASE(concepts)
ADD_MPPP_TESTCASE(global_header)
# NOTE: the interop test requires all optional
# deps to be enabled.
if(MPPP_WITH_QUADMATH AND MPPP_WITH_MPFR AND MPPP_WITH_MPC)
ADD_MPPP_TESTCASE(interop_test)
endif()

ADD_MPPP_TESTCASE(integer_abs)
ADD_MPPP_TESTCASE(integer_addsub_ui_si)
Expand Down
270 changes: 270 additions & 0 deletions test/interop_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,270 @@
// Copyright 2016-2020 Francesco Biscani ([email protected])
//
// This file is part of the mp++ library.
//
// This Source Code Form is subject to the terms of the Mozilla
// Public License v. 2.0. If a copy of the MPL was not distributed
// with this file, You can obtain one at http://mozilla.org/MPL/2.0/.

#if defined(__clang__) || defined(__GNUC__)

// NOTE: range warnings in the interop between
// real128 and __(u)int128_t.
#pragma GCC diagnostic ignored "-Wconversion"

#endif

#include <complex>
#include <tuple>
#include <type_traits>

#include <mp++/mp++.hpp>

#include "catch.hpp"
#include "test_utils.hpp"

// NOLINTNEXTLINE(google-build-using-namespace)
using namespace mppp;
// NOLINTNEXTLINE(google-build-using-namespace)
using namespace mppp_test;

using mppp_types = std::tuple<integer<1>, rational<1>, real, real128, complex128, complex>;

using cpp_types = std::tuple<int, double, std::complex<double>
#if defined(MPPP_HAVE_GCC_INT128)
,
__int128_t, __uint128_t
#endif
>;

template <typename T>
struct is_mppp_complex : std::false_type {
};

template <>
struct is_mppp_complex<complex128> : std::true_type {
};

template <>
struct is_mppp_complex<complex> : std::true_type {
};

struct mppp_interop_tester {
template <typename A, typename B>
static void run_ineq_cmp(const A &a, const B &b, std::false_type)
{
REQUIRE(!(a < b));
REQUIRE(a <= b);
REQUIRE(!(a > b));
REQUIRE(a >= b);
}
template <typename A, typename B>
static void run_ineq_cmp(const A &, const B &, std::true_type)
{
}

template <typename T>
struct runner {
template <typename U>
void operator()(const U &) const
{
// Construct T from U.
T x1{U{42}};
REQUIRE(x1 == 42);

// Assign U to T.
U y1{43};
x1 = y1;
REQUIRE(x1 == 43);

// Convert T to U.
// NOTE: this is probably not strictly necessary,
// as it is covered by switching around T and U.
REQUIRE(static_cast<U>(x1) == 43);

// Basic binary arithmetic.
REQUIRE(x1 + U{4} == 47);
REQUIRE(x1 - U{4} == 39);
REQUIRE(x1 * U{2} == 86);
x1 = 10;
REQUIRE(x1 / U{2} == 5);

// Basic in-place arithmetics.
REQUIRE((x1 += U{1}) == 11);
REQUIRE((x1 -= U{1}) == 10);
REQUIRE((x1 *= U{2}) == 20);
REQUIRE((x1 /= U{2}) == 10);

// Exponentiation.
REQUIRE(mppp::pow(x1, U{2}) == 100);

// Comparison.
REQUIRE(x1 == U{10});
REQUIRE(x1 != U{11});

run_ineq_cmp(x1, U{10}, std::integral_constant < bool,
is_mppp_complex<T>::value || is_mppp_complex<U>::value > {});
}
void operator()(const T &) const {}
};
template <typename T>
void operator()(const T &) const
{
tuple_for_each(mppp_types{}, runner<T>{});
}
};

TEST_CASE("mp++ interop")
{
tuple_for_each(mppp_types{}, mppp_interop_tester{});
}

struct mppp_cpp_interop_tester {
template <typename A, typename B>
static void run_ineq_cmp(const A &a, const B &b, std::false_type)
{
REQUIRE(!(a < b));
REQUIRE(a <= b);
REQUIRE(!(a > b));
REQUIRE(a >= b);
}
template <typename A, typename B>
static void run_ineq_cmp(const A &, const B &, std::true_type)
{
}

template <typename T>
struct runner {
template <typename U>
void operator()(const U &) const
{
// NOTE: here T is an mp++ type,
// U a C++ type.

// Construct T from U.
T x1{U{42}};
REQUIRE(x1 == 42);

// Assign U to T.
U y1{43};
x1 = y1;
REQUIRE(x1 == 43);

// Convert T to U.
REQUIRE(static_cast<U>(x1) == U{43});

// Basic binary arithmetic.
REQUIRE(x1 + U{4} == 47.);
REQUIRE(x1 - U{4} == 39.);
REQUIRE(x1 * U{2} == 86.);
x1 = 10;
REQUIRE(x1 / U{2} == 5.);

// Basic in-place arithmetics.
REQUIRE((x1 += U{1}) == 11);
REQUIRE((x1 -= U{1}) == 10);
REQUIRE((x1 *= U{2}) == 20);
REQUIRE((x1 /= U{2}) == 10);

// Exponentiation.
// NOTE: don't check the result due to roundoff errors.
(void)mppp::pow(x1, U{1});

// Comparison.
REQUIRE(x1 == U{10});
REQUIRE(x1 != U{11});

run_ineq_cmp(x1, U{10}, std::integral_constant < bool,
is_mppp_complex<T>::value || is_cpp_complex<U>::value > {});
}
void operator()(const T &) const {}
};
template <typename T>
void operator()(const T &) const
{
tuple_for_each(cpp_types{}, runner<T>{});
}
};

TEST_CASE("mppp cpp interop")
{
tuple_for_each(mppp_types{}, mppp_cpp_interop_tester{});
}

struct cpp_mppp_interop_tester {
template <typename A, typename B>
static void run_ineq_cmp(const A &a, const B &b, std::false_type)
{
REQUIRE(!(a < b));
REQUIRE(a <= b);
REQUIRE(!(a > b));
REQUIRE(a >= b);
}
template <typename A, typename B>
static void run_ineq_cmp(const A &, const B &, std::true_type)
{
}

template <typename T>
struct runner {
template <typename U>
void operator()(const U &) const
{
// NOTE: here T is a C++ type,
// U an mp++ type.

// Construct T from U.
T x1{U{42}};
// NOLINTNEXTLINE(clang-diagnostic-implicit-int-float-conversion)
REQUIRE(x1 == 42.);

// Assign U to T.
U y1{43};
x1 = static_cast<T>(y1);
// NOLINTNEXTLINE(clang-diagnostic-implicit-int-float-conversion)
REQUIRE(x1 == 43.);

// Convert T to U.
REQUIRE(static_cast<U>(x1) == U{43});

// Basic binary arithmetic.
REQUIRE(x1 + U{4} == 47.);
REQUIRE(x1 - U{4} == 39.);
REQUIRE(x1 * U{2} == 86.);
x1 = 10;
REQUIRE(x1 / U{2} == 5.);

// Basic in-place arithmetics.
// NOLINTNEXTLINE(clang-diagnostic-implicit-int-float-conversion)
REQUIRE((x1 += U{1}) == 11.);
// NOLINTNEXTLINE(clang-diagnostic-implicit-int-float-conversion)
REQUIRE((x1 -= U{1}) == 10.);
// NOLINTNEXTLINE(clang-diagnostic-implicit-int-float-conversion)
REQUIRE((x1 *= U{2}) == 20.);
// NOLINTNEXTLINE(clang-diagnostic-implicit-int-float-conversion)
REQUIRE((x1 /= U{2}) == 10.);

// Exponentiation.
// NOTE: don't check the result due to roundoff errors.
(void)mppp::pow(x1, U{1});

// Comparison.
REQUIRE(x1 == U{10});
REQUIRE(x1 != U{11});

run_ineq_cmp(x1, U{10}, std::integral_constant < bool,
is_cpp_complex<T>::value || is_mppp_complex<U>::value > {});
}
void operator()(const T &) const {}
};
template <typename T>
void operator()(const T &) const
{
tuple_for_each(mppp_types{}, runner<T>{});
}
};

TEST_CASE("cpp mppp interop")
{
tuple_for_each(cpp_types{}, cpp_mppp_interop_tester{});
}
51 changes: 51 additions & 0 deletions tools/circleci_focal_clang9_msan.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
#!/usr/bin/env bash

# Echo each command
set -x

# Exit on error.
set -e

# Core deps.
sudo apt-get install build-essential cmake wget clang ninja-build

# Create the build dir and cd into it.
mkdir build
cd build
MPPP_BUILD_DIR=`pwd`

# libc++ setup. See:
# https://github.com/google/sanitizers/wiki/MemorySanitizerLibcxxHowTo
git clone --depth=1 https://github.com/llvm/llvm-project
cd llvm-project
mkdir build
cd build
LLVM_BUILD_DIR=`pwd`
cmake -GNinja ../llvm \
-DCMAKE_BUILD_TYPE=Release \
-DLLVM_ENABLE_PROJECTS="libcxx;libcxxabi" \
-DCMAKE_C_COMPILER=clang \
-DCMAKE_CXX_COMPILER=clang++ \
-DLLVM_USE_SANITIZER=MemoryWithOrigins
cmake --build . -- cxx cxxabi
# Back to the MPPP build dir.
cd $MPPP_BUILD_DIR

# Download and compile locally GMP in debug mode.
GMP_VERSION="6.2.0"
wget https://gmplib.org/download/gmp/gmp-${GMP_VERSION}.tar.bz2 -O gmp.tar.bz2
tar xjvf gmp.tar.bz2
cd gmp-${GMP_VERSION}
CC=clang CXX=clang++ ./configure --enable-shared --disable-static --enable-assert --enable-alloca=debug --disable-assembly CFLAGS="-g -fsanitize=memory" --prefix=/home/circleci/.local
make -j2
make install

# Compile mppp and run the tests.
cd ..
MPPP_MSAN_FLAGS="-fsanitize=memory -stdlib=libc++ -nostdinc++ -isystem ${LLVM_BUILD_DIR}/include/c++/v1 -L${LLVM_BUILD_DIR}/lib -Wl,-rpath,${LLVM_BUILD_DIR}/lib -Wno-unused-command-line-argument"
CC=clang CXX=clang++ cmake ../ -DCMAKE_BUILD_TYPE=Debug -DMPPP_BUILD_TESTS=yes -DCMAKE_CXX_FLAGS="${MPPP_MSAN_FLAGS}" -DCMAKE_C_FLAGS="${MPPP_MSAN_FLAGS}" -DCMAKE_PREFIX_PATH=/home/circleci/.local -DCMAKE_CXX_STANDARD=17 -DMPPP_TEST_NSPLIT=${TEST_NSPLIT} -DMPPP_TEST_SPLIT_NUM=${SPLIT_TEST_NUM}
make -j2 VERBOSE=1
ctest -j4 -V

set +e
set +x

0 comments on commit da5bd09

Please sign in to comment.