On Wed, 04 Mar 2026 at 13:21 -0500, Nathan Myers wrote:
Perform __glibcxx_assert check on indices to bitset<>::op[] for
const and non-const overloads.
libstdc++-v3/ChangeLog
PR libstdc++/118341
* include/std/bitset (operator[] (2x)): Add assertion.
* testsuite/20_util/bitset/118341_asrt_ix.cc: New smoke test.
* testsuite/20_util/bitset/118341_asrt_ix_neg1.cc: New negative test.
* testsuite/20_util/bitset/118341_asrt_ix_neg2.cc: New negative test.
---
libstdc++-v3/include/std/bitset | 10 ++++++++--
.../testsuite/20_util/bitset/118341_asrt_ix.cc | 16 ++++++++++++++++
.../20_util/bitset/118341_asrt_ix_neg1.cc | 13 +++++++++++++
.../20_util/bitset/118341_asrt_ix_neg2.cc | 13 +++++++++++++
4 files changed, 50 insertions(+), 2 deletions(-)
create mode 100644 libstdc++-v3/testsuite/20_util/bitset/118341_asrt_ix.cc
create mode 100644 libstdc++-v3/testsuite/20_util/bitset/118341_asrt_ix_neg1.cc
create mode 100644 libstdc++-v3/testsuite/20_util/bitset/118341_asrt_ix_neg2.cc
diff --git a/libstdc++-v3/include/std/bitset b/libstdc++-v3/include/std/bitset
index 331d0894342..eb200ab9246 100644
--- a/libstdc++-v3/include/std/bitset
+++ b/libstdc++-v3/include/std/bitset
@@ -1290,11 +1290,17 @@ _GLIBCXX_BEGIN_NAMESPACE_CONTAINER
_GLIBCXX23_CONSTEXPR
reference
operator[](size_t __position)
- { return reference(*this, __position); }
+ {
+ __glibcxx_assert(__position < _Nb);
+ return reference(*this, __position);
+ }
_GLIBCXX_CONSTEXPR bool
operator[](size_t __position) const
- { return _Unchecked_test(__position); }
+ {
+ __glibcxx_assert(__position < _Nb);
+ return _Unchecked_test(__position);
+ }
///@}
/**
diff --git a/libstdc++-v3/testsuite/20_util/bitset/118341_asrt_ix.cc
b/libstdc++-v3/testsuite/20_util/bitset/118341_asrt_ix.cc
new file mode 100644
index 00000000000..bc5c7ece6df
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/bitset/118341_asrt_ix.cc
"asrt_ix" is a bit cryptic, especially as it doesn't assert.
We have the 20_util/bitset/access subdirectory for the operator[]
members, so I think this test can be just
20_util/bitset/access/118341.cc
or even
20_util/bitset/access/subscript.cc
since it's not really testing the assertions, and somehow we don't
actually have a test for operator[] already! (We do have
20_util/bitset/access/constexpr.cc but not a runtime test).
Ideally we'd test it for bitsets of different sizes too, because we
have the _Bitset<1> partial specialization used for small bitsets (and
the _Bitset<0> one, but all indices are out-of-range for that one).
But adding those tests can be done separately, as it's not part of the
Bug 118341 changes.
@@ -0,0 +1,16 @@
+// { dg-do run { target c++26 } }
There's no need for this to be restricted to C++26.
+// { dg-options "-D_GLIBCXX_ASSERTIONS" }
+
+#include <bitset>
+#include <testsuite_hooks.h>
+
+int main()
+{
+ std::bitset<13> bs{"1010101010101"};
If you use () instead of {} then the test can run for C++98 and
doesn't need any { target xxx } selector.
+ for (int i = 0; i < 13; ++i)
+ VERIFY(bs[i] != (i & 1)); // op[], range check
+
+ const std::bitset<13> cbs{"1010101010101"};
Same here.
+ for (int i = 0; i < 13; ++i)
+ VERIFY(cbs[i] != (i & 1)); // op[] const, range check
+}
diff --git a/libstdc++-v3/testsuite/20_util/bitset/118341_asrt_ix_neg1.cc
b/libstdc++-v3/testsuite/20_util/bitset/118341_asrt_ix_neg1.cc
new file mode 100644
index 00000000000..f22beab6afc
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/bitset/118341_asrt_ix_neg1.cc
20_util/bitset/access/118341_neg1.cc
(and same changes to target selector and initialization)
@@ -0,0 +1,13 @@
+// { dg-do run { target c++26 xfail *-*-* } }
+// { dg-options "-D_GLIBCXX_ASSERTIONS" }
+
+#include <bitset>
+#include <testsuite_hooks.h>
+
+int main()
+{
+ std::bitset<13> bs{"1010101010101"};
+ for (int i = 0; i < 13; ++i)
+ VERIFY(bs[i] != (i & 1));
Our testsuite has no way to distinguish between this VERIFY failing
and the next line aborting, so I don't think there's any point in
checking with this loop. Other test fils should already be verifying
that op[] works when not out-of-range, so repeating it here isn't
needed.
+ bs[13]; // aborts, 13 > 12, non-const
+}
diff --git a/libstdc++-v3/testsuite/20_util/bitset/118341_asrt_ix_neg2.cc
b/libstdc++-v3/testsuite/20_util/bitset/118341_asrt_ix_neg2.cc
new file mode 100644
index 00000000000..273fbb7f592
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/bitset/118341_asrt_ix_neg2.cc
@@ -0,0 +1,13 @@
+// { dg-do run { target c++26 xfail *-*-* } }
20_util/bitset/access/118341_neg2.cc
(and same changes as to the _neg1.cc test)
+// { dg-options "-D_GLIBCXX_ASSERTIONS" }
+
+#include <bitset>
+#include <testsuite_hooks.h>
+
+int main()
+{
+ const std::bitset<13> bs{"1010101010101"};
+ for (int i = 0; i < 13; ++i)
+ VERIFY(bs[i] != (i & 1));
+ bs[13]; // aborts, 13 > 12, const
+}
--
2.52.0