]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
libstdc++: bitset subscript check when _GLIBCXX_ASSERTIONS [PR118341]
authorNathan Myers <ncm@cantrip.org>
Wed, 4 Mar 2026 18:08:41 +0000 (13:08 -0500)
committerNathan Myers <ncm@cantrip.org>
Thu, 5 Mar 2026 18:23:36 +0000 (13:23 -0500)
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.

libstdc++-v3/include/std/bitset
libstdc++-v3/testsuite/20_util/bitset/access/118341_neg1.cc [new file with mode: 0644]
libstdc++-v3/testsuite/20_util/bitset/access/118341_neg2.cc [new file with mode: 0644]
libstdc++-v3/testsuite/20_util/bitset/access/118341_smoke.cc [new file with mode: 0644]
libstdc++-v3/testsuite/20_util/bitset/access/subscript.cc [new file with mode: 0644]
libstdc++-v3/testsuite/20_util/bitset/access/subscript_const_neg.cc [new file with mode: 0644]

index 331d0894342f8d78e662f6f43aa3723672a5e947..eb200ab9246c9cdcc06ff4e3f0ce0e4e0da9bd65 100644 (file)
@@ -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 (file)
index 0000000..22991ff
--- /dev/null
@@ -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 (file)
index 0000000..fa8942e
--- /dev/null
@@ -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 (file)
index 0000000..0a525c1
--- /dev/null
@@ -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 (file)
index 0000000..18d5155
--- /dev/null
@@ -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 (file)
index 0000000..12d4f1e
--- /dev/null
@@ -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();
+}