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()>()); }
