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();

0 commit comments

Comments
 (0)