Skip to content

Commit 4f215fd

Browse files
authored
[libc++][hardening] Categorize more assertions. (#75918)
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.
1 parent 5e54319 commit 4f215fd

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

44 files changed

+184
-156
lines changed

libcxx/include/__algorithm/pop_heap.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ __pop_heap(_RandomAccessIterator __first,
3636
_RandomAccessIterator __last,
3737
_Compare& __comp,
3838
typename iterator_traits<_RandomAccessIterator>::difference_type __len) {
39-
_LIBCPP_ASSERT_UNCATEGORIZED(__len > 0, "The heap given to pop_heap must be non-empty");
39+
// Calling `pop_heap` on an empty range is undefined behavior, but in practice it will be a no-op.
40+
_LIBCPP_ASSERT_PEDANTIC(__len > 0, "The heap given to pop_heap must be non-empty");
4041

4142
__comp_ref_type<_Compare> __comp_ref = __comp;
4243

libcxx/include/__algorithm/sift_down.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ _LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX14 _RandomAccessIterator __floy
8585
_Compare&& __comp,
8686
typename iterator_traits<_RandomAccessIterator>::difference_type __len) {
8787
using difference_type = typename iterator_traits<_RandomAccessIterator>::difference_type;
88-
_LIBCPP_ASSERT_UNCATEGORIZED(__len >= 2, "shouldn't be called unless __len >= 2");
88+
_LIBCPP_ASSERT_INTERNAL(__len >= 2, "shouldn't be called unless __len >= 2");
8989

9090
_RandomAccessIterator __hole = __first;
9191
_RandomAccessIterator __child_i = __first;

libcxx/include/__algorithm/sort.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -533,7 +533,7 @@ __bitset_partition(_RandomAccessIterator __first, _RandomAccessIterator __last,
533533
using _Ops = _IterOps<_AlgPolicy>;
534534
typedef typename std::iterator_traits<_RandomAccessIterator>::value_type value_type;
535535
typedef typename std::iterator_traits<_RandomAccessIterator>::difference_type difference_type;
536-
_LIBCPP_ASSERT_UNCATEGORIZED(__last - __first >= difference_type(3), "");
536+
_LIBCPP_ASSERT_INTERNAL(__last - __first >= difference_type(3), "");
537537
const _RandomAccessIterator __begin = __first; // used for bounds checking, those are not moved around
538538
const _RandomAccessIterator __end = __last;
539539
(void)__end; //
@@ -625,7 +625,7 @@ __partition_with_equals_on_right(_RandomAccessIterator __first, _RandomAccessIte
625625
using _Ops = _IterOps<_AlgPolicy>;
626626
typedef typename iterator_traits<_RandomAccessIterator>::difference_type difference_type;
627627
typedef typename std::iterator_traits<_RandomAccessIterator>::value_type value_type;
628-
_LIBCPP_ASSERT_UNCATEGORIZED(__last - __first >= difference_type(3), "");
628+
_LIBCPP_ASSERT_INTERNAL(__last - __first >= difference_type(3), "");
629629
const _RandomAccessIterator __begin = __first; // used for bounds checking, those are not moved around
630630
const _RandomAccessIterator __end = __last;
631631
(void)__end; //

libcxx/include/__charconv/to_chars_base_10.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -132,14 +132,14 @@ __base_10_u64(char* __buffer, uint64_t __value) noexcept {
132132
/// range that can be used. However the range is sufficient for
133133
/// \ref __base_10_u128.
134134
_LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI inline __uint128_t __pow_10(int __exp) noexcept {
135-
_LIBCPP_ASSERT_UNCATEGORIZED(__exp >= __pow10_128_offset, "Index out of bounds");
135+
_LIBCPP_ASSERT_INTERNAL(__exp >= __pow10_128_offset, "Index out of bounds");
136136
return __pow10_128[__exp - __pow10_128_offset];
137137
}
138138

139139
_LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI inline char*
140140
__base_10_u128(char* __buffer, __uint128_t __value) noexcept {
141-
_LIBCPP_ASSERT_UNCATEGORIZED(
142-
__value > numeric_limits<uint64_t>::max(), "The optimizations for this algorithm fail when this isn't true.");
141+
_LIBCPP_ASSERT_INTERNAL(
142+
__value > numeric_limits<uint64_t>::max(), "The optimizations for this algorithm fails when this isn't true.");
143143

144144
// Unlike the 64 to 32 bit case the 128 bit case the "upper half" can't be
145145
// stored in the "lower half". Instead we first need to handle the top most

libcxx/include/__charconv/to_chars_integral.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -246,7 +246,7 @@ __to_chars_integral(char* __first, char* __last, _Tp __value) {
246246

247247
template <typename _Tp>
248248
_LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI int __to_chars_integral_width(_Tp __value, unsigned __base) {
249-
_LIBCPP_ASSERT_UNCATEGORIZED(__value >= 0, "The function requires a non-negative value.");
249+
_LIBCPP_ASSERT_INTERNAL(__value >= 0, "The function requires a non-negative value.");
250250

251251
unsigned __base_2 = __base * __base;
252252
unsigned __base_3 = __base_2 * __base;

libcxx/include/__charconv/traits.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -101,11 +101,11 @@ struct _LIBCPP_HIDDEN __traits_base<_Tp, __enable_if_t<sizeof(_Tp) == sizeof(__u
101101
/// zero is set to one. This means the first element of the lookup table is
102102
/// zero.
103103
static _LIBCPP_CONSTEXPR_SINCE_CXX23 _LIBCPP_HIDE_FROM_ABI int __width(_Tp __v) {
104-
_LIBCPP_ASSERT_UNCATEGORIZED(
104+
_LIBCPP_ASSERT_INTERNAL(
105105
__v > numeric_limits<uint64_t>::max(), "The optimizations for this algorithm fail when this isn't true.");
106106
// There's always a bit set in the upper 64-bits.
107107
auto __t = (128 - std::__libcpp_clz(static_cast<uint64_t>(__v >> 64))) * 1233 >> 12;
108-
_LIBCPP_ASSERT_UNCATEGORIZED(__t >= __itoa::__pow10_128_offset, "Index out of bounds");
108+
_LIBCPP_ASSERT_INTERNAL(__t >= __itoa::__pow10_128_offset, "Index out of bounds");
109109
// __t is adjusted since the lookup table misses the lower entries.
110110
return __t - (__v < __itoa::__pow10_128[__t - __itoa::__pow10_128_offset]) + 1;
111111
}

libcxx/include/__chrono/parser_std_format_spec.h

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -160,10 +160,9 @@ class _LIBCPP_TEMPLATE_VIS __parser_chrono {
160160
private:
161161
_LIBCPP_HIDE_FROM_ABI constexpr _ConstIterator
162162
__parse_chrono_specs(_ConstIterator __begin, _ConstIterator __end, __flags __flags) {
163-
_LIBCPP_ASSERT_UNCATEGORIZED(
164-
__begin != __end,
165-
"When called with an empty input the function will cause "
166-
"undefined behavior by evaluating data not in the input");
163+
_LIBCPP_ASSERT_INTERNAL(__begin != __end,
164+
"When called with an empty input the function will cause "
165+
"undefined behavior by evaluating data not in the input");
167166

168167
if (*__begin != _CharT('%') && *__begin != _CharT('}'))
169168
std::__throw_format_error("The format specifier expects a '%' or a '}'");

libcxx/include/__config

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,6 +283,9 @@
283283
// - `_LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR` -- checks any operations that exchange nodes between containers to make sure
284284
// the containers have compatible allocators.
285285
//
286+
// - `_LIBCPP_ASSERT_PEDANTIC` -- checks prerequisites which are imposed by the Standard, but violating which happens to
287+
// be benign in our implementation.
288+
//
286289
// - `_LIBCPP_ASSERT_INTERNAL` -- checks that internal invariants of the library hold. These assertions don't depend on
287290
// user input.
288291
//
@@ -325,6 +328,7 @@ _LIBCPP_HARDENING_MODE_DEBUG
325328
// vulnerability.
326329
# define _LIBCPP_ASSERT_NON_OVERLAPPING_RANGES(expression, message) _LIBCPP_ASSUME(expression)
327330
# define _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(expression, message) _LIBCPP_ASSUME(expression)
331+
# define _LIBCPP_ASSERT_PEDANTIC(expression, message) _LIBCPP_ASSUME(expression)
328332
# define _LIBCPP_ASSERT_INTERNAL(expression, message) _LIBCPP_ASSUME(expression)
329333
# define _LIBCPP_ASSERT_UNCATEGORIZED(expression, message) _LIBCPP_ASSUME(expression)
330334

@@ -339,6 +343,7 @@ _LIBCPP_HARDENING_MODE_DEBUG
339343
# define _LIBCPP_ASSERT_NON_OVERLAPPING_RANGES(expression, message) _LIBCPP_ASSERT(expression, message)
340344
# define _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(expression, message) _LIBCPP_ASSERT(expression, message)
341345
# define _LIBCPP_ASSERT_UNCATEGORIZED(expression, message) _LIBCPP_ASSERT(expression, message)
346+
# define _LIBCPP_ASSERT_PEDANTIC(expression, message) _LIBCPP_ASSERT(expression, message)
342347
// Disabled checks.
343348
# define _LIBCPP_ASSERT_INTERNAL(expression, message) _LIBCPP_ASSUME(expression)
344349

@@ -352,6 +357,7 @@ _LIBCPP_HARDENING_MODE_DEBUG
352357
# define _LIBCPP_ASSERT_NON_NULL(expression, message) _LIBCPP_ASSERT(expression, message)
353358
# define _LIBCPP_ASSERT_NON_OVERLAPPING_RANGES(expression, message) _LIBCPP_ASSERT(expression, message)
354359
# define _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(expression, message) _LIBCPP_ASSERT(expression, message)
360+
# define _LIBCPP_ASSERT_PEDANTIC(expression, message) _LIBCPP_ASSERT(expression, message)
355361
# define _LIBCPP_ASSERT_INTERNAL(expression, message) _LIBCPP_ASSERT(expression, message)
356362
# define _LIBCPP_ASSERT_UNCATEGORIZED(expression, message) _LIBCPP_ASSERT(expression, message)
357363

@@ -365,6 +371,7 @@ _LIBCPP_HARDENING_MODE_DEBUG
365371
# define _LIBCPP_ASSERT_NON_NULL(expression, message) _LIBCPP_ASSUME(expression)
366372
# define _LIBCPP_ASSERT_NON_OVERLAPPING_RANGES(expression, message) _LIBCPP_ASSUME(expression)
367373
# define _LIBCPP_ASSERT_COMPATIBLE_ALLOCATOR(expression, message) _LIBCPP_ASSUME(expression)
374+
# define _LIBCPP_ASSERT_PEDANTIC(expression, message) _LIBCPP_ASSUME(expression)
368375
# define _LIBCPP_ASSERT_INTERNAL(expression, message) _LIBCPP_ASSUME(expression)
369376
# define _LIBCPP_ASSERT_UNCATEGORIZED(expression, message) _LIBCPP_ASSUME(expression)
370377

libcxx/include/__filesystem/directory_iterator.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,8 @@ class directory_iterator {
7373
_LIBCPP_HIDE_FROM_ABI ~directory_iterator() = default;
7474

7575
_LIBCPP_HIDE_FROM_ABI const directory_entry& operator*() const {
76-
_LIBCPP_ASSERT_UNCATEGORIZED(__imp_, "The end iterator cannot be dereferenced");
76+
// Note: this check duplicates a check in `__dereference()`.
77+
_LIBCPP_ASSERT_NON_NULL(__imp_, "The end iterator cannot be dereferenced");
7778
return __dereference();
7879
}
7980

libcxx/include/__filesystem/path_iterator.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,7 @@ class _LIBCPP_EXPORTED_FROM_ABI path::iterator {
6161
_LIBCPP_HIDE_FROM_ABI pointer operator->() const { return &__stashed_elem_; }
6262

6363
_LIBCPP_HIDE_FROM_ABI iterator& operator++() {
64-
_LIBCPP_ASSERT_UNCATEGORIZED(__state_ != _Singular, "attempting to increment a singular iterator");
64+
_LIBCPP_ASSERT_NON_NULL(__state_ != _Singular, "attempting to increment a singular iterator");
6565
_LIBCPP_ASSERT_UNCATEGORIZED(__state_ != _AtEnd, "attempting to increment the end iterator");
6666
return __increment();
6767
}
@@ -73,7 +73,7 @@ class _LIBCPP_EXPORTED_FROM_ABI path::iterator {
7373
}
7474

7575
_LIBCPP_HIDE_FROM_ABI iterator& operator--() {
76-
_LIBCPP_ASSERT_UNCATEGORIZED(__state_ != _Singular, "attempting to decrement a singular iterator");
76+
_LIBCPP_ASSERT_NON_NULL(__state_ != _Singular, "attempting to decrement a singular iterator");
7777
_LIBCPP_ASSERT_UNCATEGORIZED(
7878
__entry_.data() != __path_ptr_->native().data(), "attempting to decrement the begin iterator");
7979
return __decrement();

libcxx/include/__format/buffer.h

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -115,7 +115,7 @@ class _LIBCPP_TEMPLATE_VIS __output_buffer {
115115

116116
// The output doesn't fit in the internal buffer.
117117
// Copy the data in "__capacity_" sized chunks.
118-
_LIBCPP_ASSERT_UNCATEGORIZED(__size_ == 0, "the buffer should be flushed by __flush_on_overflow");
118+
_LIBCPP_ASSERT_INTERNAL(__size_ == 0, "the buffer should be flushed by __flush_on_overflow");
119119
const _InCharT* __first = __str.data();
120120
do {
121121
size_t __chunk = std::min(__n, __capacity_);
@@ -134,7 +134,7 @@ class _LIBCPP_TEMPLATE_VIS __output_buffer {
134134
class _UnaryOperation,
135135
__fmt_char_type _InCharT = typename iterator_traits<_Iterator>::value_type>
136136
_LIBCPP_HIDE_FROM_ABI void __transform(_Iterator __first, _Iterator __last, _UnaryOperation __operation) {
137-
_LIBCPP_ASSERT_UNCATEGORIZED(__first <= __last, "not a valid range");
137+
_LIBCPP_ASSERT_INTERNAL(__first <= __last, "not a valid range");
138138

139139
size_t __n = static_cast<size_t>(__last - __first);
140140
__flush_on_overflow(__n);
@@ -146,7 +146,7 @@ class _LIBCPP_TEMPLATE_VIS __output_buffer {
146146

147147
// The output doesn't fit in the internal buffer.
148148
// Transform the data in "__capacity_" sized chunks.
149-
_LIBCPP_ASSERT_UNCATEGORIZED(__size_ == 0, "the buffer should be flushed by __flush_on_overflow");
149+
_LIBCPP_ASSERT_INTERNAL(__size_ == 0, "the buffer should be flushed by __flush_on_overflow");
150150
do {
151151
size_t __chunk = std::min(__n, __capacity_);
152152
std::transform(__first, __first + __chunk, std::addressof(__ptr_[__size_]), __operation);
@@ -168,7 +168,7 @@ class _LIBCPP_TEMPLATE_VIS __output_buffer {
168168

169169
// The output doesn't fit in the internal buffer.
170170
// Fill the buffer in "__capacity_" sized chunks.
171-
_LIBCPP_ASSERT_UNCATEGORIZED(__size_ == 0, "the buffer should be flushed by __flush_on_overflow");
171+
_LIBCPP_ASSERT_INTERNAL(__size_ == 0, "the buffer should be flushed by __flush_on_overflow");
172172
do {
173173
size_t __chunk = std::min(__n, __capacity_);
174174
std::fill_n(std::addressof(__ptr_[__size_]), __chunk, __value);
@@ -596,7 +596,7 @@ class _LIBCPP_TEMPLATE_VIS __retarget_buffer {
596596
class _UnaryOperation,
597597
__fmt_char_type _InCharT = typename iterator_traits<_Iterator>::value_type>
598598
_LIBCPP_HIDE_FROM_ABI void __transform(_Iterator __first, _Iterator __last, _UnaryOperation __operation) {
599-
_LIBCPP_ASSERT_UNCATEGORIZED(__first <= __last, "not a valid range");
599+
_LIBCPP_ASSERT_INTERNAL(__first <= __last, "not a valid range");
600600

601601
size_t __n = static_cast<size_t>(__last - __first);
602602
if (__size_ + __n >= __capacity_)
@@ -623,7 +623,7 @@ class _LIBCPP_TEMPLATE_VIS __retarget_buffer {
623623
_LIBCPP_HIDE_FROM_ABI void __grow_buffer() { __grow_buffer(__capacity_ * 1.6); }
624624

625625
_LIBCPP_HIDE_FROM_ABI void __grow_buffer(size_t __capacity) {
626-
_LIBCPP_ASSERT_UNCATEGORIZED(__capacity > __capacity_, "the buffer must grow");
626+
_LIBCPP_ASSERT_INTERNAL(__capacity > __capacity_, "the buffer must grow");
627627
auto __result = std::__allocate_at_least(__alloc_, __capacity);
628628
auto __guard = std::__make_exception_guard([&] {
629629
allocator_traits<_Alloc>::deallocate(__alloc_, __result.ptr, __result.count);

libcxx/include/__format/format_arg.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ _LIBCPP_HIDE_FROM_ABI constexpr bool __use_packed_format_arg_store(size_t __size
8383
}
8484

8585
_LIBCPP_HIDE_FROM_ABI constexpr __arg_t __get_packed_type(uint64_t __types, size_t __id) {
86-
_LIBCPP_ASSERT_UNCATEGORIZED(__id <= __packed_types_max, "");
86+
_LIBCPP_ASSERT_INTERNAL(__id <= __packed_types_max, "");
8787

8888
if (__id > 0)
8989
__types >>= __id * __packed_arg_t_bits;

libcxx/include/__format/formatter_bool.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,7 @@ struct _LIBCPP_TEMPLATE_VIS formatter<bool, _CharT> {
6262
static_cast<unsigned>(__value), __ctx, __parser_.__get_parsed_std_specifications(__ctx));
6363

6464
default:
65-
_LIBCPP_ASSERT_UNCATEGORIZED(false, "The parse function should have validated the type");
65+
_LIBCPP_ASSERT_INTERNAL(false, "The parse function should have validated the type");
6666
__libcpp_unreachable();
6767
}
6868
}

0 commit comments

Comments
 (0)