From patchwork Wed Jun 3 10:29:23 2026 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: =?utf-8?q?Tomasz_Kami=C5=84ski?= X-Patchwork-Id: 136375 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id BF1C44BA2E1C for ; Wed, 3 Jun 2026 10:30:38 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org BF1C44BA2E1C Authentication-Results: sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=UMlQuEOj X-Original-To: gcc-patches@gcc.gnu.org Delivered-To: gcc-patches@gcc.gnu.org Received: from us-smtp-delivery-124.mimecast.com (us-smtp-delivery-124.mimecast.com [170.10.129.124]) by sourceware.org (Postfix) with ESMTP id B306B4BA2E04 for ; Wed, 3 Jun 2026 10:29:57 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org B306B4BA2E04 Authentication-Results: sourceware.org; dmarc=pass (p=quarantine dis=none) header.from=redhat.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=redhat.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org B306B4BA2E04 Authentication-Results: sourceware.org; arc=none smtp.remote-ip=170.10.129.124 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1780482597; cv=none; b=B/WD0WFAqQxi+Aq7nI9cAc4xRziMCXsETFiBDkN5TVchi8Ku4w6CilaCvr7i3ApTziOlzIslj60Dkx+fDgWPhzZavbNqyGF8v4Puml3eAqvLsc+R4DO5Sa2WHVZ+ddRI+9PGD+rg6bVbH6cWZ6Ux+/VExFTTIq2ybkAwfycwaUg= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1780482597; c=relaxed/simple; bh=x9xBJBa0aBPN8S8LcQWyMtfqFPRHPIiKQZ+7LHdmYdg=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=Fqux01SA9S7NjH48YFQR8yBfd060qZQLWuZMcn9C+2qtU0gvFaeLcSUaRRDsSMTlwbihW/AaiJt8zIIiO/SovL5bPdd8HFx2aIVdJSxlKBdH2hCuAu+KTdngK59Ro1CmXMkatxaYy/fVjWWwU/KDjPEt71ALErh85gHL2fuLMcI= ARC-Authentication-Results: i=1; sourceware.org; dkim=pass (1024-bit key, unprotected) header.d=redhat.com header.i=@redhat.com header.a=rsa-sha256 header.s=mimecast20190719 header.b=UMlQuEOj DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org B306B4BA2E04 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=redhat.com; s=mimecast20190719; t=1780482597; h=from:from:reply-to:subject:subject:date:date:message-id:message-id: to:to:cc:mime-version:mime-version:content-type:content-type: content-transfer-encoding:content-transfer-encoding; bh=LALV7dm8oqsZCJCDItSYjlj/1MtN/y5XWomiLEx+/f4=; b=UMlQuEOjJuxzE5BtaEORg5MdKEZyv5l1cyBKNfIwIISw7f2kUOI3lcGB9f4pMX7xphgNTN ADbfFqv1MPE5ob7c9cTbN+3lOO6CagLXfloQTko7EPSwfHufoJ+H9UB8roZDnLG+OG1LHt YMlb/GkWmmngw2i8rhUHQ91kRhLfxFE= Received: from mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (ec2-54-186-198-63.us-west-2.compute.amazonaws.com [54.186.198.63]) by relay.mimecast.com with ESMTP with STARTTLS (version=TLSv1.3, cipher=TLS_AES_256_GCM_SHA384) id us-mta-255-F3sCm6QbO1Ka9Al9K00y_A-1; Wed, 03 Jun 2026 06:29:55 -0400 X-MC-Unique: F3sCm6QbO1Ka9Al9K00y_A-1 X-Mimecast-MFC-AGG-ID: F3sCm6QbO1Ka9Al9K00y_A_1780482595 Received: from mx-prod-int-10.mail-002.prod.us-west-2.aws.redhat.com (mx-prod-int-10.mail-002.prod.us-west-2.aws.redhat.com [10.30.177.95]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by mx-prod-mc-01.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTPS id A6932195608C; Wed, 3 Jun 2026 10:29:54 +0000 (UTC) Received: from localhost (unknown [10.44.34.22]) by mx-prod-int-10.mail-002.prod.us-west-2.aws.redhat.com (Postfix) with ESMTP id EAA0C763; Wed, 3 Jun 2026 10:29:53 +0000 (UTC) From: =?utf-8?q?Tomasz_Kami=C5=84ski?= To: libstdc++@gcc.gnu.org, gcc-patches@gcc.gnu.org Subject: [PATCH] libstdc++: Define hardening FTM and update operator[] for mdspan Date: Wed, 3 Jun 2026 12:29:23 +0200 Message-ID: <20260603102952.413653-1-tkaminsk@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 3.6 on 10.30.177.95 X-Mimecast-Spam-Score: 0 X-Mimecast-MFC-PROC-ID: jpHxN2WDg7DD_0_KnlYEiTxnLSOafcjFnPR643N5xQY_1780482595 X-Mimecast-Originator: redhat.com content-type: text/plain; charset="US-ASCII"; x-default=true X-Spam-Status: No, score=-10.8 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, RCVD_IN_DNSWL_BLOCKED, RCVD_IN_SBL_CSS, SPF_HELO_PASS, SPF_NONE, TXREP shortcircuit=no autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gcc-patches-bounces~patchwork=sourceware.org@gcc.gnu.org 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 @@ -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(std::move(__indices))...); + else if constexpr (!(is_integral_v<_OIndexTypes> && ...)) + return operator[](__index_int_t<_OIndexTypes>(std::move(__indices))...); else { + auto __is_valid_index = [&](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 = [&](index_sequence<_Counts...>) - { return ((__indices < extents().extent(_Counts)) && ...); }; + { return (__is_valid_index(_Counts, __indices) && ...); }; __glibcxx_assert(__is_multi_index(make_index_sequence())); - return _M_accessor.access(_M_handle, _M_mapping(__indices...)); - } + auto __index = _M_mapping(static_cast(__indices)...); + return _M_accessor.access(_M_handle, __index); + } } template @@ -3084,7 +3092,7 @@ _GLIBCXX_BEGIN_NAMESPACE_VERSION -> reference { return operator[]( - __mdspan::__index_type_cast(as_const(__indices[_Counts]))...); + __index_int_t<_OIndexType>(as_const(__indices[_Counts]))...); }; return __call(make_index_sequence()); }