Skip to content

Commit 930f956

Browse files
[libc++] Fix constructing bitset from non-null-terminated arrays
Unconditional evaluation of `char_traits<_CharT>::length(__str)` is problematic, because it causes UB when `__str` points to a non-null-terminated array. We should only call `length` (currently, in `basic_string_view`'s constructor) when `__n == npos` per [bitset.cons]/8. Drive-by change: Reduction of conditional compilation, given that - both `basic_string_view<_CharT>::size_type` and `basic_string<_CharT>::size_type` must be `size_t`, and thus - both `basic_string_view<_CharT>::npos` and `basic_string<_CharT>::npos` must be `size_t(-1)`. For the type sameness in the standard wording, see: - [string.view.template.general] - [basic.string.general] - [allocator.traits.types]/6 - [default.allocator.general]/1
1 parent ac7fa40 commit 930f956

File tree

2 files changed

+33
-8
lines changed

2 files changed

+33
-8
lines changed

libcxx/include/bitset

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -645,16 +645,13 @@ public:
645645
template <class _CharT, __enable_if_t<_IsCharLikeType<_CharT>::value, int> = 0>
646646
_LIBCPP_HIDE_FROM_ABI _LIBCPP_CONSTEXPR_SINCE_CXX23 explicit bitset(
647647
const _CharT* __str,
648-
# if _LIBCPP_STD_VER >= 26
649-
typename basic_string_view<_CharT>::size_type __n = basic_string_view<_CharT>::npos,
650-
# else
651-
typename basic_string<_CharT>::size_type __n = basic_string<_CharT>::npos,
652-
# endif
648+
size_t __n = static_cast<size_t>(-1),
653649
_CharT __zero = _CharT('0'),
654650
_CharT __one = _CharT('1')) {
655-
656-
size_t __rlen = std::min(__n, char_traits<_CharT>::length(__str));
657-
__init_from_string_view(basic_string_view<_CharT>(__str, __rlen), __zero, __one);
651+
if (__n == static_cast<size_t>(-1))
652+
__init_from_string_view(basic_string_view<_CharT>(__str), __zero, __one);
653+
else
654+
__init_from_string_view(basic_string_view<_CharT>(__str, __n), __zero, __one);
658655
}
659656
# if _LIBCPP_STD_VER >= 26
660657
template <class _CharT, class _Traits>

libcxx/test/std/utilities/template.bitset/bitset.cons/char_ptr_ctor.pass.cpp

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,34 @@ TEST_CONSTEXPR_CXX23 void test_char_pointer_ctor()
7272
for (std::size_t i = 10; i < v.size(); ++i)
7373
assert(v[i] == false);
7474
}
75+
// See https://github.com/llvm/llvm-project/issues/143684
76+
{
77+
const char not_null_terminated[] = {'1', '0', '1', '0', '1', '0', '1', '0', '1', '0'};
78+
std::bitset<N> v(not_null_terminated, 10);
79+
std::size_t M = std::min<std::size_t>(v.size(), 10);
80+
for (std::size_t i = 0; i < M; ++i)
81+
assert(v[i] == (not_null_terminated[M - 1 - i] == '1'));
82+
for (std::size_t i = 10; i < v.size(); ++i)
83+
assert(v[i] == false);
84+
}
85+
{
86+
const char not_null_terminated[] = {'1', 'a', '1', 'a', '1', 'a', '1', 'a', '1', 'a'};
87+
std::bitset<N> v(not_null_terminated, 10, 'a');
88+
std::size_t M = std::min<std::size_t>(v.size(), 10);
89+
for (std::size_t i = 0; i < M; ++i)
90+
assert(v[i] == (not_null_terminated[M - 1 - i] == '1'));
91+
for (std::size_t i = 10; i < v.size(); ++i)
92+
assert(v[i] == false);
93+
}
94+
{
95+
const char not_null_terminated[] = {'b', 'a', 'b', 'a', 'b', 'a', 'b', 'a', 'b', 'a'};
96+
std::bitset<N> v(not_null_terminated, 10, 'a', 'b');
97+
std::size_t M = std::min<std::size_t>(v.size(), 10);
98+
for (std::size_t i = 0; i < M; ++i)
99+
assert(v[i] == (not_null_terminated[M - 1 - i] == 'b'));
100+
for (std::size_t i = 10; i < v.size(); ++i)
101+
assert(v[i] == false);
102+
}
75103
}
76104

77105
TEST_CONSTEXPR_CXX23 bool test() {

0 commit comments

Comments
 (0)