On Fri, Jul 4, 2025 at 10:32 AM Luc Grosheintz <luc.groshei...@gmail.com>
wrote:

> 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
> check 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.
>
> Signed-off-by: Luc Grosheintz <luc.groshei...@gmail.com>
> ---
>
LGTM.

>  libstdc++-v3/include/std/mdspan               |  5 ++++
>  .../mdspan/layouts/debug/out_of_bounds_neg.cc | 30 +++++++++++++++++++
>  2 files changed, 35 insertions(+)
>  create mode 100644
> libstdc++-v3/testsuite/23_containers/mdspan/layouts/debug/out_of_bounds_neg.cc
>
> diff --git a/libstdc++-v3/include/std/mdspan
> b/libstdc++-v3/include/std/mdspan
> index c72a64094b7..cf20553aaa5 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 00000000000..fb8ff01e8aa
> --- /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" }
> --
> 2.49.0
>
>

Reply via email to