https://gcc.gnu.org/g:19def756dec1fe2df351214d36f8b951d46f1a76

commit r17-1258-g19def756dec1fe2df351214d36f8b951d46f1a76
Author: Tomasz Kamiński <[email protected]>
Date:   Wed Jun 3 12:04:51 2026 +0200

    libstdc++: Define hardening FTM and update operator[] for mdspan
    
    Defines __cpp_lib_hardened_mdspan.
    
    The hardened precondition on the mdspan converting constructor,
    is validated by the assert(_S_is_compatible_extents()) in the
    _ExtentsStorge. This also covers user-defined mappings, as all
    mappings are required to store, and thus construct extents
    objects.
    
    The operator[] implemented all required bounds checks, by:
    * checking for negative values in __index_type_cast
    * checking if value is representable in index_type in
      __index_type_cast
    * checking against the bound by calling __is_multi_index lambda
      in operator[]
    However, the last check subsumes the representability check
    (static extent values are validated at compile time).
    To reduce duplicated checks, this patch uses __index_int_t
    (introduced in r16-7644-g43f7452026fc05 for mdspan::at), that
    preserve negative values of arguments of integral type.
    
    libstdc++-v3/ChangeLog:
    
            * include/bits/version.def (hardened_mdspan): Define.
            * include/bits/version.h: Regenerate.
            * include/std/mdspan (__cpp_lib_hardened_mdspan): Define.
            (mdspan::operator[]): Replace __mdspan::__index_type_cast
            with cast to __index_int_t, and inline negative value checks.
    
    Reviewed-by: Jonathan Wakely <[email protected]>
    Signed-off-by: Tomasz Kamiński <[email protected]>

Diff:
---
 libstdc++-v3/include/bits/version.def |  8 ++++++++
 libstdc++-v3/include/bits/version.h   | 10 ++++++++++
 libstdc++-v3/include/std/mdspan       | 22 +++++++++++++++-------
 3 files changed, 33 insertions(+), 7 deletions(-)

diff --git a/libstdc++-v3/include/bits/version.def 
b/libstdc++-v3/include/bits/version.def
index 1104e7c3c907..df7190bec487 100644
--- a/libstdc++-v3/include/bits/version.def
+++ b/libstdc++-v3/include/bits/version.def
@@ -2452,6 +2452,14 @@ ftms = {
   };
 };
 
+ftms = {
+  name = hardened_mdspan;
+  values = {
+    v = 202502;
+    extra_cond = "defined(__glibcxx_mdspan) && defined(_GLIBCXX_ASSERTIONS)";
+  };
+};
+
 // Standard test specifications.
 stds[97] = ">= 199711L";
 stds[03] = ">= 199711L";
diff --git a/libstdc++-v3/include/bits/version.h 
b/libstdc++-v3/include/bits/version.h
index 4eff2c99e8f0..1a07f1153582 100644
--- a/libstdc++-v3/include/bits/version.h
+++ b/libstdc++-v3/include/bits/version.h
@@ -2710,4 +2710,14 @@
 #endif /* !defined(__cpp_lib_valarray) */
 #undef __glibcxx_want_valarray
 
+#if !defined(__cpp_lib_hardened_mdspan)
+# if (defined(__glibcxx_mdspan) && defined(_GLIBCXX_ASSERTIONS))
+#  define __glibcxx_hardened_mdspan 202502L
+#  if defined(__glibcxx_want_all) || defined(__glibcxx_want_hardened_mdspan)
+#   define __cpp_lib_hardened_mdspan 202502L
+#  endif
+# endif
+#endif /* !defined(__cpp_lib_hardened_mdspan) */
+#undef __glibcxx_want_hardened_mdspan
+
 #undef __glibcxx_want_all
diff --git a/libstdc++-v3/include/std/mdspan b/libstdc++-v3/include/std/mdspan
index adc1c0c64219..f5556f35fa14 100644
--- a/libstdc++-v3/include/std/mdspan
+++ b/libstdc++-v3/include/std/mdspan
@@ -40,6 +40,7 @@
 
 #define __glibcxx_want_mdspan
 #define __glibcxx_want_aligned_accessor
+#define __glibcxx_want_hardened_mdspan
 #define __glibcxx_want_submdspan
 #include <bits/version.h>
 
@@ -3062,17 +3063,24 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
        {
          if constexpr (rank() == 0)
            return _M_accessor.access(_M_handle, _M_mapping());
-         else if constexpr (!(is_same_v<_OIndexTypes, index_type> && ...))
-           return operator[](
-             __mdspan::__index_type_cast<index_type>(std::move(__indices))...);
+         else if constexpr (!(is_integral_v<_OIndexTypes> && ...))
+           return 
operator[](__index_int_t<_OIndexTypes>(std::move(__indices))...);
          else
           {
+            auto __is_valid_index = [&]<typename _OIntType>(size_t __dim, 
_OIntType __index)
+            {
+              if constexpr (is_signed_v<_OIntType>)
+                if (__index < 0)
+                  return false;
+              return std::cmp_less(__index, extents().extent(__dim));
+            };
             auto __is_multi_index = [&]<size_t... 
_Counts>(index_sequence<_Counts...>)
-            { return ((__indices < extents().extent(_Counts)) && ...); };
+            { return (__is_valid_index(_Counts, __indices) && ...); };
 
             __glibcxx_assert(__is_multi_index(make_index_sequence<rank()>()));
-            return _M_accessor.access(_M_handle, _M_mapping(__indices...));
-          }
+            auto __index = _M_mapping(static_cast<index_type>(__indices)...);
+            return _M_accessor.access(_M_handle, __index);
+          }
        }
 
       template<typename _OIndexType>
@@ -3084,7 +3092,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION
            -> reference
            {
               return operator[](
-                
__mdspan::__index_type_cast<index_type>(as_const(__indices[_Counts]))...);
+                __index_int_t<_OIndexType>(as_const(__indices[_Counts]))...);
            };
          return __call(make_index_sequence<rank()>());
        }

Reply via email to