diff --git a/libcxx/docs/DesignDocs/UnspecifiedBehaviorRandomization.rst b/libcxx/docs/DesignDocs/UnspecifiedBehaviorRandomization.rst --- a/libcxx/docs/DesignDocs/UnspecifiedBehaviorRandomization.rst +++ b/libcxx/docs/DesignDocs/UnspecifiedBehaviorRandomization.rst @@ -35,8 +35,9 @@ Design ====== -* Introduce new macro ``_LIBCPP_DEBUG_RANDOMIZE_UNSPECIFIED_STABILITY`` which should - be a part of the libcxx config. +* Introduce new macro + ``_LIBCPP_ASSERTIONS_ENABLE_FEATURE_RANDOMIZE_UNSPECIFIED_BEHAVIOR`` which + should be a part of the libcxx config. * This macro randomizes the unspecified behavior of algorithms and containers. For example, for sorting algorithm the input range is shuffled and then sorted. @@ -50,7 +51,7 @@ runs, for example, for tests become flaky and eventually be seen as broken. For platforms which do not support ASLR, the seed is fixed during build. * The users can fix the seed of the random number generator by providing - ``_LIBCPP_RANDOMIZE_UNSPECIFIED_STABILITY_SEED=seed`` definition. + ``_LIBCPP_ASSERTIONS_ENABLE_FEATURE_RANDOMIZE_UNSPECIFIED_BEHAVIOR_SEED=seed`` definition. This comes with some side effects if any of the flags is on: diff --git a/libcxx/include/CMakeLists.txt b/libcxx/include/CMakeLists.txt --- a/libcxx/include/CMakeLists.txt +++ b/libcxx/include/CMakeLists.txt @@ -417,6 +417,7 @@ __fwd/string_view.h __fwd/subrange.h __fwd/tuple.h + __hardening __hash_table __ios/fpos.h __iterator/access.h diff --git a/libcxx/include/__algorithm/shuffle.h b/libcxx/include/__algorithm/shuffle.h --- a/libcxx/include/__algorithm/shuffle.h +++ b/libcxx/include/__algorithm/shuffle.h @@ -54,8 +54,8 @@ uint_fast64_t __state_; uint_fast64_t __inc_; _LIBCPP_HIDE_FROM_ABI static uint_fast64_t __seed() { -#ifdef _LIBCPP_DEBUG_RANDOMIZE_UNSPECIFIED_STABILITY_SEED - return _LIBCPP_DEBUG_RANDOMIZE_UNSPECIFIED_STABILITY_SEED; +#ifdef _LIBCPP_ASSERTIONS_ENABLE_FEATURE_RANDOMIZE_UNSPECIFIED_BEHAVIOR_SEED + return _LIBCPP_ASSERTIONS_ENABLE_FEATURE_RANDOMIZE_UNSPECIFIED_BEHAVIOR_SEED; #else static char __x; return reinterpret_cast(&__x); diff --git a/libcxx/include/__config b/libcxx/include/__config --- a/libcxx/include/__config +++ b/libcxx/include/__config @@ -84,6 +84,8 @@ // ... add new file formats here ... # endif +// ABI { + # if _LIBCPP_ABI_VERSION >= 2 // Change short string representation so that string data starts at offset 0, // improving its alignment in some cases. @@ -189,6 +191,189 @@ # define _LIBCPP_ABI_BAD_FUNCTION_CALL_KEY_FUNCTION # endif +// Changes the iterator type of select containers (see below) to a bounded iterator that: +// - keeps track of which container it refers to; +// - keeps track of whether it's valid or not and asserts validity on every dereference; +// - allows enabling the check that a given range is valid (sentinel is reachable from the begin iterator, etc.) in +// constant time. +// +// ABI impact: increases the size and changes the layout of containers (to store additional information that is used by +// bounded iterators), changes the return type of container functions that return iterators. +// +// Supported containers: +// - `span`; +// - `string_view`; +// - `array`. +// #define _LIBCPP_ABI_BOUNDED_ITERATORS + +// } ABI + +// HARDENING { + +// Enables the hardened mode which consists of all checks intended to be used in production. Hardened mode prioritizes +// security-critical checks that can be done with relatively little overhead in constant time. Mutually exclusive with +// `_LIBCPP_ENABLE_NEW_DEBUG_MODE`. +// +//#define _LIBCPP_ENABLE_HARDENED_MODE 1 + +// Enables the debug mode which contains all the checks from the hardened mode and additionally more expensive checks +// that may affect the complexity of algorithms. The debug mode is intended to be used for testing, not in production. +// Mutually exclusive with `_LIBCPP_ENABLE_HARDENED_MODE`. +// +//#define _LIBCPP_ENABLE_NEW_DEBUG_MODE 1 + +// Available checks: + +// Checks that ranges (whether expressed as an iterator pair, an iterator and a count, or a `std::range`) given as +// input to library functions are valid: +// - both iterators refer to the same container; +// - the sentinel is reachable from the begin iterator; +// - where applicable, the input range and the output range do not overlap. +// +// The level of support depends on whether bounded iterators are enabled in the ABI. If bounded iterators are not +// enabled, the library falls back to more basic checks. +// +// #define _LIBCPP_ASSERTIONS_ENABLE_CHECK_VALID_RANGE 1 + +// Checks any calls into a container that attempt to access a non-existent element. Types like `optional` and `function` +// are considered one-element containers for the purposes of this check. This check only applies to member functions of +// containers, not any access made purely via iterators. +// +// #define _LIBCPP_ASSERTIONS_ENABLE_CHECK_VALID_CONTAINER_ACCESS 1 + +// TODO: +// See docs/DesignDocs/UnspecifiedBehaviorRandomization.rst +// +// #define _LIBCPP_ASSERTIONS_ENABLE_FEATURE_RANDOMIZE_UNSPECIFIED_BEHAVIOR 1 + +// TODO: +// Checks whether the given input satisfies some algorithm-specific criteria (such as being sorted, heapified or +// partitioned). +// +// #define _LIBCPP_ASSERTIONS_ENABLE_CHECK_UNSORTED_ETC_INPUT 1 + +#ifndef _LIBCPP_ENABLE_HARDENED_MODE +# define _LIBCPP_ENABLE_HARDENED_MODE _LIBCPP_ENABLE_HARDENED_MODE_DEFAULT +#endif +#if _LIBCPP_ENABLE_HARDENED_MODE != 0 && _LIBCPP_ENABLE_HARDENED_MODE != 1 +# error "_LIBCPP_ENABLE_HARDENED_MODE must be set to 0 or 1." +#endif + +#ifndef _LIBCPP_ENABLE_NEW_DEBUG_MODE +# define _LIBCPP_ENABLE_NEW_DEBUG_MODE _LIBCPP_ENABLE_NEW_DEBUG_MODE_DEFAULT +#endif +#if _LIBCPP_ENABLE_NEW_DEBUG_MODE != 0 && _LIBCPP_ENABLE_NEW_DEBUG_MODE != 1 +# error "_LIBCPP_ENABLE_NEW_DEBUG_MODE must be set to 0 or 1." +#endif + +#if _LIBCPP_ENABLE_HARDENED_MODE && _LIBCPP_ENABLE_NEW_DEBUG_MODE +# error "Only one of _LIBCPP_ENABLE_HARDENED_MODE and _LIBCPP_ENABLE_NEW_DEBUG_MODE can be defined." +#endif + +// Hardened mode checks. +#if _LIBCPP_ENABLE_HARDENED_MODE + +// Automatically enable assertions in hardened mode (unless the user explicitly turned them off). +# ifndef _LIBCPP_ENABLE_ASSERTIONS +# define _LIBCPP_ENABLE_ASSERTIONS 1 +# endif + +# define _LIBCPP_ASSERTIONS_ENABLE_CHECK_VALID_RANGE 1 +# define _LIBCPP_ASSERTIONS_ENABLE_CHECK_VALID_CONTAINER_ACCESS 1 +# define _LIBCPP_ASSERTIONS_ENABLE_FEATURE_RANDOMIZE_UNSPECIFIED_BEHAVIOR 0 +//# define _LIBCPP_ASSERTIONS_ENABLE_CHECK_UNSORTED_ETC_INPUT 0 +// TODO: more checks to be added here... + +// Debug mode checks. +#elif _LIBCPP_ENABLE_NEW_DEBUG_MODE + +// Automatically enable assertions in debug mode (unless the user explicitly turned them off). +# ifndef _LIBCPP_ENABLE_ASSERTIONS +# define _LIBCPP_ENABLE_ASSERTIONS 1 +# endif + +// Always enable ABI-breaking checks in debug mode since it's not intended to be ABI-stable. +#if !defined(_LIBCPP_ABI_BOUNDED_ITERATORS) +# define _LIBCPP_ABI_BOUNDED_ITERATORS +#endif + +# define _LIBCPP_ASSERTIONS_ENABLE_CHECK_VALID_RANGE 1 +# define _LIBCPP_ASSERTIONS_ENABLE_CHECK_VALID_CONTAINER_ACCESS 1 +# define _LIBCPP_ASSERTIONS_ENABLE_FEATURE_RANDOMIZE_UNSPECIFIED_BEHAVIOR 1 +//# define _LIBCPP_ASSERTIONS_ENABLE_CHECK_UNSORTED_ETC_INPUT 1 +// TODO: more checks to be added here... + +// Disable all checks if neither the hardened mode nor the debug mode is enabled. +#else + +# ifndef _LIBCPP_ASSERTIONS_ENABLE_CHECK_VALID_RANGE +# define _LIBCPP_ASSERTIONS_ENABLE_CHECK_VALID_RANGE 0 +# endif +# ifndef _LIBCPP_ASSERTIONS_ENABLE_CHECK_VALID_CONTAINER_ACCESS +# define _LIBCPP_ASSERTIONS_ENABLE_CHECK_VALID_CONTAINER_ACCESS 0 +# endif +# ifndef _LIBCPP_ASSERTIONS_ENABLE_FEATURE_RANDOMIZE_UNSPECIFIED_BEHAVIOR +# define _LIBCPP_ASSERTIONS_ENABLE_FEATURE_RANDOMIZE_UNSPECIFIED_BEHAVIOR 0 +# endif +//# ifndef _LIBCPP_ASSERTIONS_ENABLE_CHECK_UNSORTED_ETC_INPUT +//# define _LIBCPP_ASSERTIONS_ENABLE_CHECK_UNSORTED_ETC_INPUT 0 +//# endif +// TODO: more checks to be added here... + +#endif + +// The assertions machinery. + +// Emulates overloaded functions for macros by delegating from a macro taking variadic arguments to one of the few other +// macros taking a certain number of arguments. Expects to be called from the variadic macro: +// +// _LIBCPP_OVERLOADED_MACRO(__VA_ARGS_, MACRO_TAKING_3_ARGS, MACRO_TAKING_2_ARGS, MACRO_TAKING_1_ARG) +// +// This will expand to `MACRO_TAKING_3_ARGS` if `__VA_ARGS__` expands to 3 arguments, `MACRO_TAKING_2_ARGS` if +// `__VA_ARGS__` expands to 2 arguments, and so on. This technique can be easily extended to any number of arguments. +#define _LIBCPP_OVERLOADED_MACRO(_ARG1, _ARG2, _ARG3, _SELECTED_OVERLOAD, ...) _SELECTED_OVERLOAD + +// Definitions of different categories of assertions. + +#if _LIBCPP_ASSERTIONS_ENABLE_CHECK_VALID_RANGE + +# define _LIBCPP_ASSERT_CHECK_VALID_RANGE2(range, message) \ + _LIBCPP_ASSERT(::std::__hardening::_CheckValidRange(range), message) +# define _LIBCPP_ASSERT_CHECK_VALID_RANGE3(first, last, message) \ + _LIBCPP_ASSERT(::std::__hardening::_CheckValidRange(first, last), message) +# define _LIBCPP_ASSERT_CHECK_VALID_RANGE(...) _LIBCPP_OVERLOADED_MACRO(__VA_ARGS__, \ + _LIBCPP_ASSERT_CHECK_VALID_RANGE3, _LIBCPP_ASSERT_CHECK_VALID_RANGE2)(__VA_ARGS__); +// TODO: _LIBCPP_ASSERT_CHECK_NONOVERLAPPING_RANGES(range1, range2, message); + +#else + +# define _LIBCPP_ASSERT_CHECK_VALID_RANGE(...) ((void)0) + +#endif // _LIBCPP_ASSERTIONS_ENABLE_CHECK_VALID_RANGE + +#if _LIBCPP_ASSERTIONS_ENABLE_CHECK_VALID_CONTAINER_ACCESS +# define _LIBCPP_ASSERT_CHECK_VALID_CONTAINER_ACCESS(condition, message) \ + _LIBCPP_ASSERT(condition, message); +#else +# define _LIBCPP_ASSERT_CHECK_VALID_CONTAINER_ACCESS(condition, message) ((void)0) +#endif // _LIBCPP_ASSERTIONS_ENABLE_CHECK_VALID_CONTAINER_ACCESS + +// TODO: +// _LIBCPP_ASSERT_CHECK_NONFOREIGN_ITERATOR(container, iter, message); + +// TODO: remove when debug mode is removed. +#ifdef _LIBCPP_DEBUG_RANDOMIZE_UNSPECIFIED_STABILITY +# define _LIBCPP_ASSERTIONS_ENABLE_FEATURE_RANDOMIZE_UNSPECIFIED_BEHAVIOR 1 +# warning "This is deprecated, use _LIBCPP_ASSERTIONS_ENABLE_FEATURE_RANDOMIZE_UNSPECIFIED_BEHAVIOR" +#endif +#ifdef _LIBCPP_DEBUG_RANDOMIZE_UNSPECIFIED_STABILITY_SEED +# define _LIBCPP_ASSERTIONS_ENABLE_FEATURE_RANDOMIZE_UNSPECIFIED_BEHAVIOR_SEED \ + _LIBCPP_DEBUG_RANDOMIZE_UNSPECIFIED_STABILITY_SEED +# warning "This is deprecated, use _LIBCPP_ASSERTIONS_ENABLE_FEATURE_RANDOMIZE_UNSPECIFIED_BEHAVIOR_SEED" +#endif + +// } HARDENING + # define _LIBCPP_TOSTRING2(x) #x # define _LIBCPP_TOSTRING(x) _LIBCPP_TOSTRING2(x) diff --git a/libcxx/include/__config_site.in b/libcxx/include/__config_site.in --- a/libcxx/include/__config_site.in +++ b/libcxx/include/__config_site.in @@ -31,11 +31,16 @@ #cmakedefine _LIBCPP_HAS_NO_WIDE_CHARACTERS #cmakedefine01 _LIBCPP_ENABLE_ASSERTIONS_DEFAULT #cmakedefine _LIBCPP_ENABLE_DEBUG_MODE +#cmakedefine _LIBCPP_ABI_BOUNDED_ITERATORS // PSTL backends #cmakedefine _LIBCPP_PSTL_CPU_BACKEND_SERIAL #cmakedefine _LIBCPP_PSTL_CPU_BACKEND_THREAD +// Hardening. +#cmakedefine01 _LIBCPP_ENABLE_HARDENED_MODE_DEFAULT +#cmakedefine01 _LIBCPP_ENABLE_NEW_DEBUG_MODE_DEFAULT + // __USE_MINGW_ANSI_STDIO gets redefined on MinGW #ifdef __clang__ # pragma clang diagnostic push diff --git a/libcxx/include/__debug b/libcxx/include/__debug --- a/libcxx/include/__debug +++ b/libcxx/include/__debug @@ -23,8 +23,8 @@ # define _LIBCPP_DEBUG_RANDOMIZE_UNSPECIFIED_STABILITY #endif -#if defined(_LIBCPP_ENABLE_DEBUG_MODE) && !defined(_LIBCPP_DEBUG_ITERATOR_BOUNDS_CHECKING) -# define _LIBCPP_DEBUG_ITERATOR_BOUNDS_CHECKING +#if defined(_LIBCPP_ENABLE_DEBUG_MODE) && !defined(_LIBCPP_ABI_BOUNDED_ITERATORS) +# define _LIBCPP_ABI_BOUNDED_ITERATORS #endif #ifdef _LIBCPP_ENABLE_DEBUG_MODE diff --git a/libcxx/include/__debug_utils/randomize_range.h b/libcxx/include/__debug_utils/randomize_range.h --- a/libcxx/include/__debug_utils/randomize_range.h +++ b/libcxx/include/__debug_utils/randomize_range.h @@ -11,7 +11,7 @@ #include <__config> -#ifdef _LIBCPP_DEBUG_RANDOMIZE_UNSPECIFIED_STABILITY +#if _LIBCPP_ASSERTIONS_ENABLE_FEATURE_RANDOMIZE_UNSPECIFIED_BEHAVIOR # include <__algorithm/shuffle.h> # include <__type_traits/is_constant_evaluated.h> #endif @@ -25,7 +25,7 @@ template _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 void __debug_randomize_range(_Iterator __first, _Sentinel __last) { -#ifdef _LIBCPP_DEBUG_RANDOMIZE_UNSPECIFIED_STABILITY +#if _LIBCPP_ASSERTIONS_ENABLE_FEATURE_RANDOMIZE_UNSPECIFIED_BEHAVIOR # ifdef _LIBCPP_CXX03_LANG # error Support for unspecified stability is only for C++11 and higher # endif diff --git a/libcxx/include/__hardening b/libcxx/include/__hardening new file mode 100644 --- /dev/null +++ b/libcxx/include/__hardening @@ -0,0 +1,59 @@ +// -*- C++ -*- +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#ifndef _LIBCPP___HARDENING +#define _LIBCPP___HARDENING + +#include <__config> +#include <__ranges/access.h> +#include <__ranges/concepts.h> +#include <__utility/forward.h> + +#if !defined(_LIBCPP_HAS_NO_PRAGMA_SYSTEM_HEADER) +# pragma GCC system_header +#endif + +_LIBCPP_BEGIN_NAMESPACE_STD + +// TODO: specialization for random access iterators. +template +struct __hardening_traits { + _LIBCPP_HIDE_FROM_ABI + static constexpr bool __refer_to_same_range(const _Iter&, const _Iter&) { + // In the general case we can't check whether two arbitrary iterators refer to the same range. + return true; + } +}; + +namespace __hardening { + +template +_LIBCPP_HIDE_FROM_ABI +constexpr bool _CheckValidRange(_Iter __first, _Iter __last) { + return __hardening_traits<_Iter>::__refer_to_same_range(__first, __last) && __first <= __last; +} + +template +_LIBCPP_HIDE_FROM_ABI +constexpr bool _CheckValidRange(const _Iter&, _SizeT) { + return true; +} + +template +_LIBCPP_HIDE_FROM_ABI +constexpr bool _CheckValidRange(_Range&& __range) { + return __hardening::_CheckValidRange( + ranges::begin(std::forward<_Range>(__range)), ranges::end(std::forward<_Range>(__range))); +} + +} // __hardening + +_LIBCPP_END_NAMESPACE_STD + +#endif // _LIBCPP___HARDENING diff --git a/libcxx/include/__iterator/bounded_iter.h b/libcxx/include/__iterator/bounded_iter.h --- a/libcxx/include/__iterator/bounded_iter.h +++ b/libcxx/include/__iterator/bounded_iter.h @@ -12,6 +12,7 @@ #include <__assert> #include <__config> +#include <__hardening> #include <__iterator/iterator_traits.h> #include <__memory/pointer_traits.h> #include <__type_traits/enable_if.h> @@ -201,6 +202,9 @@ template friend struct pointer_traits; + template + friend struct __hardening_traits; + _Iterator __current_; // current iterator _Iterator __begin_, __end_; // valid range represented as [begin, end) }; @@ -210,6 +214,14 @@ return __bounded_iter<_It>(std::move(__it), std::move(__begin), std::move(__end)); } +template +struct __hardening_traits<__bounded_iter<_It>> { + _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR + static bool __refer_to_same_range(const __bounded_iter<_It>& __iter1, const __bounded_iter<_It>& __iter2) { + return __iter1.__begin_ == __iter2.__begin_ && __iter1.__end_ == __iter2.__end_; + } +}; + #if _LIBCPP_STD_VER <= 17 template struct __libcpp_is_contiguous_iterator<__bounded_iter<_Iterator> > : true_type {}; diff --git a/libcxx/include/span b/libcxx/include/span --- a/libcxx/include/span +++ b/libcxx/include/span @@ -130,6 +130,7 @@ #include <__assert> // all public C++ headers provide the assertion handler #include <__config> #include <__debug> +#include <__hardening> #include <__fwd/span.h> #include <__iterator/bounded_iter.h> #include <__iterator/concepts.h> @@ -214,7 +215,7 @@ using const_pointer = const _Tp *; using reference = _Tp &; using const_reference = const _Tp &; -#ifdef _LIBCPP_DEBUG_ITERATOR_BOUNDS_CHECKING +#if defined(_LIBCPP_ABI_BOUNDED_ITERATORS) using iterator = __bounded_iter; #else using iterator = __wrap_iter; @@ -235,7 +236,9 @@ constexpr explicit span(_It __first, size_type __count) : __data_{_VSTD::to_address(__first)} { (void)__count; - _LIBCPP_ASSERT(_Extent == __count, "size mismatch in span's constructor (iterator, len)"); + _LIBCPP_ASSERT_CHECK_VALID_CONTAINER_ACCESS(_Extent == __count, + "size mismatch in span's constructor (iterator, len)"); + _LIBCPP_ASSERT_CHECK_VALID_RANGE(__first, __count, "invalid range passed to span's constructor (iterator, len)"); } template <__span_compatible_iterator _It, __span_compatible_sentinel_for<_It> _End> @@ -243,10 +246,12 @@ constexpr explicit span(_It __first, _End __last) : __data_{_VSTD::to_address(__first)} { // [span.cons]/10 // Throws: When and what last - first throws. - [[maybe_unused]] auto __dist = __last - __first; - _LIBCPP_ASSERT(__dist >= 0, "invalid range in span's constructor (iterator, sentinel)"); - _LIBCPP_ASSERT( - __dist == _Extent, "invalid range in span's constructor (iterator, sentinel): last - first != extent"); + _LIBCPP_ASSERT_CHECK_VALID_CONTAINER_ACCESS( + _Extent == __last - __first, + "invalid range in span's constructor (iterator, sentinel): last - first != extent"); + _LIBCPP_ASSERT_CHECK_VALID_RANGE( + __first, __last, + "invalid range in span's constructor (iterator, sentinel): last - first != extent"); } _LIBCPP_INLINE_VISIBILITY constexpr span(type_identity_t (&__arr)[_Extent]) noexcept : __data_{__arr} {} @@ -263,7 +268,9 @@ template <__span_compatible_range _Range> _LIBCPP_INLINE_VISIBILITY constexpr explicit span(_Range&& __r) : __data_{ranges::data(__r)} { - _LIBCPP_ASSERT(ranges::size(__r) == _Extent, "size mismatch in span's constructor (range)"); + _LIBCPP_ASSERT_CHECK_VALID_RANGE(std::forward<_Range>(__r), "invalid range passed to span's constructor (range)"); + _LIBCPP_ASSERT_CHECK_VALID_CONTAINER_ACCESS(ranges::size(__r) == _Extent, + "size mismatch in span's constructor (range)"); } template <__span_array_convertible _OtherElementType> @@ -274,7 +281,10 @@ template <__span_array_convertible _OtherElementType> _LIBCPP_INLINE_VISIBILITY constexpr explicit span(const span<_OtherElementType, dynamic_extent>& __other) noexcept - : __data_{__other.data()} { _LIBCPP_ASSERT(_Extent == __other.size(), "size mismatch in span's constructor (other span)"); } + : __data_{__other.data()} { + _LIBCPP_ASSERT_CHECK_VALID_CONTAINER_ACCESS(_Extent == __other.size(), + "size mismatch in span's constructor (other span)"); + } // ~span() noexcept = default; @@ -298,14 +308,15 @@ _LIBCPP_INLINE_VISIBILITY constexpr span first(size_type __count) const noexcept { - _LIBCPP_ASSERT(__count <= size(), "span::first(count): count out of range"); + _LIBCPP_ASSERT_CHECK_VALID_CONTAINER_ACCESS(__count <= size(), "span::first(count): count out of range"); + return {data(), __count}; } _LIBCPP_INLINE_VISIBILITY constexpr span last(size_type __count) const noexcept { - _LIBCPP_ASSERT(__count <= size(), "span::last(count): count out of range"); + _LIBCPP_ASSERT_CHECK_VALID_CONTAINER_ACCESS(__count <= size(), "span::last(count): count out of range"); return {data() + size() - __count, __count}; } @@ -326,10 +337,12 @@ constexpr span subspan(size_type __offset, size_type __count = dynamic_extent) const noexcept { - _LIBCPP_ASSERT(__offset <= size(), "span::subspan(offset, count): offset out of range"); + _LIBCPP_ASSERT_CHECK_VALID_CONTAINER_ACCESS(__offset <= size(), + "span::subspan(offset, count): offset out of range"); if (__count == dynamic_extent) return {data() + __offset, size() - __offset}; - _LIBCPP_ASSERT(__count <= size() - __offset, "span::subspan(offset, count): offset + count out of range"); + _LIBCPP_ASSERT_CHECK_VALID_CONTAINER_ACCESS(__count <= size() - __offset, + "span::subspan(offset, count): offset + count out of range"); return {data() + __offset, __count}; } @@ -339,19 +352,20 @@ _LIBCPP_INLINE_VISIBILITY constexpr reference operator[](size_type __idx) const noexcept { - _LIBCPP_ASSERT(__idx < size(), "span::operator[](index): index out of range"); + _LIBCPP_ASSERT_CHECK_VALID_CONTAINER_ACCESS(__idx < size(), + "span::operator[](index): index out of range"); return __data_[__idx]; } _LIBCPP_INLINE_VISIBILITY constexpr reference front() const noexcept { - _LIBCPP_ASSERT(!empty(), "span::front() on empty span"); + _LIBCPP_ASSERT_CHECK_VALID_CONTAINER_ACCESS(!empty(), "span::front() on empty span"); return __data_[0]; } _LIBCPP_INLINE_VISIBILITY constexpr reference back() const noexcept { - _LIBCPP_ASSERT(!empty(), "span::back() on empty span"); + _LIBCPP_ASSERT_CHECK_VALID_CONTAINER_ACCESS(!empty(), "span::back() on empty span"); return __data_[size()-1]; } @@ -359,14 +373,14 @@ // [span.iter], span iterator support _LIBCPP_INLINE_VISIBILITY constexpr iterator begin() const noexcept { -#ifdef _LIBCPP_DEBUG_ITERATOR_BOUNDS_CHECKING +#if defined(_LIBCPP_ABI_BOUNDED_ITERATORS) return std::__make_bounded_iter(data(), data(), data() + size()); #else return iterator(this, data()); #endif } _LIBCPP_INLINE_VISIBILITY constexpr iterator end() const noexcept { -#ifdef _LIBCPP_DEBUG_ITERATOR_BOUNDS_CHECKING +#if defined(_LIBCPP_ABI_BOUNDED_ITERATORS) return std::__make_bounded_iter(data() + size(), data(), data() + size()); #else return iterator(this, data() + size()); @@ -398,7 +412,7 @@ using const_pointer = const _Tp *; using reference = _Tp &; using const_reference = const _Tp &; -#ifdef _LIBCPP_DEBUG_ITERATOR_BOUNDS_CHECKING +#if defined(_LIBCPP_ABI_BOUNDED_ITERATORS) using iterator = __bounded_iter; #else using iterator = __wrap_iter; @@ -416,12 +430,14 @@ template <__span_compatible_iterator _It> _LIBCPP_INLINE_VISIBILITY constexpr span(_It __first, size_type __count) - : __data_{_VSTD::to_address(__first)}, __size_{__count} {} + : __data_{_VSTD::to_address(__first)}, __size_{__count} { + _LIBCPP_ASSERT_CHECK_VALID_RANGE(__first, __count, "invalid range in span's constructor (iterator, count)"); + } template <__span_compatible_iterator _It, __span_compatible_sentinel_for<_It> _End> _LIBCPP_INLINE_VISIBILITY constexpr span(_It __first, _End __last) : __data_(_VSTD::to_address(__first)), __size_(__last - __first) { - _LIBCPP_ASSERT(__last - __first >= 0, "invalid range in span's constructor (iterator, sentinel)"); + _LIBCPP_ASSERT_CHECK_VALID_RANGE(__first, __last, "invalid range in span's constructor (iterator, sentinel)"); } template @@ -439,7 +455,9 @@ template <__span_compatible_range _Range> _LIBCPP_INLINE_VISIBILITY - constexpr span(_Range&& __r) : __data_(ranges::data(__r)), __size_{ranges::size(__r)} {} + constexpr span(_Range&& __r) : __data_(ranges::data(__r)), __size_{ranges::size(__r)} { + _LIBCPP_ASSERT_CHECK_VALID_RANGE(std::forward<_Range>(__r), "invalid range in span's constructor (range)"); + } template <__span_array_convertible _OtherElementType, size_t _OtherExtent> _LIBCPP_INLINE_VISIBILITY @@ -452,7 +470,7 @@ _LIBCPP_INLINE_VISIBILITY constexpr span first() const noexcept { - _LIBCPP_ASSERT(_Count <= size(), "span::first(): Count out of range"); + _LIBCPP_ASSERT_CHECK_VALID_CONTAINER_ACCESS(_Count <= size(), "span::first(): Count out of range"); return span{data(), _Count}; } @@ -460,21 +478,21 @@ _LIBCPP_INLINE_VISIBILITY constexpr span last() const noexcept { - _LIBCPP_ASSERT(_Count <= size(), "span::last(): Count out of range"); + _LIBCPP_ASSERT_CHECK_VALID_CONTAINER_ACCESS(_Count <= size(), "span::last(): Count out of range"); return span{data() + size() - _Count, _Count}; } _LIBCPP_INLINE_VISIBILITY constexpr span first(size_type __count) const noexcept { - _LIBCPP_ASSERT(__count <= size(), "span::first(count): count out of range"); + _LIBCPP_ASSERT_CHECK_VALID_CONTAINER_ACCESS(__count <= size(), "span::first(count): count out of range"); return {data(), __count}; } _LIBCPP_INLINE_VISIBILITY constexpr span last (size_type __count) const noexcept { - _LIBCPP_ASSERT(__count <= size(), "span::last(count): count out of range"); + _LIBCPP_ASSERT_CHECK_VALID_CONTAINER_ACCESS(__count <= size(), "span::last(count): count out of range"); return {data() + size() - __count, __count}; } @@ -482,8 +500,11 @@ _LIBCPP_INLINE_VISIBILITY constexpr span subspan() const noexcept { - _LIBCPP_ASSERT(_Offset <= size(), "span::subspan(): Offset out of range"); - _LIBCPP_ASSERT(_Count == dynamic_extent || _Count <= size() - _Offset, "span::subspan(): Offset + Count out of range"); + _LIBCPP_ASSERT_CHECK_VALID_CONTAINER_ACCESS(_Offset <= size(), + "span::subspan(): Offset out of range"); + _LIBCPP_ASSERT_CHECK_VALID_CONTAINER_ACCESS(_Count == dynamic_extent || _Count <= size() - _Offset, + "span::subspan(): Offset + Count out of range"); + return span{data() + _Offset, _Count == dynamic_extent ? size() - _Offset : _Count}; } @@ -491,10 +512,12 @@ _LIBCPP_INLINE_VISIBILITY subspan(size_type __offset, size_type __count = dynamic_extent) const noexcept { - _LIBCPP_ASSERT(__offset <= size(), "span::subspan(offset, count): offset out of range"); + _LIBCPP_ASSERT_CHECK_VALID_CONTAINER_ACCESS(__offset <= size(), + "span::subspan(offset, count): offset out of range"); if (__count == dynamic_extent) return {data() + __offset, size() - __offset}; - _LIBCPP_ASSERT(__count <= size() - __offset, "span::subspan(offset, count): offset + count out of range"); + _LIBCPP_ASSERT_CHECK_VALID_CONTAINER_ACCESS(__count <= size() - __offset, + "span::subspan(offset, count): offset + count out of range"); return {data() + __offset, __count}; } @@ -504,19 +527,19 @@ _LIBCPP_INLINE_VISIBILITY constexpr reference operator[](size_type __idx) const noexcept { - _LIBCPP_ASSERT(__idx < size(), "span::operator[](index): index out of range"); + _LIBCPP_ASSERT_CHECK_VALID_CONTAINER_ACCESS(__idx < size(), "span::operator[](index): index out of range"); return __data_[__idx]; } _LIBCPP_INLINE_VISIBILITY constexpr reference front() const noexcept { - _LIBCPP_ASSERT(!empty(), "span::front() on empty span"); + _LIBCPP_ASSERT_CHECK_VALID_CONTAINER_ACCESS(!empty(), "span::front() on empty span"); return __data_[0]; } _LIBCPP_INLINE_VISIBILITY constexpr reference back() const noexcept { - _LIBCPP_ASSERT(!empty(), "span::back() on empty span"); + _LIBCPP_ASSERT_CHECK_VALID_CONTAINER_ACCESS(!empty(), "span::back() on empty span"); return __data_[size()-1]; } @@ -525,14 +548,14 @@ // [span.iter], span iterator support _LIBCPP_INLINE_VISIBILITY constexpr iterator begin() const noexcept { -#ifdef _LIBCPP_DEBUG_ITERATOR_BOUNDS_CHECKING +#if defined(_LIBCPP_ABI_BOUNDED_ITERATORS) return std::__make_bounded_iter(data(), data(), data() + size()); #else return iterator(this, data()); #endif } _LIBCPP_INLINE_VISIBILITY constexpr iterator end() const noexcept { -#ifdef _LIBCPP_DEBUG_ITERATOR_BOUNDS_CHECKING +#if defined(_LIBCPP_ABI_BOUNDED_ITERATORS) return std::__make_bounded_iter(data() + size(), data(), data() + size()); #else return iterator(this, data() + size()); diff --git a/libcxx/include/string_view b/libcxx/include/string_view --- a/libcxx/include/string_view +++ b/libcxx/include/string_view @@ -274,7 +274,7 @@ using const_pointer = const _CharT*; using reference = _CharT&; using const_reference = const _CharT&; -#ifdef _LIBCPP_DEBUG_ITERATOR_BOUNDS_CHECKING +#ifdef _LIBCPP_ABI_BOUNDED_ITERATORS using const_iterator = __bounded_iter; #else using const_iterator = const_pointer; // See [string.view.iterators] @@ -355,7 +355,7 @@ _LIBCPP_CONSTEXPR _LIBCPP_INLINE_VISIBILITY const_iterator cbegin() const _NOEXCEPT { -#ifdef _LIBCPP_DEBUG_ITERATOR_BOUNDS_CHECKING +#ifdef _LIBCPP_ABI_BOUNDED_ITERATORS return std::__make_bounded_iter(data(), data(), data() + size()); #else return __data_; @@ -364,7 +364,7 @@ _LIBCPP_CONSTEXPR _LIBCPP_INLINE_VISIBILITY const_iterator cend() const _NOEXCEPT { -#ifdef _LIBCPP_DEBUG_ITERATOR_BOUNDS_CHECKING +#ifdef _LIBCPP_ABI_BOUNDED_ITERATORS return std::__make_bounded_iter(data() + size(), data(), data() + size()); #else return __data_ + __size_; diff --git a/libcxx/include/vector b/libcxx/include/vector --- a/libcxx/include/vector +++ b/libcxx/include/vector @@ -468,6 +468,8 @@ template <_ContainerCompatibleRange<_Tp> _Range> _LIBCPP_HIDE_FROM_ABI constexpr vector(from_range_t, _Range&& __range, const allocator_type& __alloc = allocator_type()) : __end_cap_(nullptr, __alloc) { + //_LIBCPP_ASSERT_CHECK_VALID_RANGE(std::forward<_Range>(__range), "vector::vector(from_range_t)"); + if constexpr (ranges::forward_range<_Range> || ranges::sized_range<_Range>) { auto __n = static_cast(ranges::distance(__range)); __init_with_size(ranges::begin(__range), ranges::end(__range), __n); @@ -547,6 +549,9 @@ template <_ContainerCompatibleRange<_Tp> _Range> _LIBCPP_HIDE_FROM_ABI constexpr void assign_range(_Range&& __range) { + //_LIBCPP_ASSERT_CHECK_VALID_RANGE(std::forward<_Range>(__range), "vector::assign_range"); + //_LIBCPP_ASSERT_CHECK_OVERLAPPING_RANGES(*this, std::forward<_Range>(__range), "vector::assign_range"); + if constexpr (ranges::forward_range<_Range> || ranges::sized_range<_Range>) { auto __n = static_cast(ranges::distance(__range)); __assign_with_size(ranges::begin(__range), ranges::end(__range), __n); @@ -621,21 +626,25 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference front() _NOEXCEPT { _LIBCPP_ASSERT(!empty(), "front() called on an empty vector"); + //_LIBCPP_ASSERT_CHECK_VALID_CONTAINER_ACCESS(!empty(), "vector::front()"); return *this->__begin_; } _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference front() const _NOEXCEPT { _LIBCPP_ASSERT(!empty(), "front() called on an empty vector"); + //_LIBCPP_ASSERT_CHECK_VALID_CONTAINER_ACCESS(!empty(), "vector::front()"); return *this->__begin_; } _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI reference back() _NOEXCEPT { _LIBCPP_ASSERT(!empty(), "back() called on an empty vector"); + //_LIBCPP_ASSERT_CHECK_VALID_CONTAINER_ACCESS(!empty(), "vector::back()"); return *(this->__end_ - 1); } _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_HIDE_FROM_ABI const_reference back() const _NOEXCEPT { _LIBCPP_ASSERT(!empty(), "back() called on an empty vector"); + //_LIBCPP_ASSERT_CHECK_VALID_CONTAINER_ACCESS(!empty(), "vector::back()"); return *(this->__end_ - 1); } @@ -663,6 +672,8 @@ template <_ContainerCompatibleRange<_Tp> _Range> _LIBCPP_HIDE_FROM_ABI constexpr void append_range(_Range&& __range) { + //_LIBCPP_ASSERT_CHECK_VALID_RANGE(std::forward<_Range>(__range), "vector::append_range"); + //_LIBCPP_ASSERT_CHECK_OVERLAPPING_RANGES(*this, std::forward<_Range>(__range), "vector::append_range"); insert_range(end(), std::forward<_Range>(__range)); } #endif @@ -690,6 +701,10 @@ template <_ContainerCompatibleRange<_Tp> _Range> _LIBCPP_HIDE_FROM_ABI constexpr iterator insert_range(const_iterator __position, _Range&& __range) { + //_LIBCPP_ASSERT_CHECK_VALID_RANGE(std::forward<_Range>(__range), "vector::insert_range"); + //_LIBCPP_ASSERT_CHECK_OVERLAPPING_RANGES(*this, std::forward<_Range>(__range), "vector::insert_range"); + //_LIBCPP_ASSERT_CHECK_FOREIGN_ITERATOR(*this, __position, "vector::insert_range"); + if constexpr (ranges::forward_range<_Range> || ranges::sized_range<_Range>) { auto __n = static_cast(ranges::distance(__range)); return __insert_with_size(__position, ranges::begin(__range), ranges::end(__range), __n); @@ -1253,6 +1268,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 vector<_Tp, _Allocator>::vector(_InputIterator __first, _InputIterator __last) { + //_LIBCPP_ASSERT_CHECK_VALID_RANGE(__first, __last, "vector::vector(Iter, Iter)"); __init_with_sentinel(__first, __last); } @@ -1264,6 +1280,7 @@ vector<_Tp, _Allocator>::vector(_InputIterator __first, _InputIterator __last, const allocator_type& __a) : __end_cap_(nullptr, __a) { + //_LIBCPP_ASSERT_CHECK_VALID_RANGE(__first, __last, "vector::vector(Iter, Iter, Alloc)"); __init_with_sentinel(__first, __last); } @@ -1274,6 +1291,8 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 vector<_Tp, _Allocator>::vector(_ForwardIterator __first, _ForwardIterator __last) { + //_LIBCPP_ASSERT_CHECK_VALID_RANGE(__first, __last, "vector::vector(Iter, Iter)"); + size_type __n = static_cast(std::distance(__first, __last)); __init_with_size(__first, __last, __n); } @@ -1286,6 +1305,8 @@ vector<_Tp, _Allocator>::vector(_ForwardIterator __first, _ForwardIterator __last, const allocator_type& __a) : __end_cap_(nullptr, __a) { + //_LIBCPP_ASSERT_CHECK_VALID_RANGE(__first, __last, "vector::vector(Iter, Iter, Alloc)"); + size_type __n = static_cast(std::distance(__first, __last)); __init_with_size(__first, __last, __n); } @@ -1447,6 +1468,9 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::assign(_InputIterator __first, _InputIterator __last) { + //_LIBCPP_ASSERT_CHECK_VALID_RANGE(__first, __last, "vector::assign()"); + //_LIBCPP_ASSERT_CHECK_OVERLAPPING_RANGES(begin(), end(), __first, __last, "vector::assign"); + __assign_with_sentinel(__first, __last); } @@ -1466,6 +1490,9 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 void vector<_Tp, _Allocator>::assign(_ForwardIterator __first, _ForwardIterator __last) { + //_LIBCPP_ASSERT_CHECK_VALID_RANGE(__first, __last, "vector::assign()"); + //_LIBCPP_ASSERT_CHECK_OVERLAPPING_RANGES(begin(), end(), __first, __last, "vector::assign"); + __assign_with_size(__first, __last, std::distance(__first, __last)); } @@ -1502,6 +1529,9 @@ void vector<_Tp, _Allocator>::assign(size_type __n, const_reference __u) { + // TODO: _LIBCPP_ASSERT_CHECK_OVERLAPPING_RANGES( + // begin(), end(), __make_iter(__u), __make_iter(__u) + 1, "vector::assign"); + if (__n <= capacity()) { size_type __s = size(); @@ -1563,6 +1593,7 @@ vector<_Tp, _Allocator>::operator[](size_type __n) _NOEXCEPT { _LIBCPP_ASSERT(__n < size(), "vector[] index out of bounds"); + //_LIBCPP_ASSERT_CHECK_VALID_CONTAINER_ACCESS(__n < size(), "vector::operator[]"); return this->__begin_[__n]; } @@ -1573,6 +1604,7 @@ vector<_Tp, _Allocator>::operator[](size_type __n) const _NOEXCEPT { _LIBCPP_ASSERT(__n < size(), "vector[] index out of bounds"); + //_LIBCPP_ASSERT_CHECK_VALID_CONTAINER_ACCESS(__n < size(), "vector::operator[]"); return this->__begin_[__n]; } @@ -1719,6 +1751,7 @@ vector<_Tp, _Allocator>::pop_back() { _LIBCPP_ASSERT(!empty(), "vector::pop_back called on an empty vector"); + //_LIBCPP_ASSERT_CHECK_VALID_CONTAINER_ACCESS(!empty(), "vector::pop_back()"); this->__destruct_at_end(this->__end_ - 1); } @@ -1732,6 +1765,9 @@ "vector::erase(iterator) called with an iterator not referring to this vector"); _LIBCPP_ASSERT(__position != end(), "vector::erase(iterator) called with a non-dereferenceable iterator"); + //_LIBCPP_ASSERT_CHECK_VALID_CONTAINER_ACCESS(__position < end(), "vector::erase(Iter)"); + //_LIBCPP_ASSERT_CHECK_FOREIGN_ITERATOR(*this, __position, "vector::erase(Iter)"); + difference_type __ps = __position - cbegin(); pointer __p = this->__begin_ + __ps; this->__destruct_at_end(std::move(__p + 1, this->__end_, __p)); @@ -1751,6 +1787,9 @@ "vector::erase(iterator, iterator) called with an iterator not referring to this vector"); _LIBCPP_ASSERT(__first <= __last, "vector::erase(first, last) called with invalid range"); + //_LIBCPP_ASSERT_CHECK_VALID_RANGE(__first, __last, "vector::erase(Iter, Iter)"); + //_LIBCPP_ASSERT_CHECK_FOREIGN_ITERATOR(*this, __first, "vector::erase(Iter, Iter)"); + pointer __p = this->__begin_ + (__first - begin()); if (__first != __last) { this->__destruct_at_end(std::move(__p + (__last - __first), this->__end_, __p)); @@ -1787,6 +1826,8 @@ { _LIBCPP_DEBUG_ASSERT(__get_const_db()->__find_c_from_i(std::addressof(__position)) == this, "vector::insert(iterator, x) called with an iterator not referring to this vector"); + //_LIBCPP_ASSERT_CHECK_FOREIGN_ITERATOR(this, __position, "vector::insert(const_iterator, const_reference)"); + pointer __p = this->__begin_ + (__position - begin()); // We can't compare unrelated pointers inside constant expressions if (!__libcpp_is_constant_evaluated() && this->__end_ < this->__end_cap()) @@ -1821,6 +1862,8 @@ { _LIBCPP_DEBUG_ASSERT(__get_const_db()->__find_c_from_i(std::addressof(__position)) == this, "vector::insert(iterator, x) called with an iterator not referring to this vector"); + //_LIBCPP_ASSERT_CHECK_FOREIGN_ITERATOR(this, __position, "vector::insert(const_iterator, value_type&&)"); + pointer __p = this->__begin_ + (__position - begin()); if (this->__end_ < this->__end_cap()) { @@ -1852,6 +1895,8 @@ { _LIBCPP_DEBUG_ASSERT(__get_const_db()->__find_c_from_i(std::addressof(__position)) == this, "vector::emplace(iterator, x) called with an iterator not referring to this vector"); + //_LIBCPP_ASSERT_CHECK_FOREIGN_ITERATOR(*this, __position, "vector::emplace(const_iterator, Args&&...)"); + pointer __p = this->__begin_ + (__position - begin()); if (this->__end_ < this->__end_cap()) { @@ -1883,6 +1928,9 @@ { _LIBCPP_DEBUG_ASSERT(__get_const_db()->__find_c_from_i(std::addressof(__position)) == this, "vector::insert(iterator, n, x) called with an iterator not referring to this vector"); + //_LIBCPP_ASSERT_CHECK_FOREIGN_ITERATOR( + //*this, __position, "vector::insert(const_iterator, size_type, const_reference)"); + pointer __p = this->__begin_ + (__position - begin()); if (__n > 0) { @@ -1923,6 +1971,9 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 typename vector<_Tp, _Allocator>::iterator vector<_Tp, _Allocator>::insert(const_iterator __position, _InputIterator __first, _InputIterator __last) { + //_LIBCPP_ASSERT_CHECK_VALID_RANGE(__first, __last, "vector::insert(const_iterator, Iter, Iter)"); + //_LIBCPP_ASSERT_CHECK_FOREIGN_ITERATOR(*this, __position, "vector::insert(const_iterator, Iter, Iter)"); + return __insert_with_sentinel(__position, __first, __last); } @@ -1977,6 +2028,9 @@ _LIBCPP_CONSTEXPR_SINCE_CXX20 typename vector<_Tp, _Allocator>::iterator vector<_Tp, _Allocator>::insert(const_iterator __position, _ForwardIterator __first, _ForwardIterator __last) { + //_LIBCPP_ASSERT_CHECK_VALID_RANGE(__first, __last, "vector::insert(const_iterator, Iter, Iter)"); + //_LIBCPP_ASSERT_CHECK_FOREIGN_ITERATOR(this, __position, "vector::insert(const_iterator, Iter, Iter)"); + return __insert_with_size(__position, __first, __last, std::distance(__first, __last)); } diff --git a/libcxx/test/libcxx/algorithms/nth_element_stability.pass.cpp b/libcxx/test/libcxx/algorithms/nth_element_stability.pass.cpp --- a/libcxx/test/libcxx/algorithms/nth_element_stability.pass.cpp +++ b/libcxx/test/libcxx/algorithms/nth_element_stability.pass.cpp @@ -11,7 +11,7 @@ // Test std::nth_element stability randomization // UNSUPPORTED: c++03 -// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DEBUG_RANDOMIZE_UNSPECIFIED_STABILITY +// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ASSERTIONS_ENABLE_FEATURE_RANDOMIZE_UNSPECIFIED_BEHAVIOR #include #include diff --git a/libcxx/test/libcxx/algorithms/partial_sort_stability.pass.cpp b/libcxx/test/libcxx/algorithms/partial_sort_stability.pass.cpp --- a/libcxx/test/libcxx/algorithms/partial_sort_stability.pass.cpp +++ b/libcxx/test/libcxx/algorithms/partial_sort_stability.pass.cpp @@ -11,7 +11,7 @@ // Test std::partial_sort stability randomization // UNSUPPORTED: c++03 -// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DEBUG_RANDOMIZE_UNSPECIFIED_STABILITY +// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ASSERTIONS_ENABLE_FEATURE_RANDOMIZE_UNSPECIFIED_BEHAVIOR #include #include diff --git a/libcxx/test/libcxx/algorithms/sort_stability.pass.cpp b/libcxx/test/libcxx/algorithms/sort_stability.pass.cpp --- a/libcxx/test/libcxx/algorithms/sort_stability.pass.cpp +++ b/libcxx/test/libcxx/algorithms/sort_stability.pass.cpp @@ -11,7 +11,7 @@ // Test std::sort stability randomization // UNSUPPORTED: c++03 -// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_DEBUG_RANDOMIZE_UNSPECIFIED_STABILITY +// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ASSERTIONS_ENABLE_FEATURE_RANDOMIZE_UNSPECIFIED_BEHAVIOR #include #include diff --git a/libcxx/test/libcxx/assertions/hardening/debug_mode.pass.cpp b/libcxx/test/libcxx/assertions/hardening/debug_mode.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/assertions/hardening/debug_mode.pass.cpp @@ -0,0 +1,32 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// Test that enabling debug mode turns on the expected categories of checks. + +// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_NEW_DEBUG_MODE=1 + +#include <__hardening> +#include + +#include "check_assertion.h" + +int main(int, char**) { + int a[] = {1, 2, 3}; + + TEST_LIBCPP_ASSERT_FAILURE([&] { + _LIBCPP_ASSERT_CHECK_VALID_RANGE(a, a + 3, "Valid range"); + _LIBCPP_ASSERT_CHECK_VALID_RANGE(a + 3, a, "Invalid range"); + }(), "Invalid range"); + + TEST_LIBCPP_ASSERT_FAILURE([] { + _LIBCPP_ASSERT_CHECK_BAD_CONTAINER_ACCESS(true, "Good container access"); + _LIBCPP_ASSERT_CHECK_BAD_CONTAINER_ACCESS(false, "Bad container access"); + }(), "Bad container access"); + + return 0; +} diff --git a/libcxx/test/libcxx/assertions/hardening/debug_mode_assertions_disabled.pass.cpp b/libcxx/test/libcxx/assertions/hardening/debug_mode_assertions_disabled.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/assertions/hardening/debug_mode_assertions_disabled.pass.cpp @@ -0,0 +1,22 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// Test that it's possible to disable assertions even when debug mode is enabled. + +// ADDITIONAL_COMPILE_FLAGS: -Wno-macro-redefined -D_LIBCPP_ENABLE_ASSERTIONS=0 -D_LIBCPP_ENABLE_NEW_DEBUG_MODE=1 + +#include + +bool executed_condition = false; +bool f() { executed_condition = true; return false; } + +int main(int, char**) { + _LIBCPP_ASSERT(f(), "message"); // should not execute anything + assert(!executed_condition); // really make sure we did not execute anything at all + return 0; +} diff --git a/libcxx/test/libcxx/assertions/hardening/hardened_mode.pass.cpp b/libcxx/test/libcxx/assertions/hardening/hardened_mode.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/assertions/hardening/hardened_mode.pass.cpp @@ -0,0 +1,32 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// Test that enabling hardened mode turns on the expected categories of checks. + +// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_HARDENED_MODE=1 + +#include <__hardening> +#include + +#include "check_assertion.h" + +int main(int, char**) { + int a[] = {1, 2, 3}; + + TEST_LIBCPP_ASSERT_FAILURE([&] { + _LIBCPP_ASSERT_CHECK_VALID_RANGE(a, a + 3, "Valid range"); + _LIBCPP_ASSERT_CHECK_VALID_RANGE(a + 3, a, "Invalid range"); + }(), "Invalid range"); + + TEST_LIBCPP_ASSERT_FAILURE([] { + _LIBCPP_ASSERT_CHECK_BAD_CONTAINER_ACCESS(true, "Good container access"); + _LIBCPP_ASSERT_CHECK_BAD_CONTAINER_ACCESS(false, "Bad container access"); + }(), "Bad container access"); + + return 0; +} diff --git a/libcxx/test/libcxx/assertions/hardening/hardened_mode_assertions_disabled.pass.cpp b/libcxx/test/libcxx/assertions/hardening/hardened_mode_assertions_disabled.pass.cpp new file mode 100644 --- /dev/null +++ b/libcxx/test/libcxx/assertions/hardening/hardened_mode_assertions_disabled.pass.cpp @@ -0,0 +1,22 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +// Test that it's possible to disable assertions even when hardened mode is enabled. + +// ADDITIONAL_COMPILE_FLAGS: -Wno-macro-redefined -D_LIBCPP_ENABLE_ASSERTIONS=0 -D_LIBCPP_ENABLE_HARDENED_MODE=1 + +#include + +bool executed_condition = false; +bool f() { executed_condition = true; return false; } + +int main(int, char**) { + _LIBCPP_ASSERT(f(), "message"); // should not execute anything + assert(!executed_condition); // really make sure we did not execute anything at all + return 0; +} diff --git a/libcxx/test/libcxx/containers/views/views.span/span.cons/assert.iter_sent.pass.cpp b/libcxx/test/libcxx/containers/views/views.span/span.cons/assert.iter_sent.pass.cpp --- a/libcxx/test/libcxx/containers/views/views.span/span.cons/assert.iter_sent.pass.cpp +++ b/libcxx/test/libcxx/containers/views/views.span/span.cons/assert.iter_sent.pass.cpp @@ -20,7 +20,7 @@ // REQUIRES: has-unix-headers // XFAIL: availability-verbose_abort-missing -// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1 +// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_HARDENED_MODE=1 #include #include diff --git a/libcxx/test/libcxx/containers/views/views.span/span.cons/assert.iter_size.pass.cpp b/libcxx/test/libcxx/containers/views/views.span/span.cons/assert.iter_size.pass.cpp --- a/libcxx/test/libcxx/containers/views/views.span/span.cons/assert.iter_size.pass.cpp +++ b/libcxx/test/libcxx/containers/views/views.span/span.cons/assert.iter_size.pass.cpp @@ -17,7 +17,7 @@ // REQUIRES: has-unix-headers // XFAIL: availability-verbose_abort-missing -// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1 +// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_HARDENED_MODE=1 #include #include diff --git a/libcxx/test/libcxx/containers/views/views.span/span.cons/assert.other_span.pass.cpp b/libcxx/test/libcxx/containers/views/views.span/span.cons/assert.other_span.pass.cpp --- a/libcxx/test/libcxx/containers/views/views.span/span.cons/assert.other_span.pass.cpp +++ b/libcxx/test/libcxx/containers/views/views.span/span.cons/assert.other_span.pass.cpp @@ -15,7 +15,7 @@ // REQUIRES: has-unix-headers // XFAIL: availability-verbose_abort-missing -// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1 +// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_HARDENED_MODE=1 #include #include diff --git a/libcxx/test/libcxx/containers/views/views.span/span.cons/assert.range.pass.cpp b/libcxx/test/libcxx/containers/views/views.span/span.cons/assert.range.pass.cpp --- a/libcxx/test/libcxx/containers/views/views.span/span.cons/assert.range.pass.cpp +++ b/libcxx/test/libcxx/containers/views/views.span/span.cons/assert.range.pass.cpp @@ -15,7 +15,7 @@ // REQUIRES: has-unix-headers // XFAIL: availability-verbose_abort-missing -// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1 +// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_HARDENED_MODE=1 #include #include diff --git a/libcxx/test/libcxx/containers/views/views.span/span.elem/assert.back.pass.cpp b/libcxx/test/libcxx/containers/views/views.span/span.elem/assert.back.pass.cpp --- a/libcxx/test/libcxx/containers/views/views.span/span.elem/assert.back.pass.cpp +++ b/libcxx/test/libcxx/containers/views/views.span/span.elem/assert.back.pass.cpp @@ -15,7 +15,7 @@ // REQUIRES: has-unix-headers // XFAIL: availability-verbose_abort-missing -// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1 +// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_HARDENED_MODE=1 #include #include diff --git a/libcxx/test/libcxx/containers/views/views.span/span.elem/assert.front.pass.cpp b/libcxx/test/libcxx/containers/views/views.span/span.elem/assert.front.pass.cpp --- a/libcxx/test/libcxx/containers/views/views.span/span.elem/assert.front.pass.cpp +++ b/libcxx/test/libcxx/containers/views/views.span/span.elem/assert.front.pass.cpp @@ -15,7 +15,7 @@ // REQUIRES: has-unix-headers // XFAIL: availability-verbose_abort-missing -// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1 +// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_HARDENED_MODE=1 #include #include diff --git a/libcxx/test/libcxx/containers/views/views.span/span.elem/assert.op_idx.pass.cpp b/libcxx/test/libcxx/containers/views/views.span/span.elem/assert.op_idx.pass.cpp --- a/libcxx/test/libcxx/containers/views/views.span/span.elem/assert.op_idx.pass.cpp +++ b/libcxx/test/libcxx/containers/views/views.span/span.elem/assert.op_idx.pass.cpp @@ -15,7 +15,7 @@ // REQUIRES: has-unix-headers // XFAIL: availability-verbose_abort-missing -// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1 +// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_HARDENED_MODE=1 #include #include diff --git a/libcxx/test/libcxx/containers/views/views.span/span.sub/assert.first.pass.cpp b/libcxx/test/libcxx/containers/views/views.span/span.sub/assert.first.pass.cpp --- a/libcxx/test/libcxx/containers/views/views.span/span.sub/assert.first.pass.cpp +++ b/libcxx/test/libcxx/containers/views/views.span/span.sub/assert.first.pass.cpp @@ -15,7 +15,7 @@ // REQUIRES: has-unix-headers // XFAIL: availability-verbose_abort-missing -// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1 +// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_HARDENED_MODE=1 #include #include diff --git a/libcxx/test/libcxx/containers/views/views.span/span.sub/assert.last.pass.cpp b/libcxx/test/libcxx/containers/views/views.span/span.sub/assert.last.pass.cpp --- a/libcxx/test/libcxx/containers/views/views.span/span.sub/assert.last.pass.cpp +++ b/libcxx/test/libcxx/containers/views/views.span/span.sub/assert.last.pass.cpp @@ -15,7 +15,7 @@ // REQUIRES: has-unix-headers // XFAIL: availability-verbose_abort-missing -// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1 +// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_HARDENED_MODE=1 #include #include diff --git a/libcxx/test/libcxx/containers/views/views.span/span.sub/assert.subspan.pass.cpp b/libcxx/test/libcxx/containers/views/views.span/span.sub/assert.subspan.pass.cpp --- a/libcxx/test/libcxx/containers/views/views.span/span.sub/assert.subspan.pass.cpp +++ b/libcxx/test/libcxx/containers/views/views.span/span.sub/assert.subspan.pass.cpp @@ -23,7 +23,7 @@ // REQUIRES: has-unix-headers // XFAIL: availability-verbose_abort-missing -// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_ASSERTIONS=1 +// ADDITIONAL_COMPILE_FLAGS: -D_LIBCPP_ENABLE_HARDENED_MODE=1 #include #include diff --git a/libcxx/test/std/containers/views/views.span/span.cons/iterator_sentinel.pass.cpp b/libcxx/test/std/containers/views/views.span/span.cons/iterator_sentinel.pass.cpp --- a/libcxx/test/std/containers/views/views.span/span.cons/iterator_sentinel.pass.cpp +++ b/libcxx/test/std/containers/views/views.span/span.cons/iterator_sentinel.pass.cpp @@ -114,7 +114,7 @@ friend difference_type operator-(throw_operator_minus, throw_operator_minus) { throw 42; }; friend bool operator==(const throw_operator_minus& x, const throw_operator_minus& y) { return x.it_ == y.it_; } - friend bool operator<=>(const throw_operator_minus& x, const throw_operator_minus& y) { return x.it_ <=> y.it_; } + friend auto operator<=>(const throw_operator_minus& x, const throw_operator_minus& y) { return x.it_ <=> y.it_; } }; template