[gcc r16-2093] libstdc++: Check prerequisites of layout_*::operator().

Tomasz Kaminski tkaminsk@gcc.gnu.org
Tue Jul 8 11:45:16 GMT 2025


https://gcc.gnu.org/g:4d86e4cda01aa3ab60de164a8492a99bc9ca1f70

commit r16-2093-g4d86e4cda01aa3ab60de164a8492a99bc9ca1f70
Author: Luc Grosheintz <luc.grosheintz@gmail.com>
Date:   Fri Jul 4 10:29:43 2025 +0200

    libstdc++: Check prerequisites of layout_*::operator().
    
    Previously, the prerequisite that the arguments passed to operator() are
    a multi-dimensional index (of extents()) was not checked.
    
    Both mapping::operator() and mdspan::operator[] have the same
    prerequisite. Since, mdspan must check the prerequisite for user-defined
    layout mappings, the preference is to check in mdspan.
    
    Because out-of-bounds accesses are very common it's nevertheless useful
    to check the prerequisite in mapping::operator(). This is relevant for
    cases where the layout mappings are used without mdspan. This commit
    checks the prerequisites via _GLIBCXX_DEBUG_ASSERTs and adds the required
    tests.
    
    More discussion in the email chain starting at:
    
      https://gcc.gnu.org/pipermail/libstdc++/2025-July/062265.html
    
    libstdc++-v3/ChangeLog:
    
            * include/std/mdspan: Check prerequisites of
            layout_*::operator() with _GLIBCXX_DEBUG_ASSERTs.
            * testsuite/23_containers/mdspan/layouts/debug/out_of_bounds_neg.cc:
            Add tests for prerequisites.
    
    Reviewed-by: Tomasz Kamiński <tkaminsk@redhat.com>
    Signed-off-by: Luc Grosheintz <luc.grosheintz@gmail.com>

Diff:
---
 libstdc++-v3/include/std/mdspan                    |  5 ++++
 .../mdspan/layouts/debug/out_of_bounds_neg.cc      | 30 ++++++++++++++++++++++
 2 files changed, 35 insertions(+)

diff --git a/libstdc++-v3/include/std/mdspan b/libstdc++-v3/include/std/mdspan
index 4a06fb2d3a86..1fdcae634419 100644
--- a/libstdc++-v3/include/std/mdspan
+++ b/libstdc++-v3/include/std/mdspan
@@ -441,6 +441,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	    _IndexType __mult = 1;
 	    auto __update = [&, __pos = 0u](_IndexType __idx) mutable
 	      {
+		_GLIBCXX_DEBUG_ASSERT(cmp_less(__idx, __exts.extent(__pos)));
 		__res += __idx * __mult;
 		__mult *= __exts.extent(__pos);
 		++__pos;
@@ -651,6 +652,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	    auto __update = [&, __pos = __exts.rank()](_IndexType) mutable
 	      {
 		--__pos;
+		_GLIBCXX_DEBUG_ASSERT(cmp_less(__ind_arr[__pos],
+					       __exts.extent(__pos)));
 		__res += __ind_arr[__pos] * __mult;
 		__mult *= __exts.extent(__pos);
 	      };
@@ -822,6 +825,8 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
 	  {
 	    auto __update = [&, __pos = 0u](_IndexType __idx) mutable
 	      {
+		_GLIBCXX_DEBUG_ASSERT(cmp_less(__idx,
+					       __m.extents().extent(__pos)));
 		__res += __idx * __m.stride(__pos++);
 	      };
 	    (__update(__indices), ...);
diff --git a/libstdc++-v3/testsuite/23_containers/mdspan/layouts/debug/out_of_bounds_neg.cc b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/debug/out_of_bounds_neg.cc
new file mode 100644
index 000000000000..fb8ff01e8aa2
--- /dev/null
+++ b/libstdc++-v3/testsuite/23_containers/mdspan/layouts/debug/out_of_bounds_neg.cc
@@ -0,0 +1,30 @@
+// { dg-do compile { target c++23 } }
+// { dg-require-debug-mode "" }
+#include<mdspan>
+
+template<typename Layout>
+  constexpr bool
+  test_out_of_bounds_1d()
+  {
+    auto m = typename Layout::mapping<std::extents<int, 0>>{};
+    (void) m(0); // { dg-error "expansion of" }
+    return true;
+  }
+static_assert(test_out_of_bounds_1d<std::layout_left>()); // { dg-error "expansion of" }
+static_assert(test_out_of_bounds_1d<std::layout_right>()); // { dg-error "expansion of" }
+static_assert(test_out_of_bounds_1d<std::layout_stride>()); // { dg-error "expansion of" }
+
+template<typename Layout>
+  constexpr bool
+  test_out_of_bounds_3d()
+  {
+    auto m = typename Layout::mapping<std::extents<int, 3, 5, 7>>{};
+    (void) m(2, 5, 5); // { dg-error "expansion of" }
+    return true;
+  }
+static_assert(test_out_of_bounds_3d<std::layout_left>()); // { dg-error "expansion of" }
+static_assert(test_out_of_bounds_3d<std::layout_right>()); // { dg-error "expansion of" }
+static_assert(test_out_of_bounds_3d<std::layout_stride>()); // { dg-error "expansion of" }
+
+// { dg-prune-output "non-constant condition for static assertion" }
+// { dg-prune-output "__glibcxx_assert" }


More information about the Libstdc++-cvs mailing list