https://gcc.gnu.org/g:1b404c574450a48fee5f28f2acffafee7419fe38

commit r16-7919-g1b404c574450a48fee5f28f2acffafee7419fe38
Author: Nathan Myers <[email protected]>
Date:   Wed Mar 4 13:08:41 2026 -0500

    libstdc++: bitset subscript check when _GLIBCXX_ASSERTIONS [PR118341]
    
    Changes in v3:
     - Delete redundant "dg" annotations.
    
    Changes in v2:
     - Rejigger testing.
     - Add tests for regular bitset<>::op[].
    
    Perform __glibcxx_assert bounds check on indices to bitset<>::op[]
    for const and non-const overloads.
    
    Also, add previously neglected regular tests for bitset<>::op[].
    
    libstdc++-v3/ChangeLog
            PR libstdc++/118341
            * include/std/bitset (operator[] (2x)): Add assertion.
            * testsuite/20_util/bitset/access/118341_neg1.cc: New test.
            * testsuite/20_util/bitset/access/118341_neg2.cc: Same.
            * testsuite/20_util/bitset/access/118341_smoke.cc: Same.
            * testsuite/20_util/bitset/access/subscript.cc: Same.
            * testsuite/20_util/bitset/access/subscript_const_neg.cc: Same.

Diff:
---
 libstdc++-v3/include/std/bitset                    | 10 +++++--
 .../testsuite/20_util/bitset/access/118341_neg1.cc | 14 ++++++++++
 .../testsuite/20_util/bitset/access/118341_neg2.cc | 14 ++++++++++
 .../20_util/bitset/access/118341_smoke.cc          | 31 ++++++++++++++++++++++
 .../testsuite/20_util/bitset/access/subscript.cc   | 26 ++++++++++++++++++
 .../20_util/bitset/access/subscript_const_neg.cc   | 13 +++++++++
 6 files changed, 106 insertions(+), 2 deletions(-)

diff --git a/libstdc++-v3/include/std/bitset b/libstdc++-v3/include/std/bitset
index 331d0894342f..eb200ab9246c 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/access/118341_neg1.cc 
b/libstdc++-v3/testsuite/20_util/bitset/access/118341_neg1.cc
new file mode 100644
index 000000000000..22991ffac91c
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/bitset/access/118341_neg1.cc
@@ -0,0 +1,14 @@
+// { dg-do run { xfail *-*-* } }
+// { dg-options "-D_GLIBCXX_ASSERTIONS" }
+
+#include <bitset>
+#include <testsuite_hooks.h>
+
+// Check bitset<>::op[] hardening, non-const.
+
+int main()
+{
+  std::bitset<13> bs(0x1555ull);
+  bs[12];  // OK
+  bs[13];  // aborts, 13 > 12, non-const
+}
diff --git a/libstdc++-v3/testsuite/20_util/bitset/access/118341_neg2.cc 
b/libstdc++-v3/testsuite/20_util/bitset/access/118341_neg2.cc
new file mode 100644
index 000000000000..fa8942ec5108
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/bitset/access/118341_neg2.cc
@@ -0,0 +1,14 @@
+// { dg-do run { xfail *-*-* } }
+// { dg-options "-D_GLIBCXX_ASSERTIONS" }
+
+#include <bitset>
+#include <testsuite_hooks.h>
+
+// Check bitset<>::op[] hardening, const.
+
+int main()
+{
+  const std::bitset<13> bs(0x1555ull);
+  bs[12];  // OK
+  bs[13];  // aborts, 13 > 12, const
+}
diff --git a/libstdc++-v3/testsuite/20_util/bitset/access/118341_smoke.cc 
b/libstdc++-v3/testsuite/20_util/bitset/access/118341_smoke.cc
new file mode 100644
index 000000000000..0a525c1b3fac
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/bitset/access/118341_smoke.cc
@@ -0,0 +1,31 @@
+// { dg-do run }
+// { dg-options "-D_GLIBCXX_ASSERTIONS" }
+
+// Smoke test, op[] hardening.
+
+#include <bitset>
+#include <testsuite_hooks.h>
+
+void test_non_const_subscript()
+{
+  std::bitset<13> bs(0x1555ull);
+  for (int i = 0; i < 13; ++i)
+    {
+      VERIFY(bs[i] != (i & 1)); // Check op[] proxy result rvalue.
+      bs[i] = not bs[i];        // Assign via op[] proxy result lvalue.
+      VERIFY(bs[i] == (i & 1)); // Check modified.
+    }
+}
+
+void test_const_subscript()
+{
+  const std::bitset<13> cbs(0x1555ull);
+  for (int i = 0; i < 13; ++i)
+    VERIFY(cbs[i] != (i & 1));  // Check op[] proxy result const rvalue.
+}
+
+int main()
+{
+  test_non_const_subscript();
+  test_const_subscript();
+}
diff --git a/libstdc++-v3/testsuite/20_util/bitset/access/subscript.cc 
b/libstdc++-v3/testsuite/20_util/bitset/access/subscript.cc
new file mode 100644
index 000000000000..18d5155ed085
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/bitset/access/subscript.cc
@@ -0,0 +1,26 @@
+#include <bitset>
+#include <testsuite_hooks.h>
+
+void test_non_const_subscript()
+{
+  std::bitset<13> bs(0x1555ull);
+  for (int i = 0; i < 13; ++i)
+    {
+      VERIFY(bs[i] != (i & 1)); // Check op[] proxy result rvalue.
+      bs[i] = not bs[i];        // Assign via op[] proxy result lvalue.
+      VERIFY(bs[i] == (i & 1)); // Check modified.
+    }
+}
+
+void test_const_subscript()
+{
+  const std::bitset<13> cbs(0x1555ull);
+  for (int i = 0; i < 13; ++i)
+    VERIFY(cbs[i] != (i & 1));  // Check op[] proxy result const rvalue.
+}
+
+int main()
+{
+  test_non_const_subscript();
+  test_const_subscript();
+}
diff --git 
a/libstdc++-v3/testsuite/20_util/bitset/access/subscript_const_neg.cc 
b/libstdc++-v3/testsuite/20_util/bitset/access/subscript_const_neg.cc
new file mode 100644
index 000000000000..12d4f1eaf308
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/bitset/access/subscript_const_neg.cc
@@ -0,0 +1,13 @@
+#include <bitset>
+
+void test_const_subscript_assignment()
+{
+  const std::bitset<13> bs(0x1555ull);
+  for (int i = 0; i < 13; ++i)
+    bs[i] = not bs[i];  // { dg-error "lvalue required" }
+}
+
+int main()
+{
+  test_const_subscript_assignment();
+}

Reply via email to