From 3433c34b43969f2d3fc7309d895ef66019e3cfc1 Mon Sep 17 00:00:00 2001 From: Antony Polukhin Date: Thu, 15 Feb 2024 09:24:44 +0300 Subject: [PATCH] Suppress the unsigned-integer-overflow sanitizer warnings and do not recover from the integer sanitizer errors (fixes #45) (#73) --- .github/workflows/ci.yml | 2 +- .../lexical_cast/detail/converter_lexical_streams.hpp | 6 ++++++ include/boost/lexical_cast/detail/converter_numeric.hpp | 9 +++++++-- .../lexical_cast/detail/lcast_unsigned_converters.hpp | 6 ++++++ test/integral_types_test.cpp | 8 ++++---- 5 files changed, 24 insertions(+), 7 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 1da6865..04c9166 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -31,7 +31,7 @@ jobs: compiler: clang++-10 cxxstd: "03,11,14,17,2a" os: ubuntu-20.04 - cxxflags: "cxxflags=-fsanitize=address,undefined,integer -fno-sanitize-recover=undefined" + cxxflags: "cxxflags=-fsanitize=address,undefined,integer -fno-sanitize-recover=undefined,integer" linkflags: "linkflags=-fsanitize=address,undefined,integer" - toolset: clang compiler: clang++-14 diff --git a/include/boost/lexical_cast/detail/converter_lexical_streams.hpp b/include/boost/lexical_cast/detail/converter_lexical_streams.hpp index 1582cb3..8dfa968 100644 --- a/include/boost/lexical_cast/detail/converter_lexical_streams.hpp +++ b/include/boost/lexical_cast/detail/converter_lexical_streams.hpp @@ -490,6 +490,9 @@ namespace boost { namespace detail { namespace lcast { private: template +#if defined(__clang__) && (__clang_major__ > 3 || __clang_minor__ > 6) + __attribute__((no_sanitize("unsigned-integer-overflow"))) +#endif bool shr_unsigned(Type& output) { if (start == finish) return false; CharT const minus = lcast_char_constants::minus; @@ -511,6 +514,9 @@ namespace boost { namespace detail { namespace lcast { } template +#if defined(__clang__) && (__clang_major__ > 3 || __clang_minor__ > 6) + __attribute__((no_sanitize("unsigned-integer-overflow"))) +#endif bool shr_signed(Type& output) { if (start == finish) return false; CharT const minus = lcast_char_constants::minus; diff --git a/include/boost/lexical_cast/detail/converter_numeric.hpp b/include/boost/lexical_cast/detail/converter_numeric.hpp index 5357058..167473b 100644 --- a/include/boost/lexical_cast/detail/converter_numeric.hpp +++ b/include/boost/lexical_cast/detail/converter_numeric.hpp @@ -120,6 +120,9 @@ struct lexical_cast_dynamic_num_not_ignoring_minus struct lexical_cast_dynamic_num_ignoring_minus { template +#if defined(__clang__) && (__clang_major__ > 3 || __clang_minor__ > 6) + __attribute__((no_sanitize("unsigned-integer-overflow"))) +#endif static inline bool try_convert(Source arg, Target& result) noexcept { typedef typename boost::conditional< boost::is_float::value, @@ -129,8 +132,10 @@ struct lexical_cast_dynamic_num_ignoring_minus typedef typename usource_lazy_t::type usource_t; if (arg < 0) { - const bool res = boost::detail::noexcept_numeric_convert(0u - arg, result); - result = static_cast(0u) - static_cast(result); + const bool res = boost::detail::noexcept_numeric_convert( + static_cast(0u - static_cast(arg)), result + ); + result = static_cast(0u - result); return res; } else { return boost::detail::noexcept_numeric_convert(arg, result); diff --git a/include/boost/lexical_cast/detail/lcast_unsigned_converters.hpp b/include/boost/lexical_cast/detail/lcast_unsigned_converters.hpp index b7ab305..21656e8 100644 --- a/include/boost/lexical_cast/detail/lcast_unsigned_converters.hpp +++ b/include/boost/lexical_cast/detail/lcast_unsigned_converters.hpp @@ -56,6 +56,9 @@ namespace boost namespace detail // lcast_to_unsigned { template +#if defined(__clang__) && (__clang_major__ > 3 || __clang_minor__ > 6) + __attribute__((no_sanitize("unsigned-integer-overflow"))) +#endif inline typename boost::make_unsigned::type lcast_to_unsigned(const T value) noexcept { typedef typename boost::make_unsigned::type result_type; @@ -251,6 +254,9 @@ namespace boost private: // Iteration that does not care about grouping/separators and assumes that all // input characters are digits +#if defined(__clang__) && (__clang_major__ > 3 || __clang_minor__ > 6) + __attribute__((no_sanitize("unsigned-integer-overflow"))) +#endif inline bool main_convert_iteration() noexcept { CharT const czero = lcast_char_constants::zero; T const maxv = (std::numeric_limits::max)(); diff --git a/test/integral_types_test.cpp b/test/integral_types_test.cpp index f85bc9f..8ecb037 100644 --- a/test/integral_types_test.cpp +++ b/test/integral_types_test.cpp @@ -171,9 +171,9 @@ void test_conversion_from_integral_to_string(CharT) T const max_val = (limits::max)(); T const half_max_val = max_val / 2; T const cnt = lcast_integral_test_counter; // to suppress warnings - unsigned int const counter = cnt < half_max_val ? cnt : half_max_val; + T const counter = cnt < half_max_val ? cnt : half_max_val; - unsigned int i; + T i = 0; // Test values around min: t = min_val; @@ -267,10 +267,10 @@ void test_conversion_from_string_to_integral(CharT) { T const half_max_val = max_val / 2; T const cnt = lcast_integral_test_counter; // to suppress warnings - unsigned int const counter = cnt < half_max_val ? cnt : half_max_val; + T const counter = cnt < half_max_val ? cnt : half_max_val; T t; - unsigned int i; + T i; // Test values around min: t = min_val;