Clang's "unsigned integer overflow" sanitizer can't tell the difference between expected unsigned wraparound and a bug, and its developers tell users to report bugs against libstdc++.
This disables the sanitizer where we are intentionally relying on wraparound working as defined by the standard. libstdc++-v3/ChangeLog: PR libstdc++/91547 PR libstdc++/97844 * include/bits/c++config (_GLIBCXX_NO_UNSIGNED_OVERFLOW): Define new macro for Clang's no_sanitize("unsigned-integer-overflow") attribute. * include/bits/basic_string.h (basic_string::_S_compare): Add _GLIBCXX_NO_UNSIGNED_OVERFLOW. * include/bits/basic_string.tcc (basic_string::find_last_of) (basic_string::find_last_not_of): Likewise. * include/bits/string_view.tcc (basic_string_view::find_last_not_of): Likewise. * include/std/string_view (basic_string_view::_S_compare): Likewise. Should we make this change? It won't stop bogus bug reports unless we also do it on the branches, or wait until nobody is using older libstdc++ headers with recent Clang releases. But it might help eventually.
commit 3bceeb9366ea416ca3dbe0cd965151a7bdc7cfcf Author: Jonathan Wakely <jwak...@redhat.com> Date: Mon Nov 16 13:09:37 2020 libstdc++ Disable bogus -fsanitize=integer errors from Clang Clang's "unsigned integer overflow" sanitizer can't tell the difference between expected unsigned wraparound and a bug, and its developers tell users to report bugs against libstdc++. This disables the sanitizer where we are intentionally relying on wraparound working as defined by the standard. libstdc++-v3/ChangeLog: PR libstdc++/91547 PR libstdc++/97844 * include/bits/c++config (_GLIBCXX_NO_UNSIGNED_OVERFLOW): Define new macro for Clang's no_sanitize("unsigned-integer-overflow") attribute. * include/bits/basic_string.h (basic_string::_S_compare): Add _GLIBCXX_NO_UNSIGNED_OVERFLOW. * include/bits/basic_string.tcc (basic_string::find_last_of) (basic_string::find_last_not_of): Likewise. * include/bits/string_view.tcc (basic_string_view::find_last_not_of): Likewise. * include/std/string_view (basic_string_view::_S_compare): Likewise. diff --git a/libstdc++-v3/include/bits/basic_string.h b/libstdc++-v3/include/bits/basic_string.h index 372302ba6a18..1c805e5ad8ae 100644 --- a/libstdc++-v3/include/bits/basic_string.h +++ b/libstdc++-v3/include/bits/basic_string.h @@ -397,6 +397,7 @@ _GLIBCXX_BEGIN_NAMESPACE_CXX11 _GLIBCXX_NOEXCEPT { _S_copy(__p, __k1, __k2 - __k1); } + _GLIBCXX_NO_UNSIGNED_OVERFLOW static int _S_compare(size_type __n1, size_type __n2) _GLIBCXX_NOEXCEPT { @@ -3482,6 +3483,7 @@ _GLIBCXX_END_NAMESPACE_CXX11 _GLIBCXX_NOEXCEPT { _M_copy(__p, __k1, __k2 - __k1); } + _GLIBCXX_NO_UNSIGNED_OVERFLOW static int _S_compare(size_type __n1, size_type __n2) _GLIBCXX_NOEXCEPT { diff --git a/libstdc++-v3/include/bits/basic_string.tcc b/libstdc++-v3/include/bits/basic_string.tcc index 6c7896651609..d88b9692f9a0 100644 --- a/libstdc++-v3/include/bits/basic_string.tcc +++ b/libstdc++-v3/include/bits/basic_string.tcc @@ -1307,6 +1307,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } template<typename _CharT, typename _Traits, typename _Alloc> + _GLIBCXX_NO_UNSIGNED_OVERFLOW typename basic_string<_CharT, _Traits, _Alloc>::size_type basic_string<_CharT, _Traits, _Alloc>:: find_last_of(const _CharT* __s, size_type __pos, size_type __n) const @@ -1353,6 +1354,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } template<typename _CharT, typename _Traits, typename _Alloc> + _GLIBCXX_NO_UNSIGNED_OVERFLOW typename basic_string<_CharT, _Traits, _Alloc>::size_type basic_string<_CharT, _Traits, _Alloc>:: find_last_not_of(const _CharT* __s, size_type __pos, size_type __n) const @@ -1375,6 +1377,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } template<typename _CharT, typename _Traits, typename _Alloc> + _GLIBCXX_NO_UNSIGNED_OVERFLOW typename basic_string<_CharT, _Traits, _Alloc>::size_type basic_string<_CharT, _Traits, _Alloc>:: find_last_not_of(_CharT __c, size_type __pos) const _GLIBCXX_NOEXCEPT diff --git a/libstdc++-v3/include/bits/c++config b/libstdc++-v3/include/bits/c++config index 2e6c880ad95a..95fb934564e3 100644 --- a/libstdc++-v3/include/bits/c++config +++ b/libstdc++-v3/include/bits/c++config @@ -702,6 +702,13 @@ namespace std { __glibcxx_assert_2(_Condition); } \ } while (false) +#if __has_attribute(__no_sanitize__) && defined __clang__ +// Suppress UBsan errors about unsigned wraparound. +# define _GLIBCXX_NO_UNSIGNED_OVERFLOW \ + __attribute__((__no_sanitize__("unsigned-integer-overflow"))) +#else +# define _GLIBCXX_NO_UNSIGNED_OVERFLOW +#endif // PSTL configuration diff --git a/libstdc++-v3/include/bits/string_view.tcc b/libstdc++-v3/include/bits/string_view.tcc index 88d9371f1906..30f35e446a07 100644 --- a/libstdc++-v3/include/bits/string_view.tcc +++ b/libstdc++-v3/include/bits/string_view.tcc @@ -180,6 +180,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } template<typename _CharT, typename _Traits> + _GLIBCXX_NO_UNSIGNED_OVERFLOW constexpr typename basic_string_view<_CharT, _Traits>::size_type basic_string_view<_CharT, _Traits>:: find_last_not_of(const _CharT* __str, size_type __pos, @@ -202,6 +203,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION } template<typename _CharT, typename _Traits> + _GLIBCXX_NO_UNSIGNED_OVERFLOW constexpr typename basic_string_view<_CharT, _Traits>::size_type basic_string_view<_CharT, _Traits>:: find_last_not_of(_CharT __c, size_type __pos) const noexcept diff --git a/libstdc++-v3/include/std/string_view b/libstdc++-v3/include/std/string_view index 656d06bf90e9..5c939a388a7f 100644 --- a/libstdc++-v3/include/std/string_view +++ b/libstdc++-v3/include/std/string_view @@ -456,6 +456,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION private: + _GLIBCXX_NO_UNSIGNED_OVERFLOW static constexpr int _S_compare(size_type __n1, size_type __n2) noexcept {