From b1680c85a6227905dea20be1520eed1953c96c9c Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Mon, 6 Nov 2023 08:53:14 -1000 Subject: [PATCH 01/10] [libc++][hardening] Categorize more 'valid-element-access' checks. --- libcxx/include/__algorithm/sample.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/libcxx/include/__algorithm/sample.h b/libcxx/include/__algorithm/sample.h index ebe5180b7eeca..6285b8aed1713 100644 --- a/libcxx/include/__algorithm/sample.h +++ b/libcxx/include/__algorithm/sample.h @@ -77,12 +77,6 @@ _LIBCPP_HIDE_FROM_ABI _SampleIterator __sample( return __output_iter; } -template _LIBCPP_HIDE_FROM_ABI _SampleIterator __sample( _PopulationIterator __first, _PopulationSentinel __last, From 9a8622d49fbce838ef3c1cb86bfedc5345e85f8a Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Fri, 15 Dec 2023 16:10:03 -0800 Subject: [PATCH 02/10] Address feedback (test iterator operations) --- .../iterators/predef.iterators/counted.iterator/assert.pass.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcxx/test/libcxx/iterators/predef.iterators/counted.iterator/assert.pass.cpp b/libcxx/test/libcxx/iterators/predef.iterators/counted.iterator/assert.pass.cpp index f803b2cad75be..923b57fe6a05f 100644 --- a/libcxx/test/libcxx/iterators/predef.iterators/counted.iterator/assert.pass.cpp +++ b/libcxx/test/libcxx/iterators/predef.iterators/counted.iterator/assert.pass.cpp @@ -18,7 +18,7 @@ int main(int, char**) { using Iter = std::counted_iterator; - int a[] = {1, 2, 3}; + int a[] = {1, 2, 3}; Iter valid_i(a, 1); { From bcc8ef28c19c2da48a4fa430af97e8e3c40e3750 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Fri, 15 Dec 2023 16:25:40 -0800 Subject: [PATCH 03/10] Quick fix to new tests --- .../iterators/predef.iterators/counted.iterator/assert.pass.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libcxx/test/libcxx/iterators/predef.iterators/counted.iterator/assert.pass.cpp b/libcxx/test/libcxx/iterators/predef.iterators/counted.iterator/assert.pass.cpp index 923b57fe6a05f..f803b2cad75be 100644 --- a/libcxx/test/libcxx/iterators/predef.iterators/counted.iterator/assert.pass.cpp +++ b/libcxx/test/libcxx/iterators/predef.iterators/counted.iterator/assert.pass.cpp @@ -18,7 +18,7 @@ int main(int, char**) { using Iter = std::counted_iterator; - int a[] = {1, 2, 3}; + int a[] = {1, 2, 3}; Iter valid_i(a, 1); { From cd4d8c78c125165b5e86e2c891fcc8dbcc863d6a Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Tue, 19 Dec 2023 01:48:39 -0800 Subject: [PATCH 04/10] Fix bad merge --- libcxx/include/__algorithm/sample.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/libcxx/include/__algorithm/sample.h b/libcxx/include/__algorithm/sample.h index 6285b8aed1713..ebe5180b7eeca 100644 --- a/libcxx/include/__algorithm/sample.h +++ b/libcxx/include/__algorithm/sample.h @@ -77,6 +77,12 @@ _LIBCPP_HIDE_FROM_ABI _SampleIterator __sample( return __output_iter; } +template _LIBCPP_HIDE_FROM_ABI _SampleIterator __sample( _PopulationIterator __first, _PopulationSentinel __last, From 904bb3e4d9b12b35b84b0b19701a3dd34fc65cea Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Tue, 19 Dec 2023 01:27:50 -0800 Subject: [PATCH 05/10] [libc++][hardening] Categorize more assertions. Also introduce `_LIBCPP_ASSERT_PEDANTIC` for assertions violating which results in a no-op or other benign behavior, but which may nevertheless indicate a bug in the invoking code. --- libcxx/include/__algorithm/pop_heap.h | 3 +- libcxx/include/__algorithm/sift_down.h | 2 +- libcxx/include/__algorithm/sort.h | 4 +- libcxx/include/__charconv/to_chars_base_10.h | 4 +- libcxx/include/__charconv/to_chars_integral.h | 2 +- libcxx/include/__charconv/traits.h | 4 +- .../include/__chrono/parser_std_format_spec.h | 2 +- libcxx/include/__config | 6 ++ libcxx/include/__filesystem/path_iterator.h | 4 +- libcxx/include/__format/buffer.h | 12 ++-- libcxx/include/__format/format_arg.h | 2 +- libcxx/include/__format/formatter_bool.h | 2 +- .../__format/formatter_floating_point.h | 55 +++++++++---------- libcxx/include/__format/formatter_integral.h | 16 ++---- libcxx/include/__format/formatter_output.h | 6 +- libcxx/include/__format/formatter_string.h | 5 +- .../include/__format/parser_std_format_spec.h | 7 +-- libcxx/include/__format/range_formatter.h | 5 +- libcxx/include/__format/unicode.h | 14 ++--- libcxx/include/__format/write_escaped.h | 2 +- libcxx/include/__hash_table | 5 +- libcxx/include/__iterator/advance.h | 13 +++-- libcxx/include/__iterator/next.h | 10 ++-- libcxx/include/__iterator/prev.h | 6 +- .../__random/negative_binomial_distribution.h | 7 +-- libcxx/include/__ranges/chunk_by_view.h | 20 ++++--- libcxx/include/__ranges/drop_while_view.h | 3 +- libcxx/include/__ranges/filter_view.h | 5 +- libcxx/include/__thread/thread.h | 2 +- libcxx/include/__utility/exception_guard.h | 2 +- libcxx/include/__utility/unreachable.h | 2 +- libcxx/include/print | 8 ++- libcxx/include/set | 32 +++++------ libcxx/src/filesystem/error.h | 2 +- libcxx/src/filesystem/format_string.h | 2 +- libcxx/src/filesystem/posix_compat.h | 6 +- libcxx/src/include/to_chars_floating_point.h | 20 +++---- libcxx/src/memory_resource.cpp | 2 +- libcxx/src/strstream.cpp | 2 +- libcxx/src/system_error.cpp | 2 +- 40 files changed, 163 insertions(+), 145 deletions(-) diff --git a/libcxx/include/__algorithm/pop_heap.h b/libcxx/include/__algorithm/pop_heap.h index a93a9875f7058..798a1d09934bc 100644 --- a/libcxx/include/__algorithm/pop_heap.h +++ b/libcxx/include/__algorithm/pop_heap.h @@ -36,7 +36,8 @@ __pop_heap(_RandomAccessIterator __first, _RandomAccessIterator __last, _Compare& __comp, typename iterator_traits<_RandomAccessIterator>::difference_type __len) { - _LIBCPP_ASSERT_UNCATEGORIZED(__len > 0, "The heap given to pop_heap must be non-empty"); + // Calling `pop_heap` on an empty range is undefined behavior, but in practice it will be a no-op. + _LIBCPP_ASSERT_PEDANTIC(__len > 0, "The heap given to pop_heap must be non-empty"); __comp_ref_type<_Compare> __comp_ref = __comp; diff --git a/libcxx/include/__algorithm/sift_down.h b/libcxx/include/__algorithm/sift_down.h index 7f152e4dbd7f3..42803e30631fb 100644 --- a/libcxx/include/__algorithm/sift_down.h +++ b/libcxx/include/__algorithm/sift_down.h @@ -85,7 +85,7 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _RandomAccessIterator __floy _Compare&& __comp, typename iterator_traits<_RandomAccessIterator>::difference_type __len) { using difference_type = typename iterator_traits<_RandomAccessIterator>::difference_type; - _LIBCPP_ASSERT_UNCATEGORIZED(__len >= 2, "shouldn't be called unless __len >= 2"); + _LIBCPP_ASSERT_INTERNAL(__len >= 2, "shouldn't be called unless __len >= 2"); _RandomAccessIterator __hole = __first; _RandomAccessIterator __child_i = __first; diff --git a/libcxx/include/__algorithm/sort.h b/libcxx/include/__algorithm/sort.h index 1b878c33c7a16..ac47489af0aac 100644 --- a/libcxx/include/__algorithm/sort.h +++ b/libcxx/include/__algorithm/sort.h @@ -533,7 +533,7 @@ __bitset_partition(_RandomAccessIterator __first, _RandomAccessIterator __last, using _Ops = _IterOps<_AlgPolicy>; typedef typename std::iterator_traits<_RandomAccessIterator>::value_type value_type; typedef typename std::iterator_traits<_RandomAccessIterator>::difference_type difference_type; - _LIBCPP_ASSERT_UNCATEGORIZED(__last - __first >= difference_type(3), ""); + _LIBCPP_ASSERT_INTERNAL(__last - __first >= difference_type(3), ""); const _RandomAccessIterator __begin = __first; // used for bounds checking, those are not moved around const _RandomAccessIterator __end = __last; (void)__end; // @@ -625,7 +625,7 @@ __partition_with_equals_on_right(_RandomAccessIterator __first, _RandomAccessIte using _Ops = _IterOps<_AlgPolicy>; typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type; typedef typename std::iterator_traits<_RandomAccessIterator>::value_type value_type; - _LIBCPP_ASSERT_UNCATEGORIZED(__last - __first >= difference_type(3), ""); + _LIBCPP_ASSERT_INTERNAL(__last - __first >= difference_type(3), ""); const _RandomAccessIterator __begin = __first; // used for bounds checking, those are not moved around const _RandomAccessIterator __end = __last; (void)__end; // diff --git a/libcxx/include/__charconv/to_chars_base_10.h b/libcxx/include/__charconv/to_chars_base_10.h index 33c512e20f04c..c1a5d4f9d5d52 100644 --- a/libcxx/include/__charconv/to_chars_base_10.h +++ b/libcxx/include/__charconv/to_chars_base_10.h @@ -132,13 +132,13 @@ __base_10_u64(char* __buffer, uint64_t __value) noexcept { /// range that can be used. However the range is sufficient for /// \ref __base_10_u128. _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI inline __uint128_t __pow_10(int __exp) noexcept { - _LIBCPP_ASSERT_UNCATEGORIZED(__exp >= __pow10_128_offset, "Index out of bounds"); + _LIBCPP_ASSERT_INTERNAL(__exp >= __pow10_128_offset, "Index out of bounds"); return __pow10_128[__exp - __pow10_128_offset]; } _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI inline char* __base_10_u128(char* __buffer, __uint128_t __value) noexcept { - _LIBCPP_ASSERT_UNCATEGORIZED( + _LIBCPP_ASSERT_INTERNAL( __value > numeric_limits::max(), "The optimizations for this algorithm fail when this isn't true."); // Unlike the 64 to 32 bit case the 128 bit case the "upper half" can't be diff --git a/libcxx/include/__charconv/to_chars_integral.h b/libcxx/include/__charconv/to_chars_integral.h index f50cc55a4c6d9..40fbe334d8d54 100644 --- a/libcxx/include/__charconv/to_chars_integral.h +++ b/libcxx/include/__charconv/to_chars_integral.h @@ -246,7 +246,7 @@ __to_chars_integral(char* __first, char* __last, _Tp __value) { template _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI int __to_chars_integral_width(_Tp __value, unsigned __base) { - _LIBCPP_ASSERT_UNCATEGORIZED(__value >= 0, "The function requires a non-negative value."); + _LIBCPP_ASSERT_INTERNAL(__value >= 0, "The function requires a non-negative value."); unsigned __base_2 = __base * __base; unsigned __base_3 = __base_2 * __base; diff --git a/libcxx/include/__charconv/traits.h b/libcxx/include/__charconv/traits.h index d3884b560dfd7..b4907c3f77571 100644 --- a/libcxx/include/__charconv/traits.h +++ b/libcxx/include/__charconv/traits.h @@ -101,11 +101,11 @@ struct _LIBCPP_HIDDEN __traits_base<_Tp, __enable_if_t numeric_limits::max(), "The optimizations for this algorithm fail when this isn't true."); // There's always a bit set in the upper 64-bits. auto __t = (128 - std::__libcpp_clz(static_cast(__v >> 64))) * 1233 >> 12; - _LIBCPP_ASSERT_UNCATEGORIZED(__t >= __itoa::__pow10_128_offset, "Index out of bounds"); + _LIBCPP_ASSERT_INTERNAL(__t >= __itoa::__pow10_128_offset, "Index out of bounds"); // __t is adjusted since the lookup table misses the lower entries. return __t - (__v < __itoa::__pow10_128[__t - __itoa::__pow10_128_offset]) + 1; } diff --git a/libcxx/include/__chrono/parser_std_format_spec.h b/libcxx/include/__chrono/parser_std_format_spec.h index 296be8794ec59..86c9712ba487d 100644 --- a/libcxx/include/__chrono/parser_std_format_spec.h +++ b/libcxx/include/__chrono/parser_std_format_spec.h @@ -160,7 +160,7 @@ class _LIBCPP_TEMPLATE_VIS __parser_chrono { private: _LIBCPP_HIDE_FROM_ABI constexpr _ConstIterator __parse_chrono_specs(_ConstIterator __begin, _ConstIterator __end, __flags __flags) { - _LIBCPP_ASSERT_UNCATEGORIZED( + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( __begin != __end, "When called with an empty input the function will cause " "undefined behavior by evaluating data not in the input"); diff --git a/libcxx/include/__config b/libcxx/include/__config index 40e6da8bc03af..2553ad48667fc 100644 --- a/libcxx/include/__config +++ b/libcxx/include/__config @@ -283,6 +283,9 @@ // - `_LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR` -- checks any operations that exchange nodes between containers to make sure // the containers have compatible allocators. // +// - `_LIBCPP_ASSERT_PEDANTIC` -- checks prerequisites which are imposed by the Standard, but violating which happens to +// be benign in our implementation. +// // - `_LIBCPP_ASSERT_INTERNAL` -- checks that internal invariants of the library hold. These assertions don't depend on // user input. // @@ -325,6 +328,7 @@ _LIBCPP_HARDENING_MODE_DEBUG // vulnerability. # define _LIBCPP_ASSERT_NON_OVERLAPPING_RANGES(expression, message) _LIBCPP_ASSUME(expression) # define _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(expression, message) _LIBCPP_ASSUME(expression) +# define _LIBCPP_ASSERT_PEDANTIC(expression, message) _LIBCPP_ASSUME(expression) # define _LIBCPP_ASSERT_INTERNAL(expression, message) _LIBCPP_ASSUME(expression) # define _LIBCPP_ASSERT_UNCATEGORIZED(expression, message) _LIBCPP_ASSUME(expression) @@ -340,6 +344,7 @@ _LIBCPP_HARDENING_MODE_DEBUG # define _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(expression, message) _LIBCPP_ASSERT(expression, message) # define _LIBCPP_ASSERT_UNCATEGORIZED(expression, message) _LIBCPP_ASSERT(expression, message) // Disabled checks. +# define _LIBCPP_ASSERT_PEDANTIC(expression, message) _LIBCPP_ASSUME(expression) # define _LIBCPP_ASSERT_INTERNAL(expression, message) _LIBCPP_ASSUME(expression) // Debug hardening mode checks. @@ -352,6 +357,7 @@ _LIBCPP_HARDENING_MODE_DEBUG # define _LIBCPP_ASSERT_NON_NULL(expression, message) _LIBCPP_ASSERT(expression, message) # define _LIBCPP_ASSERT_NON_OVERLAPPING_RANGES(expression, message) _LIBCPP_ASSERT(expression, message) # define _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(expression, message) _LIBCPP_ASSERT(expression, message) +# define _LIBCPP_ASSERT_PEDANTIC(expression, message) _LIBCPP_ASSERT(expression, message) # define _LIBCPP_ASSERT_INTERNAL(expression, message) _LIBCPP_ASSERT(expression, message) # define _LIBCPP_ASSERT_UNCATEGORIZED(expression, message) _LIBCPP_ASSERT(expression, message) diff --git a/libcxx/include/__filesystem/path_iterator.h b/libcxx/include/__filesystem/path_iterator.h index 1a9aaf0e7d99e..d2d65cd122cab 100644 --- a/libcxx/include/__filesystem/path_iterator.h +++ b/libcxx/include/__filesystem/path_iterator.h @@ -61,7 +61,7 @@ class _LIBCPP_EXPORTED_FROM_ABI path::iterator { _LIBCPP_HIDE_FROM_ABI pointer operator->() const { return &__stashed_elem_; } _LIBCPP_HIDE_FROM_ABI iterator& operator++() { - _LIBCPP_ASSERT_UNCATEGORIZED(__state_ != _Singular, "attempting to increment a singular iterator"); + _LIBCPP_ASSERT_NON_NULL(__state_ != _Singular, "attempting to increment a singular iterator"); _LIBCPP_ASSERT_UNCATEGORIZED(__state_ != _AtEnd, "attempting to increment the end iterator"); return __increment(); } @@ -73,7 +73,7 @@ class _LIBCPP_EXPORTED_FROM_ABI path::iterator { } _LIBCPP_HIDE_FROM_ABI iterator& operator--() { - _LIBCPP_ASSERT_UNCATEGORIZED(__state_ != _Singular, "attempting to decrement a singular iterator"); + _LIBCPP_ASSERT_NON_NULL(__state_ != _Singular, "attempting to decrement a singular iterator"); _LIBCPP_ASSERT_UNCATEGORIZED( __entry_.data() != __path_ptr_->native().data(), "attempting to decrement the begin iterator"); return __decrement(); diff --git a/libcxx/include/__format/buffer.h b/libcxx/include/__format/buffer.h index 7ee583d813945..8598f0a1c0395 100644 --- a/libcxx/include/__format/buffer.h +++ b/libcxx/include/__format/buffer.h @@ -115,7 +115,7 @@ class _LIBCPP_TEMPLATE_VIS __output_buffer { // The output doesn't fit in the internal buffer. // Copy the data in "__capacity_" sized chunks. - _LIBCPP_ASSERT_UNCATEGORIZED(__size_ == 0, "the buffer should be flushed by __flush_on_overflow"); + _LIBCPP_ASSERT_INTERNAL(__size_ == 0, "the buffer should be flushed by __flush_on_overflow"); const _InCharT* __first = __str.data(); do { size_t __chunk = std::min(__n, __capacity_); @@ -134,7 +134,7 @@ class _LIBCPP_TEMPLATE_VIS __output_buffer { class _UnaryOperation, __fmt_char_type _InCharT = typename iterator_traits<_Iterator>::value_type> _LIBCPP_HIDE_FROM_ABI void __transform(_Iterator __first, _Iterator __last, _UnaryOperation __operation) { - _LIBCPP_ASSERT_UNCATEGORIZED(__first <= __last, "not a valid range"); + _LIBCPP_ASSERT_INTERNAL(__first <= __last, "not a valid range"); size_t __n = static_cast(__last - __first); __flush_on_overflow(__n); @@ -146,7 +146,7 @@ class _LIBCPP_TEMPLATE_VIS __output_buffer { // The output doesn't fit in the internal buffer. // Transform the data in "__capacity_" sized chunks. - _LIBCPP_ASSERT_UNCATEGORIZED(__size_ == 0, "the buffer should be flushed by __flush_on_overflow"); + _LIBCPP_ASSERT_INTERNAL(__size_ == 0, "the buffer should be flushed by __flush_on_overflow"); do { size_t __chunk = std::min(__n, __capacity_); std::transform(__first, __first + __chunk, std::addressof(__ptr_[__size_]), __operation); @@ -168,7 +168,7 @@ class _LIBCPP_TEMPLATE_VIS __output_buffer { // The output doesn't fit in the internal buffer. // Fill the buffer in "__capacity_" sized chunks. - _LIBCPP_ASSERT_UNCATEGORIZED(__size_ == 0, "the buffer should be flushed by __flush_on_overflow"); + _LIBCPP_ASSERT_INTERNAL(__size_ == 0, "the buffer should be flushed by __flush_on_overflow"); do { size_t __chunk = std::min(__n, __capacity_); std::fill_n(std::addressof(__ptr_[__size_]), __chunk, __value); @@ -596,7 +596,7 @@ class _LIBCPP_TEMPLATE_VIS __retarget_buffer { class _UnaryOperation, __fmt_char_type _InCharT = typename iterator_traits<_Iterator>::value_type> _LIBCPP_HIDE_FROM_ABI void __transform(_Iterator __first, _Iterator __last, _UnaryOperation __operation) { - _LIBCPP_ASSERT_UNCATEGORIZED(__first <= __last, "not a valid range"); + _LIBCPP_ASSERT_INTERNAL(__first <= __last, "not a valid range"); size_t __n = static_cast(__last - __first); if (__size_ + __n >= __capacity_) @@ -623,7 +623,7 @@ class _LIBCPP_TEMPLATE_VIS __retarget_buffer { _LIBCPP_HIDE_FROM_ABI void __grow_buffer() { __grow_buffer(__capacity_ * 1.6); } _LIBCPP_HIDE_FROM_ABI void __grow_buffer(size_t __capacity) { - _LIBCPP_ASSERT_UNCATEGORIZED(__capacity > __capacity_, "the buffer must grow"); + _LIBCPP_ASSERT_INTERNAL(__capacity > __capacity_, "the buffer must grow"); auto __result = std::__allocate_at_least(__alloc_, __capacity); auto __guard = std::__make_exception_guard([&] { allocator_traits<_Alloc>::deallocate(__alloc_, __result.ptr, __result.count); diff --git a/libcxx/include/__format/format_arg.h b/libcxx/include/__format/format_arg.h index 280c910824175..10fca15d5a7a9 100644 --- a/libcxx/include/__format/format_arg.h +++ b/libcxx/include/__format/format_arg.h @@ -83,7 +83,7 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool __use_packed_format_arg_store(size_t __size } _LIBCPP_HIDE_FROM_ABI constexpr __arg_t __get_packed_type(uint64_t __types, size_t __id) { - _LIBCPP_ASSERT_UNCATEGORIZED(__id <= __packed_types_max, ""); + _LIBCPP_ASSERT_INTERNAL(__id <= __packed_types_max, ""); if (__id > 0) __types >>= __id * __packed_arg_t_bits; diff --git a/libcxx/include/__format/formatter_bool.h b/libcxx/include/__format/formatter_bool.h index 3c8ae95f55fa1..1c479501b675f 100644 --- a/libcxx/include/__format/formatter_bool.h +++ b/libcxx/include/__format/formatter_bool.h @@ -62,7 +62,7 @@ struct _LIBCPP_TEMPLATE_VIS formatter { static_cast(__value), __ctx, __parser_.__get_parsed_std_specifications(__ctx)); default: - _LIBCPP_ASSERT_UNCATEGORIZED(false, "The parse function should have validated the type"); + _LIBCPP_ASSERT_INTERNAL(false, "The parse function should have validated the type"); __libcpp_unreachable(); } } diff --git a/libcxx/include/__format/formatter_floating_point.h b/libcxx/include/__format/formatter_floating_point.h index 33cc2a4ed6612..6802a8b7bd4ca 100644 --- a/libcxx/include/__format/formatter_floating_point.h +++ b/libcxx/include/__format/formatter_floating_point.h @@ -57,21 +57,21 @@ namespace __formatter { template _LIBCPP_HIDE_FROM_ABI char* __to_buffer(char* __first, char* __last, _Tp __value) { to_chars_result __r = std::to_chars(__first, __last, __value); - _LIBCPP_ASSERT_UNCATEGORIZED(__r.ec == errc(0), "Internal buffer too small"); + _LIBCPP_ASSERT_INTERNAL(__r.ec == errc(0), "Internal buffer too small"); return __r.ptr; } template _LIBCPP_HIDE_FROM_ABI char* __to_buffer(char* __first, char* __last, _Tp __value, chars_format __fmt) { to_chars_result __r = std::to_chars(__first, __last, __value, __fmt); - _LIBCPP_ASSERT_UNCATEGORIZED(__r.ec == errc(0), "Internal buffer too small"); + _LIBCPP_ASSERT_INTERNAL(__r.ec == errc(0), "Internal buffer too small"); return __r.ptr; } template _LIBCPP_HIDE_FROM_ABI char* __to_buffer(char* __first, char* __last, _Tp __value, chars_format __fmt, int __precision) { to_chars_result __r = std::to_chars(__first, __last, __value, __fmt, __precision); - _LIBCPP_ASSERT_UNCATEGORIZED(__r.ec == errc(0), "Internal buffer too small"); + _LIBCPP_ASSERT_INTERNAL(__r.ec == errc(0), "Internal buffer too small"); return __r.ptr; } @@ -252,10 +252,10 @@ __format_buffer_default(const __float_buffer<_Fp>& __buffer, _Tp __value, char* __result.__radix_point = __result.__last; // clang-format off - _LIBCPP_ASSERT_UNCATEGORIZED((__result.__integral != __result.__last) && - (__result.__radix_point == __result.__last || *__result.__radix_point == '.') && - (__result.__exponent == __result.__last || *__result.__exponent == 'e'), - "Post-condition failure."); + _LIBCPP_ASSERT_INTERNAL((__result.__integral != __result.__last) && + (__result.__radix_point == __result.__last || *__result.__radix_point == '.') && + (__result.__exponent == __result.__last || *__result.__exponent == 'e'), + "Post-condition failure."); // clang-format on return __result; @@ -304,10 +304,10 @@ _LIBCPP_HIDE_FROM_ABI __float_result __format_buffer_hexadecimal_lower_case( } // clang-format off - _LIBCPP_ASSERT_UNCATEGORIZED((__result.__integral != __result.__last) && - (__result.__radix_point == __result.__last || *__result.__radix_point == '.') && - (__result.__exponent != __result.__last && *__result.__exponent == 'p'), - "Post-condition failure."); + _LIBCPP_ASSERT_INTERNAL((__result.__integral != __result.__last) && + (__result.__radix_point == __result.__last || *__result.__radix_point == '.') && + (__result.__exponent != __result.__last && *__result.__exponent == 'p'), + "Post-condition failure."); // clang-format on return __result; @@ -332,7 +332,7 @@ _LIBCPP_HIDE_FROM_ABI __float_result __format_buffer_scientific_lower_case( __formatter::__to_buffer(__integral, __buffer.end(), __value, chars_format::scientific, __precision); char* __first = __integral + 1; - _LIBCPP_ASSERT_UNCATEGORIZED(__first != __result.__last, "No exponent present"); + _LIBCPP_ASSERT_INTERNAL(__first != __result.__last, "No exponent present"); if (*__first == '.') { __result.__radix_point = __first; __result.__exponent = __formatter::__find_exponent(__first + 1, __result.__last); @@ -342,10 +342,10 @@ _LIBCPP_HIDE_FROM_ABI __float_result __format_buffer_scientific_lower_case( } // clang-format off - _LIBCPP_ASSERT_UNCATEGORIZED((__result.__integral != __result.__last) && - (__result.__radix_point == __result.__last || *__result.__radix_point == '.') && - (__result.__exponent != __result.__last && *__result.__exponent == 'e'), - "Post-condition failure."); + _LIBCPP_ASSERT_INTERNAL((__result.__integral != __result.__last) && + (__result.__radix_point == __result.__last || *__result.__radix_point == '.') && + (__result.__exponent != __result.__last && *__result.__exponent == 'e'), + "Post-condition failure."); // clang-format on return __result; } @@ -374,10 +374,10 @@ __format_buffer_fixed(const __float_buffer<_Fp>& __buffer, _Tp __value, int __pr __result.__exponent = __result.__last; // clang-format off - _LIBCPP_ASSERT_UNCATEGORIZED((__result.__integral != __result.__last) && - (__result.__radix_point == __result.__last || *__result.__radix_point == '.') && - (__result.__exponent == __result.__last), - "Post-condition failure."); + _LIBCPP_ASSERT_INTERNAL((__result.__integral != __result.__last) && + (__result.__radix_point == __result.__last || *__result.__radix_point == '.') && + (__result.__exponent == __result.__last), + "Post-condition failure."); // clang-format on return __result; } @@ -410,10 +410,10 @@ __format_buffer_general_lower_case(__float_buffer<_Fp>& __buffer, _Tp __value, i } // clang-format off - _LIBCPP_ASSERT_UNCATEGORIZED((__result.__integral != __result.__last) && - (__result.__radix_point == __result.__last || *__result.__radix_point == '.') && - (__result.__exponent == __result.__last || *__result.__exponent == 'e'), - "Post-condition failure."); + _LIBCPP_ASSERT_INTERNAL((__result.__integral != __result.__last) && + (__result.__radix_point == __result.__last || *__result.__radix_point == '.') && + (__result.__exponent == __result.__last || *__result.__exponent == 'e'), + "Post-condition failure."); // clang-format on return __result; @@ -485,7 +485,7 @@ _LIBCPP_HIDE_FROM_ABI __float_result __format_buffer( return __formatter::__format_buffer_general_upper_case(__buffer, __value, __buffer.__precision(), __first); default: - _LIBCPP_ASSERT_UNCATEGORIZED(false, "The parser should have validated the type"); + _LIBCPP_ASSERT_INTERNAL(false, "The parser should have validated the type"); __libcpp_unreachable(); } } @@ -620,9 +620,8 @@ _LIBCPP_HIDE_FROM_ABI auto __write_using_trailing_zeros( size_t __size, const _CharT* __exponent, size_t __num_trailing_zeros) -> decltype(__out_it) { - _LIBCPP_ASSERT_UNCATEGORIZED(__first <= __last, "Not a valid range"); - _LIBCPP_ASSERT_UNCATEGORIZED( - __num_trailing_zeros > 0, "The overload not writing trailing zeros should have been used"); + _LIBCPP_ASSERT_INTERNAL(__first <= __last, "Not a valid range"); + _LIBCPP_ASSERT_INTERNAL(__num_trailing_zeros > 0, "The overload not writing trailing zeros should have been used"); __padding_size_result __padding = __formatter::__padding_size(__size + __num_trailing_zeros, __specs.__width_, __specs.__alignment_); diff --git a/libcxx/include/__format/formatter_integral.h b/libcxx/include/__format/formatter_integral.h index ca66e26ede107..e0217a240027c 100644 --- a/libcxx/include/__format/formatter_integral.h +++ b/libcxx/include/__format/formatter_integral.h @@ -90,10 +90,8 @@ _LIBCPP_HIDE_FROM_ABI inline _Iterator __insert_sign(_Iterator __buf, bool __neg * regardless whether the @c std::numpunct's type is @c char or @c wchar_t. */ _LIBCPP_HIDE_FROM_ABI inline string __determine_grouping(ptrdiff_t __size, const string& __grouping) { - _LIBCPP_ASSERT_UNCATEGORIZED( - !__grouping.empty() && __size > __grouping[0], - "The slow grouping formatting is used while there will be no " - "separators written"); + _LIBCPP_ASSERT_INTERNAL(!__grouping.empty() && __size > __grouping[0], + "The slow grouping formatting is used while there will be no separators written"); string __r; auto __end = __grouping.end() - 1; auto __ptr = __grouping.begin(); @@ -161,7 +159,7 @@ _LIBCPP_HIDE_FROM_ABI _Iterator __to_buffer(_Iterator __first, _Iterator __last, // TODO FMT Evaluate code overhead due to not calling the internal function // directly. (Should be zero overhead.) to_chars_result __r = std::to_chars(std::to_address(__first), std::to_address(__last), __value, __base); - _LIBCPP_ASSERT_UNCATEGORIZED(__r.ec == errc(0), "Internal buffer too small"); + _LIBCPP_ASSERT_INTERNAL(__r.ec == errc(0), "Internal buffer too small"); auto __diff = __r.ptr - std::to_address(__first); return __first + __diff; } @@ -248,10 +246,8 @@ _LIBCPP_HIDE_FROM_ABI _OutIt __write_using_decimal_separators( auto __r = __grouping.rbegin(); auto __e = __grouping.rend() - 1; - _LIBCPP_ASSERT_UNCATEGORIZED( - __r != __e, - "The slow grouping formatting is used while " - "there will be no separators written."); + _LIBCPP_ASSERT_INTERNAL( + __r != __e, "The slow grouping formatting is used while there will be no separators written."); // The output is divided in small groups of numbers to write: // - A group before the first separator. // - A separator and a group, repeated for the number of separators. @@ -380,7 +376,7 @@ __format_integer(_Tp __value, return __formatter::__format_integer(__value, __ctx, __specs, __negative, __array.begin(), __array.end(), "0X", 16); } default: - _LIBCPP_ASSERT_UNCATEGORIZED(false, "The parse function should have validated the type"); + _LIBCPP_ASSERT_INTERNAL(false, "The parse function should have validated the type"); __libcpp_unreachable(); } } diff --git a/libcxx/include/__format/formatter_output.h b/libcxx/include/__format/formatter_output.h index 31e06425703ae..eebe880d69ef5 100644 --- a/libcxx/include/__format/formatter_output.h +++ b/libcxx/include/__format/formatter_output.h @@ -66,8 +66,8 @@ struct _LIBCPP_EXPORTED_FROM_ABI __padding_size_result { _LIBCPP_HIDE_FROM_ABI constexpr __padding_size_result __padding_size(size_t __size, size_t __width, __format_spec::__alignment __align) { - _LIBCPP_ASSERT_UNCATEGORIZED(__width > __size, "don't call this function when no padding is required"); - _LIBCPP_ASSERT_UNCATEGORIZED( + _LIBCPP_ASSERT_INTERNAL(__width > __size, "don't call this function when no padding is required"); + _LIBCPP_ASSERT_INTERNAL( __align != __format_spec::__alignment::__zero_padding, "the caller should have handled the zero-padding"); size_t __fill = __width - __size; @@ -296,7 +296,7 @@ _LIBCPP_HIDE_FROM_ABI auto __write_string_no_precision( basic_string_view<_CharT> __str, output_iterator auto __out_it, __format_spec::__parsed_specifications<_CharT> __specs) -> decltype(__out_it) { - _LIBCPP_ASSERT_UNCATEGORIZED(!__specs.__has_precision(), "use __write_string"); + _LIBCPP_ASSERT_INTERNAL(!__specs.__has_precision(), "use __write_string"); // No padding -> copy the string if (!__specs.__has_width()) diff --git a/libcxx/include/__format/formatter_string.h b/libcxx/include/__format/formatter_string.h index 4ba5617a49c8d..d1ccfb9b5f7dc 100644 --- a/libcxx/include/__format/formatter_string.h +++ b/libcxx/include/__format/formatter_string.h @@ -64,10 +64,7 @@ struct _LIBCPP_TEMPLATE_VIS formatter : public __formatte template _LIBCPP_HIDE_FROM_ABI typename _FormatContext::iterator format(const _CharT* __str, _FormatContext& __ctx) const { - _LIBCPP_ASSERT_UNCATEGORIZED( - __str, - "The basic_format_arg constructor should have " - "prevented an invalid pointer."); + _LIBCPP_ASSERT_INTERNAL(__str, "The basic_format_arg constructor should have prevented an invalid pointer."); __format_spec::__parsed_specifications<_CharT> __specs = _Base::__parser_.__get_parsed_std_specifications(__ctx); # if _LIBCPP_STD_VER >= 23 diff --git a/libcxx/include/__format/parser_std_format_spec.h b/libcxx/include/__format/parser_std_format_spec.h index e38729db965c3..cf8af87b21284 100644 --- a/libcxx/include/__format/parser_std_format_spec.h +++ b/libcxx/include/__format/parser_std_format_spec.h @@ -733,10 +733,9 @@ class _LIBCPP_TEMPLATE_VIS __parser { __format::__parse_number_result __r = __format::__parse_number(__begin, __end); __width_ = __r.__value; - _LIBCPP_ASSERT_UNCATEGORIZED( - __width_ != 0, - "A zero value isn't allowed and should be impossible, " - "due to validations in this function"); + _LIBCPP_ASSERT_INTERNAL(__width_ != 0, + "A zero value isn't allowed and should be impossible, " + "due to validations in this function"); __begin = __r.__last; return true; } diff --git a/libcxx/include/__format/range_formatter.h b/libcxx/include/__format/range_formatter.h index d13278009fcf8..6915630743493 100644 --- a/libcxx/include/__format/range_formatter.h +++ b/libcxx/include/__format/range_formatter.h @@ -246,9 +246,8 @@ struct _LIBCPP_TEMPLATE_VIS range_formatter { __parse_empty_range_underlying_spec(_ParseContext& __ctx, typename _ParseContext::iterator __begin) { __ctx.advance_to(__begin); [[maybe_unused]] typename _ParseContext::iterator __result = __underlying_.parse(__ctx); - _LIBCPP_ASSERT_UNCATEGORIZED( - __result == __begin, - "the underlying's parse function should not advance the input beyond the end of the input"); + _LIBCPP_ASSERT_INTERNAL(__result == __begin, + "the underlying's parse function should not advance the input beyond the end of the input"); return __begin; } diff --git a/libcxx/include/__format/unicode.h b/libcxx/include/__format/unicode.h index 8e1e7bb192a00..40067ca3448bb 100644 --- a/libcxx/include/__format/unicode.h +++ b/libcxx/include/__format/unicode.h @@ -153,7 +153,7 @@ class __code_point_view { // - The parser always needs to consume these code units // - The code is optimized for well-formed UTF-8 [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __consume_result __consume() noexcept { - _LIBCPP_ASSERT_UNCATEGORIZED(__first_ != __last_, "can't move beyond the end of input"); + _LIBCPP_ASSERT_INTERNAL(__first_ != __last_, "can't move beyond the end of input"); // Based on the number of leading 1 bits the number of code units in the // code point can be determined. See @@ -259,7 +259,7 @@ class __code_point_view { _LIBCPP_HIDE_FROM_ABI constexpr bool __at_end() const noexcept { return __first_ == __last_; } [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __consume_result __consume() noexcept { - _LIBCPP_ASSERT_UNCATEGORIZED(__first_ != __last_, "can't move beyond the end of input"); + _LIBCPP_ASSERT_INTERNAL(__first_ != __last_, "can't move beyond the end of input"); char32_t __value = static_cast(*__first_++); if constexpr (sizeof(wchar_t) == 2) { @@ -305,8 +305,8 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool __at_extended_grapheme_cluster_break( // *** Break at the start and end of text, unless the text is empty. *** - _LIBCPP_ASSERT_UNCATEGORIZED(__prev != __property::__sot, "should be handled in the constructor"); // GB1 - _LIBCPP_ASSERT_UNCATEGORIZED(__prev != __property::__eot, "should be handled by our caller"); // GB2 + _LIBCPP_ASSERT_INTERNAL(__prev != __property::__sot, "should be handled in the constructor"); // GB1 + _LIBCPP_ASSERT_INTERNAL(__prev != __property::__eot, "should be handled by our caller"); // GB2 // *** Do not break between a CR and LF. Otherwise, break before and after controls. *** if (__prev == __property::__CR && __next == __property::__LF) // GB3 @@ -401,8 +401,8 @@ class __extended_grapheme_cluster_view { }; _LIBCPP_HIDE_FROM_ABI constexpr __cluster __consume() { - _LIBCPP_ASSERT_UNCATEGORIZED(__next_prop_ != __extended_grapheme_custer_property_boundary::__property::__eot, - "can't move beyond the end of input"); + _LIBCPP_ASSERT_INTERNAL(__next_prop_ != __extended_grapheme_custer_property_boundary::__property::__eot, + "can't move beyond the end of input"); char32_t __code_point = __next_code_point_; if (!__code_point_view_.__at_end()) @@ -459,7 +459,7 @@ class __code_point_view { _LIBCPP_HIDE_FROM_ABI constexpr _Iterator __position() const noexcept { return __first_; } [[nodiscard]] _LIBCPP_HIDE_FROM_ABI constexpr __consume_result __consume() noexcept { - _LIBCPP_ASSERT_UNCATEGORIZED(__first_ != __last_, "can't move beyond the end of input"); + _LIBCPP_ASSERT_INTERNAL(__first_ != __last_, "can't move beyond the end of input"); return {static_cast(*__first_++)}; } diff --git a/libcxx/include/__format/write_escaped.h b/libcxx/include/__format/write_escaped.h index 15141eebc0292..ec1283a173e94 100644 --- a/libcxx/include/__format/write_escaped.h +++ b/libcxx/include/__format/write_escaped.h @@ -71,7 +71,7 @@ __write_escaped_code_unit(basic_string<_CharT>& __str, char32_t __value, const _ char __buffer[8]; to_chars_result __r = std::to_chars(std::begin(__buffer), std::end(__buffer), __value, 16); - _LIBCPP_ASSERT_UNCATEGORIZED(__r.ec == errc(0), "Internal buffer too small"); + _LIBCPP_ASSERT_INTERNAL(__r.ec == errc(0), "Internal buffer too small"); std::ranges::copy(std::begin(__buffer), __r.ptr, __out_it); __str += _CharT('}'); diff --git a/libcxx/include/__hash_table b/libcxx/include/__hash_table index 3cee48ef8538c..4ca49fe42606c 100644 --- a/libcxx/include/__hash_table +++ b/libcxx/include/__hash_table @@ -915,7 +915,10 @@ public: return __bc != 0 ? (float)size() / __bc : 0.f; } _LIBCPP_HIDE_FROM_ABI void max_load_factor(float __mlf) _NOEXCEPT { - _LIBCPP_ASSERT_UNCATEGORIZED(__mlf > 0, "unordered container::max_load_factor(lf) called with lf <= 0"); + // While passing a non-positive load factor is undefined behavior, in practice the result will be benign (the + // call will be equivalent to `max_load_factor(load_factor())`, which is also the case for passing a valid value + // less than the current `load_factor`). + _LIBCPP_ASSERT_PEDANTIC(__mlf > 0, "unordered container::max_load_factor(lf) called with lf <= 0"); max_load_factor() = std::max(__mlf, load_factor()); } diff --git a/libcxx/include/__iterator/advance.h b/libcxx/include/__iterator/advance.h index 64c8d249f78f3..de6df653789e5 100644 --- a/libcxx/include/__iterator/advance.h +++ b/libcxx/include/__iterator/advance.h @@ -65,8 +65,9 @@ template < class _InputIter, _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 void advance(_InputIter& __i, _Distance __orig_n) { typedef typename iterator_traits<_InputIter>::difference_type _Difference; _Difference __n = static_cast<_Difference>(std::__convert_to_integral(__orig_n)); - _LIBCPP_ASSERT_UNCATEGORIZED(__n >= 0 || __has_bidirectional_iterator_category<_InputIter>::value, - "Attempt to advance(it, n) with negative n on a non-bidirectional iterator"); + // Calling `advance` with a negative value on a non-bidirectional iterator in the current implementation. + _LIBCPP_ASSERT_PEDANTIC(__n >= 0 || __has_bidirectional_iterator_category<_InputIter>::value, + "Attempt to advance(it, n) with negative n on a non-bidirectional iterator"); std::__advance(__i, __n, typename iterator_traits<_InputIter>::iterator_category()); } @@ -99,7 +100,8 @@ struct __fn { // Preconditions: If `I` does not model `bidirectional_iterator`, `n` is not negative. template _LIBCPP_HIDE_FROM_ABI constexpr void operator()(_Ip& __i, iter_difference_t<_Ip> __n) const { - _LIBCPP_ASSERT_UNCATEGORIZED( + // Calling `advance` with a negative value on a non-bidirectional iterator in the current implementation. + _LIBCPP_ASSERT_PEDANTIC( __n >= 0 || bidirectional_iterator<_Ip>, "If `n < 0`, then `bidirectional_iterator` must be true."); // If `I` models `random_access_iterator`, equivalent to `i += n`. @@ -149,8 +151,9 @@ struct __fn { template _Sp> _LIBCPP_HIDE_FROM_ABI constexpr iter_difference_t<_Ip> operator()(_Ip& __i, iter_difference_t<_Ip> __n, _Sp __bound_sentinel) const { - _LIBCPP_ASSERT_UNCATEGORIZED((__n >= 0) || (bidirectional_iterator<_Ip> && same_as<_Ip, _Sp>), - "If `n < 0`, then `bidirectional_iterator && same_as` must be true."); + // Calling `advance` with a negative value on a non-bidirectional iterator in the current implementation. + _LIBCPP_ASSERT_PEDANTIC((__n >= 0) || (bidirectional_iterator<_Ip> && same_as<_Ip, _Sp>), + "If `n < 0`, then `bidirectional_iterator && same_as` must be true."); // If `S` and `I` model `sized_sentinel_for`: if constexpr (sized_sentinel_for<_Sp, _Ip>) { // If |n| >= |bound_sentinel - i|, equivalent to `ranges::advance(i, bound_sentinel)`. diff --git a/libcxx/include/__iterator/next.h b/libcxx/include/__iterator/next.h index da60aacfd08d2..2331c004d35ea 100644 --- a/libcxx/include/__iterator/next.h +++ b/libcxx/include/__iterator/next.h @@ -27,11 +27,13 @@ _LIBCPP_BEGIN_NAMESPACE_STD template ::value, int> = 0> inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 _InputIter next(_InputIter __x, typename iterator_traits<_InputIter>::difference_type __n = 1) { - _LIBCPP_ASSERT_UNCATEGORIZED(__n >= 0 || __has_bidirectional_iterator_category<_InputIter>::value, - "Attempt to next(it, n) with negative n on a non-bidirectional iterator"); + // Calling `advance` with a negative value on a non-bidirectional iterator in the current implementation. Note that + // this check duplicates the similar check in `std::advance`. + _LIBCPP_ASSERT_PEDANTIC(__n >= 0 || __has_bidirectional_iterator_category<_InputIter>::value, + "Attempt to next(it, n) with negative n on a non-bidirectional iterator"); - std::advance(__x, __n); - return __x; + std::advance(__x, __n); + return __x; } #if _LIBCPP_STD_VER >= 20 diff --git a/libcxx/include/__iterator/prev.h b/libcxx/include/__iterator/prev.h index 1651942acea9e..cb0e1fcb9b44d 100644 --- a/libcxx/include/__iterator/prev.h +++ b/libcxx/include/__iterator/prev.h @@ -27,8 +27,10 @@ _LIBCPP_BEGIN_NAMESPACE_STD template ::value, int> = 0> inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 _InputIter prev(_InputIter __x, typename iterator_traits<_InputIter>::difference_type __n = 1) { - _LIBCPP_ASSERT_UNCATEGORIZED(__n <= 0 || __has_bidirectional_iterator_category<_InputIter>::value, - "Attempt to prev(it, n) with a positive n on a non-bidirectional iterator"); + // Calling `advance` with a negative value on a non-bidirectional iterator in the current implementation. Note that + // this check duplicates the similar check in `std::advance`. + _LIBCPP_ASSERT_PEDANTIC(__n <= 0 || __has_bidirectional_iterator_category<_InputIter>::value, + "Attempt to prev(it, n) with a positive n on a non-bidirectional iterator"); std::advance(__x, -__n); return __x; } diff --git a/libcxx/include/__random/negative_binomial_distribution.h b/libcxx/include/__random/negative_binomial_distribution.h index 580c74d464404..eed4f511e8719 100644 --- a/libcxx/include/__random/negative_binomial_distribution.h +++ b/libcxx/include/__random/negative_binomial_distribution.h @@ -113,10 +113,9 @@ _IntType negative_binomial_distribution<_IntType>::operator()(_URNG& __urng, con else ++__f; } - _LIBCPP_ASSERT_UNCATEGORIZED( - __f >= 0, - "std::negative_binomial_distribution should never produce negative values. " - "This is almost certainly a signed integer overflow issue on __f."); + _LIBCPP_ASSERT_INTERNAL(__f >= 0, + "std::negative_binomial_distribution should never produce negative values. " + "This is almost certainly a signed integer overflow issue on __f."); return __f; } return poisson_distribution(gamma_distribution(__k, (1 - __p) / __p)(__urng))(__urng); diff --git a/libcxx/include/__ranges/chunk_by_view.h b/libcxx/include/__ranges/chunk_by_view.h index 3ecc018cac9d9..332e12da17110 100644 --- a/libcxx/include/__ranges/chunk_by_view.h +++ b/libcxx/include/__ranges/chunk_by_view.h @@ -66,7 +66,8 @@ class _LIBCPP_ABI_2023_OVERLAPPING_SUBOBJECT_FIX_TAG chunk_by_view class __iterator; _LIBCPP_HIDE_FROM_ABI constexpr iterator_t<_View> __find_next(iterator_t<_View> __current) { - _LIBCPP_ASSERT_UNCATEGORIZED( + // Note: this duplicates a check in `optional` but provides a better error message. + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( __pred_.__has_value(), "Trying to call __find_next() on a chunk_by_view that does not have a valid predicate."); auto __reversed_pred = [this](_Tp&& __x, _Up&& __y) -> bool { return !std::invoke(*__pred_, std::forward<_Tp>(__x), std::forward<_Up>(__y)); @@ -78,9 +79,10 @@ class _LIBCPP_ABI_2023_OVERLAPPING_SUBOBJECT_FIX_TAG chunk_by_view _LIBCPP_HIDE_FROM_ABI constexpr iterator_t<_View> __find_prev(iterator_t<_View> __current) requires bidirectional_range<_View> { - _LIBCPP_ASSERT_UNCATEGORIZED( - __current != ranges::begin(__base_), "Trying to call __find_prev() on a begin iterator."); - _LIBCPP_ASSERT_UNCATEGORIZED( + // Attempting to increment an end iterator is a no-op (`__find_next` would return the same argument given to it). + _LIBCPP_ASSERT_PEDANTIC(__current != ranges::begin(__base_), "Trying to call __find_prev() on a begin iterator."); + // Note: this duplicates a check in `optional` but provides a better error message. + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( __pred_.__has_value(), "Trying to call __find_prev() on a chunk_by_view that does not have a valid predicate."); auto __first = ranges::begin(__base_); @@ -110,7 +112,8 @@ class _LIBCPP_ABI_2023_OVERLAPPING_SUBOBJECT_FIX_TAG chunk_by_view _LIBCPP_HIDE_FROM_ABI constexpr const _Pred& pred() const { return *__pred_; } _LIBCPP_HIDE_FROM_ABI constexpr __iterator begin() { - _LIBCPP_ASSERT_UNCATEGORIZED( + // Note: this duplicates a check in `optional` but provides a better error message. + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( __pred_.__has_value(), "Trying to call begin() on a chunk_by_view that does not have a valid predicate."); auto __first = ranges::begin(__base_); @@ -154,12 +157,15 @@ class chunk_by_view<_View, _Pred>::__iterator { _LIBCPP_HIDE_FROM_ABI __iterator() = default; _LIBCPP_HIDE_FROM_ABI constexpr value_type operator*() const { - _LIBCPP_ASSERT_UNCATEGORIZED(__current_ != __next_, "Trying to dereference past-the-end chunk_by_view iterator."); + // If the iterator is at end, this would return an empty range which can be checked by the calling code and doesn't + // necessarily lead to a bad access. + _LIBCPP_ASSERT_PEDANTIC(__current_ != __next_, "Trying to dereference past-the-end chunk_by_view iterator."); return {__current_, __next_}; } _LIBCPP_HIDE_FROM_ABI constexpr __iterator& operator++() { - _LIBCPP_ASSERT_UNCATEGORIZED(__current_ != __next_, "Trying to increment past end chunk_by_view iterator."); + // Attempting to increment an end iterator is a no-op (`__find_next` would return the same argument given to it). + _LIBCPP_ASSERT_PEDANTIC(__current_ != __next_, "Trying to increment past end chunk_by_view iterator."); __current_ = __next_; __next_ = __parent_->__find_next(__current_); return *this; diff --git a/libcxx/include/__ranges/drop_while_view.h b/libcxx/include/__ranges/drop_while_view.h index eb3783eb42f14..b367f735c1417 100644 --- a/libcxx/include/__ranges/drop_while_view.h +++ b/libcxx/include/__ranges/drop_while_view.h @@ -66,7 +66,8 @@ class _LIBCPP_ABI_2023_OVERLAPPING_SUBOBJECT_FIX_TAG drop_while_view _LIBCPP_HIDE_FROM_ABI constexpr const _Pred& pred() const { return *__pred_; } _LIBCPP_HIDE_FROM_ABI constexpr auto begin() { - _LIBCPP_ASSERT_UNCATEGORIZED( + // Note: this duplicates a check in `optional` but provides a better error message. + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( __pred_.__has_value(), "drop_while_view needs to have a non-empty predicate before calling begin() -- did a previous " "assignment to this drop_while_view fail?"); diff --git a/libcxx/include/__ranges/filter_view.h b/libcxx/include/__ranges/filter_view.h index 868ad128e8944..7369369950a61 100644 --- a/libcxx/include/__ranges/filter_view.h +++ b/libcxx/include/__ranges/filter_view.h @@ -83,8 +83,9 @@ class _LIBCPP_ABI_2023_OVERLAPPING_SUBOBJECT_FIX_TAG filter_view : public view_i _LIBCPP_HIDE_FROM_ABI constexpr _Pred const& pred() const { return *__pred_; } _LIBCPP_HIDE_FROM_ABI constexpr __iterator begin() { - _LIBCPP_ASSERT_UNCATEGORIZED( - __pred_.__has_value(), "Trying to call begin() on a filter_view that does not have a valid predicate."); + // Note: this duplicates a check in `optional` but provides a better error message. + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __pred_.__has_value(), "Trying to call begin() on a filter_view that does not have a valid predicate."); if constexpr (_UseCache) { if (!__cached_begin_.__has_value()) { __cached_begin_.__emplace(ranges::find_if(__base_, std::ref(*__pred_))); diff --git a/libcxx/include/__thread/thread.h b/libcxx/include/__thread/thread.h index f3300752ac9e7..463bbd6772552 100644 --- a/libcxx/include/__thread/thread.h +++ b/libcxx/include/__thread/thread.h @@ -104,7 +104,7 @@ __thread_specific_ptr<_Tp>::~__thread_specific_ptr() { template void __thread_specific_ptr<_Tp>::set_pointer(pointer __p) { - _LIBCPP_ASSERT_UNCATEGORIZED(get() == nullptr, "Attempting to overwrite thread local data"); + _LIBCPP_ASSERT_INTERNAL(get() == nullptr, "Attempting to overwrite thread local data"); std::__libcpp_tls_set(__key_, __p); } diff --git a/libcxx/include/__utility/exception_guard.h b/libcxx/include/__utility/exception_guard.h index 389fca6c71012..8d90dfd5f1907 100644 --- a/libcxx/include/__utility/exception_guard.h +++ b/libcxx/include/__utility/exception_guard.h @@ -115,7 +115,7 @@ struct __exception_guard_noexceptions { } _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX20 _LIBCPP_NODEBUG ~__exception_guard_noexceptions() { - _LIBCPP_ASSERT_UNCATEGORIZED(__completed_, "__exception_guard not completed with exceptions disabled"); + _LIBCPP_ASSERT_INTERNAL(__completed_, "__exception_guard not completed with exceptions disabled"); } private: diff --git a/libcxx/include/__utility/unreachable.h b/libcxx/include/__utility/unreachable.h index 49334decc8f68..d833f74c2e4f1 100644 --- a/libcxx/include/__utility/unreachable.h +++ b/libcxx/include/__utility/unreachable.h @@ -19,7 +19,7 @@ _LIBCPP_BEGIN_NAMESPACE_STD _LIBCPP_NORETURN _LIBCPP_HIDE_FROM_ABI inline void __libcpp_unreachable() { - _LIBCPP_ASSERT_UNCATEGORIZED(false, "std::unreachable() was reached"); + _LIBCPP_ASSERT_INTERNAL(false, "std::unreachable() was reached"); __builtin_unreachable(); } diff --git a/libcxx/include/print b/libcxx/include/print index 0f8e73f8eb5c7..b866899b3b4ce 100644 --- a/libcxx/include/print +++ b/libcxx/include/print @@ -122,6 +122,8 @@ _LIBCPP_HIDE_FROM_ABI constexpr void __encode(_OutIt&, char32_t) = delete; template requires __utf16_code_unit> _LIBCPP_HIDE_FROM_ABI constexpr void __encode(_OutIt& __out_it, char32_t __value) { + // From the Standard: "if `out` contains invalid code units, the behavior is undefined and implementations are + // encouraged to diagnose it". _LIBCPP_ASSERT_UNCATEGORIZED(__is_scalar_value(__value), "an invalid unicode scalar value results in invalid UTF-16"); if (__value < 0x10000) { @@ -137,6 +139,8 @@ _LIBCPP_HIDE_FROM_ABI constexpr void __encode(_OutIt& __out_it, char32_t __value template requires __utf32_code_unit> _LIBCPP_HIDE_FROM_ABI constexpr void __encode(_OutIt& __out_it, char32_t __value) { + // From the Standard: "if `out` contains invalid code units, the behavior is undefined and implementations are + // encouraged to diagnose it". _LIBCPP_ASSERT_UNCATEGORIZED(__is_scalar_value(__value), "an invalid unicode scalar value results in invalid UTF-32"); *__out_it++ = __value; } @@ -214,7 +218,7 @@ _LIBCPP_HIDE_FROM_ABI inline bool __is_terminal(FILE* __stream) { template // TODO PRINT template or availability markup fires too eagerly (http://llvm.org/PR61563). _LIBCPP_HIDE_FROM_ABI inline void __vprint_nonunicode(FILE* __stream, string_view __fmt, format_args __args, bool __write_nl) { - _LIBCPP_ASSERT_UNCATEGORIZED(__stream, "__stream is a valid pointer to an output C stream"); + _LIBCPP_ASSERT_NON_NULL(__stream, "__stream must be a valid pointer to an output C stream"); string __str = std::vformat(__fmt, __args); if (__write_nl) __str.push_back('\n'); @@ -290,7 +294,7 @@ __vprint_unicode([[maybe_unused]] FILE* __stream, [[maybe_unused]] string_view __fmt, [[maybe_unused]] format_args __args, [[maybe_unused]] bool __write_nl) { - _LIBCPP_ASSERT_UNCATEGORIZED(__stream, "__stream is a valid pointer to an output C stream"); + _LIBCPP_ASSERT_NON_NULL(__stream, "__stream must be a valid pointer to an output C stream"); // [print.fun] // 7 - Effects: If stream refers to a terminal capable of displaying diff --git a/libcxx/include/set b/libcxx/include/set index 08677a94054fe..55ba8f8208be1 100644 --- a/libcxx/include/set +++ b/libcxx/include/set @@ -769,13 +769,13 @@ public: #if _LIBCPP_STD_VER >= 17 _LIBCPP_HIDE_FROM_ABI insert_return_type insert(node_type&& __nh) { - _LIBCPP_ASSERT_UNCATEGORIZED(__nh.empty() || __nh.get_allocator() == get_allocator(), - "node_type with incompatible allocator passed to set::insert()"); + _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(__nh.empty() || __nh.get_allocator() == get_allocator(), + "node_type with incompatible allocator passed to set::insert()"); return __tree_.template __node_handle_insert_unique< node_type, insert_return_type>(std::move(__nh)); } _LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __hint, node_type&& __nh) { - _LIBCPP_ASSERT_UNCATEGORIZED(__nh.empty() || __nh.get_allocator() == get_allocator(), - "node_type with incompatible allocator passed to set::insert()"); + _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(__nh.empty() || __nh.get_allocator() == get_allocator(), + "node_type with incompatible allocator passed to set::insert()"); return __tree_.template __node_handle_insert_unique(__hint, std::move(__nh)); } _LIBCPP_HIDE_FROM_ABI node_type extract(key_type const& __key) { @@ -786,25 +786,25 @@ public: } template _LIBCPP_HIDE_FROM_ABI void merge(set& __source) { - _LIBCPP_ASSERT_UNCATEGORIZED( + _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR( __source.get_allocator() == get_allocator(), "merging container with incompatible allocator"); __tree_.__node_handle_merge_unique(__source.__tree_); } template _LIBCPP_HIDE_FROM_ABI void merge(set&& __source) { - _LIBCPP_ASSERT_UNCATEGORIZED( + _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR( __source.get_allocator() == get_allocator(), "merging container with incompatible allocator"); __tree_.__node_handle_merge_unique(__source.__tree_); } template _LIBCPP_HIDE_FROM_ABI void merge(multiset& __source) { - _LIBCPP_ASSERT_UNCATEGORIZED( + _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR( __source.get_allocator() == get_allocator(), "merging container with incompatible allocator"); __tree_.__node_handle_merge_unique(__source.__tree_); } template _LIBCPP_HIDE_FROM_ABI void merge(multiset&& __source) { - _LIBCPP_ASSERT_UNCATEGORIZED( + _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR( __source.get_allocator() == get_allocator(), "merging container with incompatible allocator"); __tree_.__node_handle_merge_unique(__source.__tree_); } @@ -1227,13 +1227,13 @@ public: #if _LIBCPP_STD_VER >= 17 _LIBCPP_HIDE_FROM_ABI iterator insert(node_type&& __nh) { - _LIBCPP_ASSERT_UNCATEGORIZED(__nh.empty() || __nh.get_allocator() == get_allocator(), - "node_type with incompatible allocator passed to multiset::insert()"); + _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(__nh.empty() || __nh.get_allocator() == get_allocator(), + "node_type with incompatible allocator passed to multiset::insert()"); return __tree_.template __node_handle_insert_multi(std::move(__nh)); } _LIBCPP_HIDE_FROM_ABI iterator insert(const_iterator __hint, node_type&& __nh) { - _LIBCPP_ASSERT_UNCATEGORIZED(__nh.empty() || __nh.get_allocator() == get_allocator(), - "node_type with incompatible allocator passed to multiset::insert()"); + _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(__nh.empty() || __nh.get_allocator() == get_allocator(), + "node_type with incompatible allocator passed to multiset::insert()"); return __tree_.template __node_handle_insert_multi(__hint, std::move(__nh)); } _LIBCPP_HIDE_FROM_ABI node_type extract(key_type const& __key) { @@ -1244,25 +1244,25 @@ public: } template _LIBCPP_HIDE_FROM_ABI void merge(multiset& __source) { - _LIBCPP_ASSERT_UNCATEGORIZED( + _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR( __source.get_allocator() == get_allocator(), "merging container with incompatible allocator"); __tree_.__node_handle_merge_multi(__source.__tree_); } template _LIBCPP_HIDE_FROM_ABI void merge(multiset&& __source) { - _LIBCPP_ASSERT_UNCATEGORIZED( + _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR( __source.get_allocator() == get_allocator(), "merging container with incompatible allocator"); __tree_.__node_handle_merge_multi(__source.__tree_); } template _LIBCPP_HIDE_FROM_ABI void merge(set& __source) { - _LIBCPP_ASSERT_UNCATEGORIZED( + _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR( __source.get_allocator() == get_allocator(), "merging container with incompatible allocator"); __tree_.__node_handle_merge_multi(__source.__tree_); } template _LIBCPP_HIDE_FROM_ABI void merge(set&& __source) { - _LIBCPP_ASSERT_UNCATEGORIZED( + _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR( __source.get_allocator() == get_allocator(), "merging container with incompatible allocator"); __tree_.__node_handle_merge_multi(__source.__tree_); } diff --git a/libcxx/src/filesystem/error.h b/libcxx/src/filesystem/error.h index b86f4ed41071e..572cc73292a19 100644 --- a/libcxx/src/filesystem/error.h +++ b/libcxx/src/filesystem/error.h @@ -99,7 +99,7 @@ inline errc __win_err_to_errc(int err) { #endif // _LIBCPP_WIN32API inline error_code capture_errno() { - _LIBCPP_ASSERT_UNCATEGORIZED(errno != 0, "Expected errno to be non-zero"); + _LIBCPP_ASSERT_INTERNAL(errno != 0, "Expected errno to be non-zero"); return error_code(errno, generic_category()); } diff --git a/libcxx/src/filesystem/format_string.h b/libcxx/src/filesystem/format_string.h index 215d42421b2a0..a44def86f53e9 100644 --- a/libcxx/src/filesystem/format_string.h +++ b/libcxx/src/filesystem/format_string.h @@ -47,7 +47,7 @@ inline _LIBCPP_ATTRIBUTE_FORMAT(__printf__, 1, 0) string vformat_string(const ch size_t size_with_null = static_cast(ret) + 1; result.__resize_default_init(size_with_null - 1); ret = ::vsnprintf(&result[0], size_with_null, msg, ap); - _LIBCPP_ASSERT_UNCATEGORIZED(static_cast(ret) == (size_with_null - 1), "TODO"); + _LIBCPP_ASSERT_INTERNAL(static_cast(ret) == (size_with_null - 1), "TODO"); } return result; } diff --git a/libcxx/src/filesystem/posix_compat.h b/libcxx/src/filesystem/posix_compat.h index ec2de49960be1..760cdb65dae1d 100644 --- a/libcxx/src/filesystem/posix_compat.h +++ b/libcxx/src/filesystem/posix_compat.h @@ -318,8 +318,8 @@ inline int statvfs(const wchar_t* p, StatVFS* buf) { inline wchar_t* getcwd([[maybe_unused]] wchar_t* in_buf, [[maybe_unused]] size_t in_size) { // Only expected to be used with us allocating the buffer. - _LIBCPP_ASSERT_UNCATEGORIZED(in_buf == nullptr, "Windows getcwd() assumes in_buf==nullptr"); - _LIBCPP_ASSERT_UNCATEGORIZED(in_size == 0, "Windows getcwd() assumes in_size==0"); + _LIBCPP_ASSERT_INTERNAL(in_buf == nullptr, "Windows getcwd() assumes in_buf==nullptr"); + _LIBCPP_ASSERT_INTERNAL(in_size == 0, "Windows getcwd() assumes in_size==0"); size_t buff_size = MAX_PATH + 10; std::unique_ptr buff(static_cast(malloc(buff_size * sizeof(wchar_t))), &::free); @@ -338,7 +338,7 @@ inline wchar_t* getcwd([[maybe_unused]] wchar_t* in_buf, [[maybe_unused]] size_t inline wchar_t* realpath(const wchar_t* path, [[maybe_unused]] wchar_t* resolved_name) { // Only expected to be used with us allocating the buffer. - _LIBCPP_ASSERT_UNCATEGORIZED(resolved_name == nullptr, "Windows realpath() assumes a null resolved_name"); + _LIBCPP_ASSERT_INTERNAL(resolved_name == nullptr, "Windows realpath() assumes a null resolved_name"); WinHandle h(path, FILE_READ_ATTRIBUTES, 0); if (!h) { diff --git a/libcxx/src/include/to_chars_floating_point.h b/libcxx/src/include/to_chars_floating_point.h index 3110bc20e1600..e4715d10d97da 100644 --- a/libcxx/src/include/to_chars_floating_point.h +++ b/libcxx/src/include/to_chars_floating_point.h @@ -269,7 +269,7 @@ to_chars_result _Floating_to_chars_hex_precision( // * Print the leading hexit, then mask it away. { const uint32_t _Nibble = static_cast(_Adjusted_mantissa >> _Adjusted_explicit_bits); - _LIBCPP_ASSERT_UNCATEGORIZED(_Nibble < 3, ""); + _LIBCPP_ASSERT_INTERNAL(_Nibble < 3, ""); const char _Leading_hexit = static_cast('0' + _Nibble); *_First++ = _Leading_hexit; @@ -288,12 +288,12 @@ to_chars_result _Floating_to_chars_hex_precision( int32_t _Number_of_bits_remaining = _Adjusted_explicit_bits; // 24 for float, 52 for double for (;;) { - _LIBCPP_ASSERT_UNCATEGORIZED(_Number_of_bits_remaining >= 4, ""); - _LIBCPP_ASSERT_UNCATEGORIZED(_Number_of_bits_remaining % 4 == 0, ""); + _LIBCPP_ASSERT_INTERNAL(_Number_of_bits_remaining >= 4, ""); + _LIBCPP_ASSERT_INTERNAL(_Number_of_bits_remaining % 4 == 0, ""); _Number_of_bits_remaining -= 4; const uint32_t _Nibble = static_cast(_Adjusted_mantissa >> _Number_of_bits_remaining); - _LIBCPP_ASSERT_UNCATEGORIZED(_Nibble < 16, ""); + _LIBCPP_ASSERT_INTERNAL(_Nibble < 16, ""); const char _Hexit = __itoa::_Charconv_digits[_Nibble]; *_First++ = _Hexit; @@ -415,12 +415,12 @@ to_chars_result _Floating_to_chars_hex_shortest( // '0' hexits, the same condition works (as we print the final hexit and mask it away); we don't need to test // _Number_of_bits_remaining. do { - _LIBCPP_ASSERT_UNCATEGORIZED(_Number_of_bits_remaining >= 4, ""); - _LIBCPP_ASSERT_UNCATEGORIZED(_Number_of_bits_remaining % 4 == 0, ""); + _LIBCPP_ASSERT_INTERNAL(_Number_of_bits_remaining >= 4, ""); + _LIBCPP_ASSERT_INTERNAL(_Number_of_bits_remaining % 4 == 0, ""); _Number_of_bits_remaining -= 4; const uint32_t _Nibble = static_cast(_Adjusted_mantissa >> _Number_of_bits_remaining); - _LIBCPP_ASSERT_UNCATEGORIZED(_Nibble < 16, ""); + _LIBCPP_ASSERT_INTERNAL(_Nibble < 16, ""); const char _Hexit = __itoa::_Charconv_digits[_Nibble]; if (_First == _Last) { @@ -940,13 +940,13 @@ to_chars_result _Floating_to_chars_general_precision( _Effective_precision = std::min(_Precision - (_Scientific_exponent_X + 1), _Max_fixed_precision); const to_chars_result _Buf_result = _Floating_to_chars_fixed_precision(_Buffer, std::end(_Buffer), _Value, _Effective_precision); - _LIBCPP_ASSERT_UNCATEGORIZED(_Buf_result.ec == errc{}, ""); + _LIBCPP_ASSERT_INTERNAL(_Buf_result.ec == errc{}, ""); _Significand_last = _Buf_result.ptr; } else { _Effective_precision = std::min(_Precision - 1, _Max_scientific_precision); const to_chars_result _Buf_result = _Floating_to_chars_scientific_precision(_Buffer, std::end(_Buffer), _Value, _Effective_precision); - _LIBCPP_ASSERT_UNCATEGORIZED(_Buf_result.ec == errc{}, ""); + _LIBCPP_ASSERT_INTERNAL(_Buf_result.ec == errc{}, ""); _Significand_last = std::find(_Buffer, _Buf_result.ptr, 'e'); _Exponent_first = _Significand_last; _Exponent_last = _Buf_result.ptr; @@ -992,7 +992,7 @@ to_chars_result _Floating_to_chars( char* _First, char* const _Last, _Floating _Value, const chars_format _Fmt, const int _Precision) noexcept { if constexpr (_Overload == _Floating_to_chars_overload::_Plain) { - _LIBCPP_ASSERT_UNCATEGORIZED(_Fmt == chars_format{}, ""); // plain overload must pass chars_format{} internally + _LIBCPP_ASSERT_INTERNAL(_Fmt == chars_format{}, ""); // plain overload must pass chars_format{} internally } else { _LIBCPP_ASSERT_UNCATEGORIZED(_Fmt == chars_format::general || _Fmt == chars_format::scientific || _Fmt == chars_format::fixed || _Fmt == chars_format::hex, diff --git a/libcxx/src/memory_resource.cpp b/libcxx/src/memory_resource.cpp index afd1b892086da..42c366893f736 100644 --- a/libcxx/src/memory_resource.cpp +++ b/libcxx/src/memory_resource.cpp @@ -230,7 +230,7 @@ class unsynchronized_pool_resource::__fixed_pool { } void* __allocate_in_new_chunk(memory_resource* upstream, size_t block_size, size_t chunk_size) { - _LIBCPP_ASSERT_UNCATEGORIZED(chunk_size % block_size == 0, ""); + _LIBCPP_ASSERT_INTERNAL(chunk_size % block_size == 0, ""); static_assert(__default_alignment >= alignof(std::max_align_t), ""); static_assert(__default_alignment >= alignof(__chunk_footer), ""); static_assert(__default_alignment >= alignof(__vacancy_header), ""); diff --git a/libcxx/src/strstream.cpp b/libcxx/src/strstream.cpp index a9b5989ec495c..70374191c6aba 100644 --- a/libcxx/src/strstream.cpp +++ b/libcxx/src/strstream.cpp @@ -120,7 +120,7 @@ strstreambuf::int_type strstreambuf::overflow(int_type __c) { if (buf == nullptr) return int_type(EOF); if (old_size != 0) { - _LIBCPP_ASSERT_UNCATEGORIZED(eback(), "overflow copying from NULL"); + _LIBCPP_ASSERT_INTERNAL(eback(), "strstreambuf::overflow reallocating but the get area is a null pointer"); memcpy(buf, eback(), static_cast(old_size)); } ptrdiff_t ninp = gptr() - eback(); diff --git a/libcxx/src/system_error.cpp b/libcxx/src/system_error.cpp index 034b73c5480a6..f518b480a2782 100644 --- a/libcxx/src/system_error.cpp +++ b/libcxx/src/system_error.cpp @@ -68,7 +68,7 @@ __attribute__((unused)) const char* handle_strerror_r_return(int strerror_return if (new_errno == EINVAL) return ""; - _LIBCPP_ASSERT_UNCATEGORIZED(new_errno == ERANGE, "unexpected error from ::strerror_r"); + _LIBCPP_ASSERT_INTERNAL(new_errno == ERANGE, "unexpected error from ::strerror_r"); // FIXME maybe? 'strerror_buff_size' is likely to exceed the // maximum error size so ERANGE shouldn't be returned. std::abort(); From 24d8122d35726c0b323c7def78cc29961c8b3955 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Wed, 20 Dec 2023 22:05:56 -0800 Subject: [PATCH 06/10] Classify a few more assertions (mostly in ```). --- libcxx/include/__config | 2 +- .../include/__filesystem/directory_iterator.h | 3 ++- libcxx/include/regex | 23 +++++++++++++------ 3 files changed, 19 insertions(+), 9 deletions(-) diff --git a/libcxx/include/__config b/libcxx/include/__config index 2553ad48667fc..5a2b6586bbd8e 100644 --- a/libcxx/include/__config +++ b/libcxx/include/__config @@ -343,8 +343,8 @@ _LIBCPP_HARDENING_MODE_DEBUG # define _LIBCPP_ASSERT_NON_OVERLAPPING_RANGES(expression, message) _LIBCPP_ASSERT(expression, message) # define _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(expression, message) _LIBCPP_ASSERT(expression, message) # define _LIBCPP_ASSERT_UNCATEGORIZED(expression, message) _LIBCPP_ASSERT(expression, message) +# define _LIBCPP_ASSERT_PEDANTIC(expression, message) _LIBCPP_ASSERT(expression, message) // Disabled checks. -# define _LIBCPP_ASSERT_PEDANTIC(expression, message) _LIBCPP_ASSUME(expression) # define _LIBCPP_ASSERT_INTERNAL(expression, message) _LIBCPP_ASSUME(expression) // Debug hardening mode checks. diff --git a/libcxx/include/__filesystem/directory_iterator.h b/libcxx/include/__filesystem/directory_iterator.h index 29bd8da6caa46..5287a4d8b055f 100644 --- a/libcxx/include/__filesystem/directory_iterator.h +++ b/libcxx/include/__filesystem/directory_iterator.h @@ -73,7 +73,8 @@ class directory_iterator { _LIBCPP_HIDE_FROM_ABI ~directory_iterator() = default; _LIBCPP_HIDE_FROM_ABI const directory_entry& operator*() const { - _LIBCPP_ASSERT_UNCATEGORIZED(__imp_, "The end iterator cannot be dereferenced"); + // Note: this check duplicates a check in `__dereference()`. + _LIBCPP_ASSERT_NON_NULL(__imp_, "The end iterator cannot be dereferenced"); return __dereference(); } diff --git a/libcxx/include/regex b/libcxx/include/regex index 061194cb2eba9..b575a267583b5 100644 --- a/libcxx/include/regex +++ b/libcxx/include/regex @@ -4587,28 +4587,36 @@ public: // element access: _LIBCPP_HIDE_FROM_ABI difference_type length(size_type __sub = 0) const { - _LIBCPP_ASSERT_UNCATEGORIZED(ready(), "match_results::length() called when not ready"); + // If the match results are not ready, this will return `0`. + _LIBCPP_ASSERT_PEDANTIC(ready(), "match_results::length() called when not ready"); return (*this)[__sub].length(); } _LIBCPP_HIDE_FROM_ABI difference_type position(size_type __sub = 0) const { - _LIBCPP_ASSERT_UNCATEGORIZED(ready(), "match_results::position() called when not ready"); + // If the match results are not ready, this will return the result of subtracting two default-constructed iterators + // (which is typically a well-defined operation). + _LIBCPP_ASSERT_PEDANTIC(ready(), "match_results::position() called when not ready"); return std::distance(__position_start_, (*this)[__sub].first); } _LIBCPP_HIDE_FROM_ABI string_type str(size_type __sub = 0) const { - _LIBCPP_ASSERT_UNCATEGORIZED(ready(), "match_results::str() called when not ready"); + // If the match results are not ready, this will return an empty string. + _LIBCPP_ASSERT_PEDANTIC(ready(), "match_results::str() called when not ready"); return (*this)[__sub].str(); } _LIBCPP_HIDE_FROM_ABI const_reference operator[](size_type __n) const { - _LIBCPP_ASSERT_UNCATEGORIZED(ready(), "match_results::operator[]() called when not ready"); + // If the match results are not ready, this call will be equivalent to calling this function with `__n >= size()`, + // returning an empty subrange. + _LIBCPP_ASSERT_PEDANTIC(ready(), "match_results::operator[]() called when not ready"); return __n < __matches_.size() ? __matches_[__n] : __unmatched_; } _LIBCPP_HIDE_FROM_ABI const_reference prefix() const { - _LIBCPP_ASSERT_UNCATEGORIZED(ready(), "match_results::prefix() called when not ready"); + // If the match results are not ready, this will return a default-constructed empty `__suffix_`. + _LIBCPP_ASSERT_PEDANTIC(ready(), "match_results::prefix() called when not ready"); return __prefix_; } _LIBCPP_HIDE_FROM_ABI const_reference suffix() const { - _LIBCPP_ASSERT_UNCATEGORIZED(ready(), "match_results::suffix() called when not ready"); + // If the match results are not ready, this will return a default-constructed empty `__suffix_`. + _LIBCPP_ASSERT_PEDANTIC(ready(), "match_results::suffix() called when not ready"); return __suffix_; } @@ -4722,7 +4730,8 @@ _OutputIter match_results<_BidirectionalIterator, _Allocator>::format( const char_type* __fmt_first, const char_type* __fmt_last, regex_constants::match_flag_type __flags) const { - _LIBCPP_ASSERT_UNCATEGORIZED(ready(), "match_results::format() called when not ready"); + // Note: this duplicates a check in `vector::operator[]` but provides a better error message. + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS(ready(), "match_results::format() called when not ready"); if (__flags & regex_constants::format_sed) { for (; __fmt_first != __fmt_last; ++__fmt_first) { if (*__fmt_first == '&') From cc436dfe85f1be48e8980799a19f10fc5d251ad2 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Thu, 4 Jan 2024 18:57:38 -0800 Subject: [PATCH 07/10] Address feedback --- libcxx/include/__charconv/to_chars_base_10.h | 2 +- libcxx/include/__chrono/parser_std_format_spec.h | 7 +++---- libcxx/include/__iterator/advance.h | 6 +++--- libcxx/include/__ranges/chunk_by_view.h | 2 +- libcxx/include/print | 8 ++++---- 5 files changed, 12 insertions(+), 13 deletions(-) diff --git a/libcxx/include/__charconv/to_chars_base_10.h b/libcxx/include/__charconv/to_chars_base_10.h index c1a5d4f9d5d52..0dee351521f9c 100644 --- a/libcxx/include/__charconv/to_chars_base_10.h +++ b/libcxx/include/__charconv/to_chars_base_10.h @@ -139,7 +139,7 @@ _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI inline __uint128_t __pow_10( _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI inline char* __base_10_u128(char* __buffer, __uint128_t __value) noexcept { _LIBCPP_ASSERT_INTERNAL( - __value > numeric_limits::max(), "The optimizations for this algorithm fail when this isn't true."); + __value > numeric_limits::max(), "The optimizations for this algorithm fails when this isn't true."); // Unlike the 64 to 32 bit case the 128 bit case the "upper half" can't be // stored in the "lower half". Instead we first need to handle the top most diff --git a/libcxx/include/__chrono/parser_std_format_spec.h b/libcxx/include/__chrono/parser_std_format_spec.h index 86c9712ba487d..785bbae198e46 100644 --- a/libcxx/include/__chrono/parser_std_format_spec.h +++ b/libcxx/include/__chrono/parser_std_format_spec.h @@ -160,10 +160,9 @@ class _LIBCPP_TEMPLATE_VIS __parser_chrono { private: _LIBCPP_HIDE_FROM_ABI constexpr _ConstIterator __parse_chrono_specs(_ConstIterator __begin, _ConstIterator __end, __flags __flags) { - _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( - __begin != __end, - "When called with an empty input the function will cause " - "undefined behavior by evaluating data not in the input"); + _LIBCPP_ASSERT_INTERNAL(__begin != __end, + "When called with an empty input the function will cause " + "undefined behavior by evaluating data not in the input"); if (*__begin != _CharT('%') && *__begin != _CharT('}')) std::__throw_format_error("The format specifier expects a '%' or a '}'"); diff --git a/libcxx/include/__iterator/advance.h b/libcxx/include/__iterator/advance.h index de6df653789e5..13ab4525d2eac 100644 --- a/libcxx/include/__iterator/advance.h +++ b/libcxx/include/__iterator/advance.h @@ -65,7 +65,7 @@ template < class _InputIter, _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 void advance(_InputIter& __i, _Distance __orig_n) { typedef typename iterator_traits<_InputIter>::difference_type _Difference; _Difference __n = static_cast<_Difference>(std::__convert_to_integral(__orig_n)); - // Calling `advance` with a negative value on a non-bidirectional iterator in the current implementation. + // Calling `advance` with a negative value on a non-bidirectional iterator is a no-op in the current implementation. _LIBCPP_ASSERT_PEDANTIC(__n >= 0 || __has_bidirectional_iterator_category<_InputIter>::value, "Attempt to advance(it, n) with negative n on a non-bidirectional iterator"); std::__advance(__i, __n, typename iterator_traits<_InputIter>::iterator_category()); @@ -100,7 +100,7 @@ struct __fn { // Preconditions: If `I` does not model `bidirectional_iterator`, `n` is not negative. template _LIBCPP_HIDE_FROM_ABI constexpr void operator()(_Ip& __i, iter_difference_t<_Ip> __n) const { - // Calling `advance` with a negative value on a non-bidirectional iterator in the current implementation. + // Calling `advance` with a negative value on a non-bidirectional iterator is a no-op in the current implementation. _LIBCPP_ASSERT_PEDANTIC( __n >= 0 || bidirectional_iterator<_Ip>, "If `n < 0`, then `bidirectional_iterator` must be true."); @@ -151,7 +151,7 @@ struct __fn { template _Sp> _LIBCPP_HIDE_FROM_ABI constexpr iter_difference_t<_Ip> operator()(_Ip& __i, iter_difference_t<_Ip> __n, _Sp __bound_sentinel) const { - // Calling `advance` with a negative value on a non-bidirectional iterator in the current implementation. + // Calling `advance` with a negative value on a non-bidirectional iterator is a no-op in the current implementation. _LIBCPP_ASSERT_PEDANTIC((__n >= 0) || (bidirectional_iterator<_Ip> && same_as<_Ip, _Sp>), "If `n < 0`, then `bidirectional_iterator && same_as` must be true."); // If `S` and `I` model `sized_sentinel_for`: diff --git a/libcxx/include/__ranges/chunk_by_view.h b/libcxx/include/__ranges/chunk_by_view.h index 332e12da17110..c5b3240a7d0be 100644 --- a/libcxx/include/__ranges/chunk_by_view.h +++ b/libcxx/include/__ranges/chunk_by_view.h @@ -79,7 +79,7 @@ class _LIBCPP_ABI_2023_OVERLAPPING_SUBOBJECT_FIX_TAG chunk_by_view _LIBCPP_HIDE_FROM_ABI constexpr iterator_t<_View> __find_prev(iterator_t<_View> __current) requires bidirectional_range<_View> { - // Attempting to increment an end iterator is a no-op (`__find_next` would return the same argument given to it). + // Attempting to decrement a begin iterator is a no-op (`__find_prev` would return the same argument given to it). _LIBCPP_ASSERT_PEDANTIC(__current != ranges::begin(__base_), "Trying to call __find_prev() on a begin iterator."); // Note: this duplicates a check in `optional` but provides a better error message. _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( diff --git a/libcxx/include/print b/libcxx/include/print index b866899b3b4ce..5e00fc87f47e9 100644 --- a/libcxx/include/print +++ b/libcxx/include/print @@ -122,8 +122,8 @@ _LIBCPP_HIDE_FROM_ABI constexpr void __encode(_OutIt&, char32_t) = delete; template requires __utf16_code_unit> _LIBCPP_HIDE_FROM_ABI constexpr void __encode(_OutIt& __out_it, char32_t __value) { - // From the Standard: "if `out` contains invalid code units, the behavior is undefined and implementations are - // encouraged to diagnose it". + // [print.fun]/7 : "if `out` contains invalid code units, the behavior is undefined and implementations are encouraged + // to diagnose it". _LIBCPP_ASSERT_UNCATEGORIZED(__is_scalar_value(__value), "an invalid unicode scalar value results in invalid UTF-16"); if (__value < 0x10000) { @@ -139,8 +139,8 @@ _LIBCPP_HIDE_FROM_ABI constexpr void __encode(_OutIt& __out_it, char32_t __value template requires __utf32_code_unit> _LIBCPP_HIDE_FROM_ABI constexpr void __encode(_OutIt& __out_it, char32_t __value) { - // From the Standard: "if `out` contains invalid code units, the behavior is undefined and implementations are - // encouraged to diagnose it". + // [print.fun]/7 : "if `out` contains invalid code units, the behavior is undefined and implementations are encouraged + // to diagnose it". _LIBCPP_ASSERT_UNCATEGORIZED(__is_scalar_value(__value), "an invalid unicode scalar value results in invalid UTF-32"); *__out_it++ = __value; } From 2d6607364f2a6147322a946b7511bf51128e68b8 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Thu, 4 Jan 2024 19:06:22 -0800 Subject: [PATCH 08/10] clang-format --- libcxx/include/__iterator/advance.h | 2 +- libcxx/include/__iterator/next.h | 12 ++++++------ libcxx/include/__iterator/prev.h | 8 ++++---- libcxx/include/__ranges/filter_view.h | 6 +++--- 4 files changed, 14 insertions(+), 14 deletions(-) diff --git a/libcxx/include/__iterator/advance.h b/libcxx/include/__iterator/advance.h index 13ab4525d2eac..73473f899eac7 100644 --- a/libcxx/include/__iterator/advance.h +++ b/libcxx/include/__iterator/advance.h @@ -65,7 +65,7 @@ template < class _InputIter, _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 void advance(_InputIter& __i, _Distance __orig_n) { typedef typename iterator_traits<_InputIter>::difference_type _Difference; _Difference __n = static_cast<_Difference>(std::__convert_to_integral(__orig_n)); - // Calling `advance` with a negative value on a non-bidirectional iterator is a no-op in the current implementation. + // Calling `advance` with a negative value on a non-bidirectional iterator is a no-op in the current implementation. _LIBCPP_ASSERT_PEDANTIC(__n >= 0 || __has_bidirectional_iterator_category<_InputIter>::value, "Attempt to advance(it, n) with negative n on a non-bidirectional iterator"); std::__advance(__i, __n, typename iterator_traits<_InputIter>::iterator_category()); diff --git a/libcxx/include/__iterator/next.h b/libcxx/include/__iterator/next.h index 2331c004d35ea..21d3688ad9eb6 100644 --- a/libcxx/include/__iterator/next.h +++ b/libcxx/include/__iterator/next.h @@ -27,13 +27,13 @@ _LIBCPP_BEGIN_NAMESPACE_STD template ::value, int> = 0> inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 _InputIter next(_InputIter __x, typename iterator_traits<_InputIter>::difference_type __n = 1) { - // Calling `advance` with a negative value on a non-bidirectional iterator in the current implementation. Note that - // this check duplicates the similar check in `std::advance`. - _LIBCPP_ASSERT_PEDANTIC(__n >= 0 || __has_bidirectional_iterator_category<_InputIter>::value, - "Attempt to next(it, n) with negative n on a non-bidirectional iterator"); + // Calling `advance` with a negative value on a non-bidirectional iterator is a no-op in the current implementation. + // Note that this check duplicates the similar check in `std::advance`. + _LIBCPP_ASSERT_PEDANTIC(__n >= 0 || __has_bidirectional_iterator_category<_InputIter>::value, + "Attempt to next(it, n) with negative n on a non-bidirectional iterator"); - std::advance(__x, __n); - return __x; + std::advance(__x, __n); + return __x; } #if _LIBCPP_STD_VER >= 20 diff --git a/libcxx/include/__iterator/prev.h b/libcxx/include/__iterator/prev.h index cb0e1fcb9b44d..2f0e6a088edb3 100644 --- a/libcxx/include/__iterator/prev.h +++ b/libcxx/include/__iterator/prev.h @@ -27,10 +27,10 @@ _LIBCPP_BEGIN_NAMESPACE_STD template ::value, int> = 0> inline _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX17 _InputIter prev(_InputIter __x, typename iterator_traits<_InputIter>::difference_type __n = 1) { - // Calling `advance` with a negative value on a non-bidirectional iterator in the current implementation. Note that - // this check duplicates the similar check in `std::advance`. - _LIBCPP_ASSERT_PEDANTIC(__n <= 0 || __has_bidirectional_iterator_category<_InputIter>::value, - "Attempt to prev(it, n) with a positive n on a non-bidirectional iterator"); + // Calling `advance` with a negative value on a non-bidirectional iterator is a no-op in the current implementation. + // Note that this check duplicates the similar check in `std::advance`. + _LIBCPP_ASSERT_PEDANTIC(__n <= 0 || __has_bidirectional_iterator_category<_InputIter>::value, + "Attempt to prev(it, n) with a positive n on a non-bidirectional iterator"); std::advance(__x, -__n); return __x; } diff --git a/libcxx/include/__ranges/filter_view.h b/libcxx/include/__ranges/filter_view.h index 7369369950a61..ecb78eee38100 100644 --- a/libcxx/include/__ranges/filter_view.h +++ b/libcxx/include/__ranges/filter_view.h @@ -83,9 +83,9 @@ class _LIBCPP_ABI_2023_OVERLAPPING_SUBOBJECT_FIX_TAG filter_view : public view_i _LIBCPP_HIDE_FROM_ABI constexpr _Pred const& pred() const { return *__pred_; } _LIBCPP_HIDE_FROM_ABI constexpr __iterator begin() { - // Note: this duplicates a check in `optional` but provides a better error message. - _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( - __pred_.__has_value(), "Trying to call begin() on a filter_view that does not have a valid predicate."); + // Note: this duplicates a check in `optional` but provides a better error message. + _LIBCPP_ASSERT_VALID_ELEMENT_ACCESS( + __pred_.__has_value(), "Trying to call begin() on a filter_view that does not have a valid predicate."); if constexpr (_UseCache) { if (!__cached_begin_.__has_value()) { __cached_begin_.__emplace(ranges::find_if(__base_, std::ref(*__pred_))); From 840523335d0b351ff2c7ba44755b3e01969a5923 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Thu, 4 Jan 2024 19:08:09 -0800 Subject: [PATCH 09/10] Fix CI --- libcxx/include/__config | 1 + 1 file changed, 1 insertion(+) diff --git a/libcxx/include/__config b/libcxx/include/__config index 5a2b6586bbd8e..082c73e672c74 100644 --- a/libcxx/include/__config +++ b/libcxx/include/__config @@ -371,6 +371,7 @@ _LIBCPP_HARDENING_MODE_DEBUG # define _LIBCPP_ASSERT_NON_NULL(expression, message) _LIBCPP_ASSUME(expression) # define _LIBCPP_ASSERT_NON_OVERLAPPING_RANGES(expression, message) _LIBCPP_ASSUME(expression) # define _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(expression, message) _LIBCPP_ASSUME(expression) +# define _LIBCPP_ASSERT_PEDANTIC(expression, message) _LIBCPP_ASSUME(expression) # define _LIBCPP_ASSERT_INTERNAL(expression, message) _LIBCPP_ASSUME(expression) # define _LIBCPP_ASSERT_UNCATEGORIZED(expression, message) _LIBCPP_ASSUME(expression) From ea26d9db5ebfab6c625ddea5218370d46e1fb750 Mon Sep 17 00:00:00 2001 From: Konstantin Varlamov Date: Fri, 5 Jan 2024 03:38:10 -0800 Subject: [PATCH 10/10] Fix CI --- .../utilities/assert.exception_guard.no_exceptions.pass.cpp | 2 +- .../utility/utility.unreachable/assert.unreachable.pass.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/libcxx/test/libcxx/utilities/assert.exception_guard.no_exceptions.pass.cpp b/libcxx/test/libcxx/utilities/assert.exception_guard.no_exceptions.pass.cpp index 8c14b84278cb4..cf6b7bef3ebce 100644 --- a/libcxx/test/libcxx/utilities/assert.exception_guard.no_exceptions.pass.cpp +++ b/libcxx/test/libcxx/utilities/assert.exception_guard.no_exceptions.pass.cpp @@ -8,7 +8,7 @@ // REQUIRES: has-unix-headers // UNSUPPORTED: c++03 -// REQUIRES: libcpp-hardening-mode={{extensive|debug}} +// REQUIRES: libcpp-hardening-mode=debug // XFAIL: availability-verbose_abort-missing // ADDITIONAL_COMPILE_FLAGS: -fno-exceptions diff --git a/libcxx/test/std/utilities/utility/utility.unreachable/assert.unreachable.pass.cpp b/libcxx/test/std/utilities/utility/utility.unreachable/assert.unreachable.pass.cpp index 112b687cb17e2..f95b83ff4eb3c 100644 --- a/libcxx/test/std/utilities/utility/utility.unreachable/assert.unreachable.pass.cpp +++ b/libcxx/test/std/utilities/utility/utility.unreachable/assert.unreachable.pass.cpp @@ -8,7 +8,7 @@ // REQUIRES: has-unix-headers // UNSUPPORTED: c++03, c++11, c++14, c++17, c++20 -// REQUIRES: libcpp-hardening-mode={{extensive|debug}} +// REQUIRES: libcpp-hardening-mode=debug // XFAIL: availability-verbose_abort-missing // Make sure that reaching std::unreachable() with assertions enabled triggers an assertion.