From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-wr1-x433.google.com (mail-wr1-x433.google.com [IPv6:2a00:1450:4864:20::433]) by sourceware.org (Postfix) with ESMTPS id A80083856DEA for ; Tue, 18 Jul 2023 13:13:30 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org A80083856DEA Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=adacore.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=adacore.com Received: by mail-wr1-x433.google.com with SMTP id ffacd0b85a97d-3159d5e409dso4409120f8f.0 for ; Tue, 18 Jul 2023 06:13:30 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=adacore.com; s=google; t=1689686009; x=1690290809; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:from:to:cc:subject:date:message-id:reply-to; bh=GgHAhivYkjmbNP2cuz/cDIlDWZTGm7OdKtFu7fVrhpQ=; b=TI/FbEFYF02FJ0lVK9iwuGckJBYWC06CA8UGpAvi6lZx/KZHRzn/3B5XdR5tG6N66h y19l5BP6ul/2ArDw5ISefa8K7od/IOoU3HHAhhgg31l4IdkQvhg49KUIlmeFWAUmE+BF jZArNWIma1xiTWJfmdUoB8w5HZUqQ6mY5IOU9bpITjlWylfLkufe8k5W+raCW/p603Bp ouAuYcWE3AIZ684agJOUSouey4kwwvBWO8UVS6afYI8NGgtX8ufwZjCQdX3iOiz3GFDz CvUCiI43a49nTk9aRkorcUntc5dtfi47G10n6xgukV/r094pLVM9KoW0KopuYxneds7g XePQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20221208; t=1689686009; x=1690290809; h=content-transfer-encoding:mime-version:message-id:date:subject:cc :to:from:x-gm-message-state:from:to:cc:subject:date:message-id :reply-to; bh=GgHAhivYkjmbNP2cuz/cDIlDWZTGm7OdKtFu7fVrhpQ=; b=TuTHW6x+jR8UmD3oWBad0VCsnO9u/AOPCnGVv5d3/G+ZuIbHaKwwanfCzxBwQIvCKB cdJEUkVPx34qBiGS+saEV1x6I1j+vbSQaEfJT85z8DKUle3ewSV2trryJxbhnToI+MiS 57dCimOvmN9ryvfpi9Y1Qe27nB8iGk0wTNDbKwpBuHzvLThNmw7PzlS3g4N+rJENotoa oyYP/1HTZvefnAkj2IycJ0TF1MFiVUVDofYZ4iuhGzJnq3M/eF2NAcvMks5pnyZBNfey 0ZJwYkuzCdUoC7xTNKi56BieaLkT+/cVjOWAm1m8StUgHBXf8wZg3EwRgZrjbQuHOXaS M4tw== X-Gm-Message-State: ABy/qLZIk5schNhvWod5HTE06+LAY8Bs8xnnz247kG3VXu74vjlTRiJC r6E925B/GQVV8QKtujOpwOpsj6/qS3Lyw5l22AvGyQ== X-Google-Smtp-Source: APBJJlGr2/Is44a+9yH1APBertCXeTVbSYu9hh4rdfZpZuPyTNLUIybdUFDuTqEBYAemYvqCpQ/UMQ== X-Received: by 2002:a5d:408c:0:b0:30a:c681:fd2e with SMTP id o12-20020a5d408c000000b0030ac681fd2emr11758324wrp.22.1689686009350; Tue, 18 Jul 2023 06:13:29 -0700 (PDT) Received: from poulhies-Precision-5550.telnowedge.local (lmontsouris-659-1-24-67.w81-250.abo.wanadoo.fr. [81.250.175.67]) by smtp.gmail.com with ESMTPSA id k9-20020a5d6289000000b00314417f5272sm2381585wru.64.2023.07.18.06.13.28 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 18 Jul 2023 06:13:28 -0700 (PDT) From: =?UTF-8?q?Marc=20Poulhi=C3=A8s?= To: gcc-patches@gcc.gnu.org Cc: Alexandre Oliva Subject: [COMMITTED] ada: Expose expected_throw attribute Date: Tue, 18 Jul 2023 15:13:28 +0200 Message-Id: <20230718131328.80948-1-poulhies@adacore.com> X-Mailer: git-send-email 2.40.0 MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-13.7 required=5.0 tests=BAYES_00,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,DKIM_VALID_EF,GIT_PATCH_0,RCVD_IN_DNSWL_NONE,SPF_HELO_NONE,SPF_PASS,TXREP,T_SCC_BODY_TEXT_LINE autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on server2.sourceware.org List-Id: From: Alexandre Oliva Mark exception-raising subprograms with expected_throw attribute. Document the use of the attribute in Control Flow Redundancy. Enable marking subprograms as expected_throw with Machine_Attribute pragmas. gcc/ada/ * libgnat/a-except.ads (Raise_Exception): Mark expected_throw. (Reraise_Occurrence): Likewise. (Raise_Exception_Always): Likewise. (Raise_From_Controlled_Operation): Likewise. (Reraise_Occurrence_Always): Likewise. (Reraise_Occurrence_No_Defer): Likewise. * libgnat/a-except.adb (Exception_Propagation.Propagate_Exception): Likewise. (Complete_And_Propagate_Occurrence): Likewise. (Raise_Exception_No_Defer): Likewise. (Raise_From_Signal_Handler): Likewise. (Raise_With_Msg): Likewise. (Raise_With_Location_And_Msg): Likewise. (Raise_Constraint_Error): Likewise. (Raise_Constraint_Error_Msg): Likewise. (Raise_Program_Error): Likewise. (Raise_Program_Error_Msg): Likewise. (Raise_Storage_Error): Likewise. (Raise_Storage_Error_Msg): Likewise. (Reraise, Rcheck_*): Likewise. * doc/gnat_rm/security_hardening_features.rst (Control Flow Hardening): Note the influence of expected_throw. * gnat_rm.texi: Regenerate. * gnat_ugn.texi: Regenerate. * gcc-interface/utils.cc (handle_expected_throw_attribute): New. (gnat_internal_attribute_table): Add expected_throw. Tested on x86_64-pc-linux-gnu, committed on master. --- .../gnat_rm/security_hardening_features.rst | 4 +- gcc/ada/gcc-interface/utils.cc | 19 ++++ gcc/ada/gnat_rm.texi | 6 +- gcc/ada/gnat_ugn.texi | 4 +- gcc/ada/libgnat/a-except.adb | 104 ++++++++++++++++++ gcc/ada/libgnat/a-except.ads | 14 +++ 6 files changed, 146 insertions(+), 5 deletions(-) diff --git a/gcc/ada/doc/gnat_rm/security_hardening_features.rst b/gcc/ada/doc/gnat_rm/security_hardening_features.rst index e057af2ea12..015b9ce3533 100644 --- a/gcc/ada/doc/gnat_rm/security_hardening_features.rst +++ b/gcc/ada/doc/gnat_rm/security_hardening_features.rst @@ -500,7 +500,9 @@ gets modified as follows: Verification may also be performed before No_Return calls, whether all of them, with :switch:`-fhardcfr-check-noreturn-calls=always`; all but -internal subprograms involved in exception-raising or -reraising, with +internal subprograms involved in exception-raising or -reraising or +subprograms explicitly marked with both :samp:`No_Return` and +:samp:`Machine_Attribute` :samp:`expected_throw` pragmas, with :switch:`-fhardcfr-check-noreturn-calls=no-xthrow` (default); only nothrow ones, with :switch:`-fhardcfr-check-noreturn-calls=nothrow`; or none, with :switch:`-fhardcfr-check-noreturn-calls=never`. diff --git a/gcc/ada/gcc-interface/utils.cc b/gcc/ada/gcc-interface/utils.cc index 8f1861b848e..d0a13d2af33 100644 --- a/gcc/ada/gcc-interface/utils.cc +++ b/gcc/ada/gcc-interface/utils.cc @@ -87,6 +87,7 @@ tree gnat_raise_decls_ext[(int) LAST_REASON_CODE + 1]; /* Forward declarations for handlers of attributes. */ static tree handle_const_attribute (tree *, tree, tree, int, bool *); static tree handle_nothrow_attribute (tree *, tree, tree, int, bool *); +static tree handle_expected_throw_attribute (tree *, tree, tree, int, bool *); static tree handle_pure_attribute (tree *, tree, tree, int, bool *); static tree handle_novops_attribute (tree *, tree, tree, int, bool *); static tree handle_nonnull_attribute (tree *, tree, tree, int, bool *); @@ -143,6 +144,8 @@ const struct attribute_spec gnat_internal_attribute_table[] = handle_const_attribute, NULL }, { "nothrow", 0, 0, true, false, false, false, handle_nothrow_attribute, NULL }, + { "expected_throw", 0, 0, true, false, false, false, + handle_expected_throw_attribute, NULL }, { "pure", 0, 0, true, false, false, false, handle_pure_attribute, NULL }, { "no vops", 0, 0, true, false, false, false, @@ -6379,6 +6382,22 @@ handle_nothrow_attribute (tree *node, tree ARG_UNUSED (name), return NULL_TREE; } +/* Handle a "expected_throw" attribute; arguments as in + struct attribute_spec.handler. */ + +static tree +handle_expected_throw_attribute (tree *node, tree ARG_UNUSED (name), + tree ARG_UNUSED (args), int ARG_UNUSED (flags), + bool *no_add_attrs) +{ + if (TREE_CODE (*node) == FUNCTION_DECL) + /* No flag to set here. */; + else + *no_add_attrs = true; + + return NULL_TREE; +} + /* Handle a "pure" attribute; arguments as in struct attribute_spec.handler. */ diff --git a/gcc/ada/gnat_rm.texi b/gcc/ada/gnat_rm.texi index 066c066d19d..b7e098331e9 100644 --- a/gcc/ada/gnat_rm.texi +++ b/gcc/ada/gnat_rm.texi @@ -19,7 +19,7 @@ @copying @quotation -GNAT Reference Manual , Jul 10, 2023 +GNAT Reference Manual , Jul 17, 2023 AdaCore @@ -29666,7 +29666,9 @@ end; Verification may also be performed before No_Return calls, whether all of them, with @code{-fhardcfr-check-noreturn-calls=always}; all but -internal subprograms involved in exception-raising or -reraising, with +internal subprograms involved in exception-raising or -reraising or +subprograms explicitly marked with both @code{No_Return} and +@code{Machine_Attribute} @code{expected_throw} pragmas, with @code{-fhardcfr-check-noreturn-calls=no-xthrow} (default); only nothrow ones, with @code{-fhardcfr-check-noreturn-calls=nothrow}; or none, with @code{-fhardcfr-check-noreturn-calls=never}. diff --git a/gcc/ada/gnat_ugn.texi b/gcc/ada/gnat_ugn.texi index 2721251c4e4..78f9b87a82e 100644 --- a/gcc/ada/gnat_ugn.texi +++ b/gcc/ada/gnat_ugn.texi @@ -19,7 +19,7 @@ @copying @quotation -GNAT User's Guide for Native Platforms , Jul 10, 2023 +GNAT User's Guide for Native Platforms , Jul 17, 2023 AdaCore @@ -29531,8 +29531,8 @@ to permit their use in free software. @printindex ge -@anchor{d1}@w{ } @anchor{gnat_ugn/gnat_utility_programs switches-related-to-project-files}@w{ } +@anchor{d1}@w{ } @c %**end of body @bye diff --git a/gcc/ada/libgnat/a-except.adb b/gcc/ada/libgnat/a-except.adb index 20a773661ae..dd5edaf1a9c 100644 --- a/gcc/ada/libgnat/a-except.adb +++ b/gcc/ada/libgnat/a-except.adb @@ -229,6 +229,7 @@ package body Ada.Exceptions is procedure Propagate_Exception (Excep : Exception_Occurrence); pragma No_Return (Propagate_Exception); + pragma Machine_Attribute (Propagate_Exception, "expected_throw"); -- This procedure propagates the exception represented by Excep end Exception_Propagation; @@ -256,6 +257,8 @@ package body Ada.Exceptions is procedure Complete_And_Propagate_Occurrence (X : EOA); pragma No_Return (Complete_And_Propagate_Occurrence); + pragma Machine_Attribute (Complete_And_Propagate_Occurrence, + "expected_throw"); -- This is a simple wrapper to Complete_Occurrence and -- Exception_Propagation.Propagate_Exception. @@ -280,6 +283,7 @@ package body Ada.Exceptions is (Ada, Raise_Exception_No_Defer, "ada__exceptions__raise_exception_no_defer"); pragma No_Return (Raise_Exception_No_Defer); + pragma Machine_Attribute (Raise_Exception_No_Defer, "expected_throw"); -- Similar to Raise_Exception, but with no abort deferral procedure Raise_From_Signal_Handler @@ -288,6 +292,7 @@ package body Ada.Exceptions is pragma Export (C, Raise_From_Signal_Handler, "__gnat_raise_from_signal_handler"); pragma No_Return (Raise_From_Signal_Handler); + pragma Machine_Attribute (Raise_From_Signal_Handler, "expected_throw"); -- This routine is used to raise an exception from a signal handler. The -- signal handler has already stored the machine state (i.e. the state that -- corresponds to the location at which the signal was raised). E is the @@ -301,6 +306,7 @@ package body Ada.Exceptions is procedure Raise_With_Msg (E : Exception_Id); pragma No_Return (Raise_With_Msg); + pragma Machine_Attribute (Raise_With_Msg, "expected_throw"); pragma Export (C, Raise_With_Msg, "__gnat_raise_with_msg"); -- Raises an exception with given exception id value. A message -- is associated with the raise, and has already been stored in the @@ -314,6 +320,7 @@ package body Ada.Exceptions is C : Integer := 0; M : System.Address := System.Null_Address); pragma No_Return (Raise_With_Location_And_Msg); + pragma Machine_Attribute (Raise_With_Location_And_Msg, "expected_throw"); -- Raise an exception with given exception id value. A filename and line -- number is associated with the raise and is stored in the exception -- occurrence and in addition a column and a string message M may be @@ -321,6 +328,7 @@ package body Ada.Exceptions is procedure Raise_Constraint_Error (File : System.Address; Line : Integer); pragma No_Return (Raise_Constraint_Error); + pragma Machine_Attribute (Raise_Constraint_Error, "expected_throw"); pragma Export (C, Raise_Constraint_Error, "__gnat_raise_constraint_error"); -- Raise constraint error with file:line information @@ -330,12 +338,14 @@ package body Ada.Exceptions is Column : Integer; Msg : System.Address); pragma No_Return (Raise_Constraint_Error_Msg); + pragma Machine_Attribute (Raise_Constraint_Error_Msg, "expected_throw"); pragma Export (C, Raise_Constraint_Error_Msg, "__gnat_raise_constraint_error_msg"); -- Raise constraint error with file:line:col + msg information procedure Raise_Program_Error (File : System.Address; Line : Integer); pragma No_Return (Raise_Program_Error); + pragma Machine_Attribute (Raise_Program_Error, "expected_throw"); pragma Export (C, Raise_Program_Error, "__gnat_raise_program_error"); -- Raise program error with file:line information @@ -344,12 +354,14 @@ package body Ada.Exceptions is Line : Integer; Msg : System.Address); pragma No_Return (Raise_Program_Error_Msg); + pragma Machine_Attribute (Raise_Program_Error_Msg, "expected_throw"); pragma Export (C, Raise_Program_Error_Msg, "__gnat_raise_program_error_msg"); -- Raise program error with file:line + msg information procedure Raise_Storage_Error (File : System.Address; Line : Integer); pragma No_Return (Raise_Storage_Error); + pragma Machine_Attribute (Raise_Storage_Error, "expected_throw"); pragma Export (C, Raise_Storage_Error, "__gnat_raise_storage_error"); -- Raise storage error with file:line information @@ -358,6 +370,7 @@ package body Ada.Exceptions is Line : Integer; Msg : System.Address); pragma No_Return (Raise_Storage_Error_Msg); + pragma Machine_Attribute (Raise_Storage_Error_Msg, "expected_throw"); pragma Export (C, Raise_Storage_Error_Msg, "__gnat_raise_storage_error_msg"); -- Raise storage error with file:line + reason msg information @@ -385,6 +398,7 @@ package body Ada.Exceptions is procedure Reraise; pragma No_Return (Reraise); + pragma Machine_Attribute (Reraise, "expected_throw"); pragma Export (C, Reraise, "__gnat_reraise"); -- Reraises the exception referenced by the Current_Excep field -- of the TSD (all fields of this exception occurrence are set). @@ -632,6 +646,96 @@ package body Ada.Exceptions is pragma No_Return (Rcheck_CE_Invalid_Data_Ext); pragma No_Return (Rcheck_CE_Range_Check_Ext); + -- These procedures are all expected to raise an exception. + -- These attributes are not visible to callers; they are made + -- visible in trans.c:build_raise_check. + + pragma Machine_Attribute (Rcheck_CE_Access_Check, + "expected_throw"); + pragma Machine_Attribute (Rcheck_CE_Null_Access_Parameter, + "expected_throw"); + pragma Machine_Attribute (Rcheck_CE_Discriminant_Check, + "expected_throw"); + pragma Machine_Attribute (Rcheck_CE_Divide_By_Zero, + "expected_throw"); + pragma Machine_Attribute (Rcheck_CE_Explicit_Raise, + "expected_throw"); + pragma Machine_Attribute (Rcheck_CE_Index_Check, + "expected_throw"); + pragma Machine_Attribute (Rcheck_CE_Invalid_Data, + "expected_throw"); + pragma Machine_Attribute (Rcheck_CE_Length_Check, + "expected_throw"); + pragma Machine_Attribute (Rcheck_CE_Null_Exception_Id, + "expected_throw"); + pragma Machine_Attribute (Rcheck_CE_Null_Not_Allowed, + "expected_throw"); + pragma Machine_Attribute (Rcheck_CE_Overflow_Check, + "expected_throw"); + pragma Machine_Attribute (Rcheck_CE_Partition_Check, + "expected_throw"); + pragma Machine_Attribute (Rcheck_CE_Range_Check, + "expected_throw"); + pragma Machine_Attribute (Rcheck_CE_Tag_Check, + "expected_throw"); + pragma Machine_Attribute (Rcheck_PE_Access_Before_Elaboration, + "expected_throw"); + pragma Machine_Attribute (Rcheck_PE_Accessibility_Check, + "expected_throw"); + pragma Machine_Attribute (Rcheck_PE_Address_Of_Intrinsic, + "expected_throw"); + pragma Machine_Attribute (Rcheck_PE_Aliased_Parameters, + "expected_throw"); + pragma Machine_Attribute (Rcheck_PE_All_Guards_Closed, + "expected_throw"); + pragma Machine_Attribute (Rcheck_PE_Bad_Predicated_Generic_Type, + "expected_throw"); + pragma Machine_Attribute (Rcheck_PE_Build_In_Place_Mismatch, + "expected_throw"); + pragma Machine_Attribute (Rcheck_PE_Current_Task_In_Entry_Body, + "expected_throw"); + pragma Machine_Attribute (Rcheck_PE_Duplicated_Entry_Address, + "expected_throw"); + pragma Machine_Attribute (Rcheck_PE_Explicit_Raise, + "expected_throw"); + pragma Machine_Attribute (Rcheck_PE_Implicit_Return, + "expected_throw"); + pragma Machine_Attribute (Rcheck_PE_Misaligned_Address_Value, + "expected_throw"); + pragma Machine_Attribute (Rcheck_PE_Missing_Return, + "expected_throw"); + pragma Machine_Attribute (Rcheck_PE_Non_Transportable_Actual, + "expected_throw"); + pragma Machine_Attribute (Rcheck_PE_Overlaid_Controlled_Object, + "expected_throw"); + pragma Machine_Attribute (Rcheck_PE_Potentially_Blocking_Operation, + "expected_throw"); + pragma Machine_Attribute (Rcheck_PE_Stream_Operation_Not_Allowed, + "expected_throw"); + pragma Machine_Attribute (Rcheck_PE_Stubbed_Subprogram_Called, + "expected_throw"); + pragma Machine_Attribute (Rcheck_PE_Unchecked_Union_Restriction, + "expected_throw"); + pragma Machine_Attribute (Rcheck_PE_Finalize_Raised_Exception, + "expected_throw"); + pragma Machine_Attribute (Rcheck_SE_Empty_Storage_Pool, + "expected_throw"); + pragma Machine_Attribute (Rcheck_SE_Explicit_Raise, + "expected_throw"); + pragma Machine_Attribute (Rcheck_SE_Infinite_Recursion, + "expected_throw"); + pragma Machine_Attribute (Rcheck_SE_Object_Too_Large, + "expected_throw"); + + pragma Machine_Attribute (Rcheck_CE_Access_Check_Ext, + "expected_throw"); + pragma Machine_Attribute (Rcheck_CE_Index_Check_Ext, + "expected_throw"); + pragma Machine_Attribute (Rcheck_CE_Invalid_Data_Ext, + "expected_throw"); + pragma Machine_Attribute (Rcheck_CE_Range_Check_Ext, + "expected_throw"); + -- Make all of these procedures callable from strub contexts. -- These attributes are not visible to callers; they are made -- visible in trans.c:build_raise_check. diff --git a/gcc/ada/libgnat/a-except.ads b/gcc/ada/libgnat/a-except.ads index 7949b5907b6..5583bf5504d 100644 --- a/gcc/ada/libgnat/a-except.ads +++ b/gcc/ada/libgnat/a-except.ads @@ -163,6 +163,14 @@ private Null_Id : constant Exception_Id := null; + pragma Machine_Attribute (Raise_Exception, "expected_throw"); + pragma Machine_Attribute (Reraise_Occurrence, "expected_throw"); + -- Tell the compiler that an exception is likely after calling + -- these subprograms. This could eventually be used for hot/cold + -- partitioning. For now, this only enables the control flow + -- redundancy to avoid duplicating a check before the No_Return + -- call and in the exception handler for the call. + ------------------------- -- Private Subprograms -- ------------------------- @@ -177,6 +185,7 @@ private procedure Raise_Exception_Always (E : Exception_Id; Message : String := ""); pragma No_Return (Raise_Exception_Always); + pragma Machine_Attribute (Raise_Exception_Always, "expected_throw"); pragma Export (Ada, Raise_Exception_Always, "__gnat_raise_exception"); -- This differs from Raise_Exception only in that the caller has determined -- that for sure the parameter E is not null, and that therefore no check @@ -195,6 +204,9 @@ private "__gnat_raise_from_controlled_operation"); -- Raise Program_Error, providing information about X (an exception raised -- during a controlled operation) in the exception message. + pragma Machine_Attribute (Raise_From_Controlled_Operation, + "expected_throw"); + -- Mark it like internal exception-raising subprograms procedure Reraise_Library_Exception_If_Any; pragma Export @@ -205,6 +217,7 @@ private procedure Reraise_Occurrence_Always (X : Exception_Occurrence); pragma No_Return (Reraise_Occurrence_Always); + pragma Machine_Attribute (Reraise_Occurrence_Always, "expected_throw"); -- This differs from Raise_Occurrence only in that the caller guarantees -- that for sure the parameter X is not the null occurrence, and that -- therefore this procedure cannot return. The expander uses this routine @@ -212,6 +225,7 @@ private procedure Reraise_Occurrence_No_Defer (X : Exception_Occurrence); pragma No_Return (Reraise_Occurrence_No_Defer); + pragma Machine_Attribute (Reraise_Occurrence_No_Defer, "expected_throw"); -- Exactly like Reraise_Occurrence, except that abort is not deferred -- before the call and the parameter X is known not to be the null -- occurrence. This is used in generated code when it is known that abort -- 2.40.0