Changes in v2:
 - Rejigger testing, test on c++98 et al.
 - 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.
---
 libstdc++-v3/include/std/bitset               | 10 ++++--
 .../20_util/bitset/access/118341_neg1.cc      | 14 +++++++++
 .../20_util/bitset/access/118341_neg2.cc      | 14 +++++++++
 .../20_util/bitset/access/118341_smoke.cc     | 31 +++++++++++++++++++
 .../20_util/bitset/access/subscript.cc        | 28 +++++++++++++++++
 .../bitset/access/subscript_const_neg.cc      | 15 +++++++++
 6 files changed, 110 insertions(+), 2 deletions(-)
 create mode 100644 libstdc++-v3/testsuite/20_util/bitset/access/118341_neg1.cc
 create mode 100644 libstdc++-v3/testsuite/20_util/bitset/access/118341_neg2.cc
 create mode 100644 libstdc++-v3/testsuite/20_util/bitset/access/118341_smoke.cc
 create mode 100644 libstdc++-v3/testsuite/20_util/bitset/access/subscript.cc
 create mode 100644 
libstdc++-v3/testsuite/20_util/bitset/access/subscript_const_neg.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/access/118341_neg1.cc 
b/libstdc++-v3/testsuite/20_util/bitset/access/118341_neg1.cc
new file mode 100644
index 00000000000..22991ffac91
--- /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 00000000000..fa8942ec510
--- /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 00000000000..0a525c1b3fa
--- /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 00000000000..4bcf6e3d530
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/bitset/access/subscript.cc
@@ -0,0 +1,28 @@
+// { dg-do run }
+
+#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 00000000000..00ed36196f8
--- /dev/null
+++ b/libstdc++-v3/testsuite/20_util/bitset/access/subscript_const_neg.cc
@@ -0,0 +1,15 @@
+// { dg-do compile
+
+#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();
+}
-- 
2.52.0

Reply via email to