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



Reply via email to