[PATCH] libstdc++: Define hardening FTM and update operator[] for mdspan
Tomasz Kamiński
tkaminsk@redhat.com
Wed Jun 3 10:29:23 GMT 2026
This 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
(introduce 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.
---
Testing on x86_64-linux. All *mdspan* test passed.
OK for trunk when all test passes?
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 1104e7c3c90..df7190bec48 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 4eff2c99e8f..1a07f115358 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 adc1c0c6421..f5556f35fa1 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()>());
}
--
2.54.0
More information about the Libstdc++
mailing list