From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-wr1-x430.google.com (mail-wr1-x430.google.com [IPv6:2a00:1450:4864:20::430]) by sourceware.org (Postfix) with ESMTPS id C98433858410 for ; Sat, 9 Oct 2021 06:42:20 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.1 sourceware.org C98433858410 Received: by mail-wr1-x430.google.com with SMTP id v17so36270145wrv.9 for ; Fri, 08 Oct 2021 23:42:20 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:date:from:to:subject:user-agent:in-reply-to :references:message-id:mime-version:content-transfer-encoding; bh=8r1PJ+hmI8rlk/BvrpazQ2ioWhRbBh/IWzMPvBsfOfY=; b=sfi7t93gqhh2QiRKTaDZjPqHF1XbsZpsps2PQmyPJU3zuLJwyqFUK137ys3reldmUT 2gZD2ny4IwXTUdyDX4pH4pnFvtQkY4GwNBR79ijoL0iksBetQWVl+NYvdiqNyEFWgotD LCX79khDPGHXUM6NKR74UYyoNhDb3kO9of3uVao92SLIz0Bk4FVPZAiLq3lHxGFAazo1 YYBnoSau51242fckZBQsms0/peV8QKovTBz3wipEmO8FvrOi/GLzF5fZ7WUGNOBLvL99 CqfnC/z0K0GpbnAFuHcspCaDYtO9tOeEIgcVDhlyx/fITqHhsJdInH7GyP7SzFEB9PZD 4fnw== X-Gm-Message-State: AOAM532bKNqL9kBovh2J5r6S83vq9Fm8nOufYT885ChIMjookCyA97OE Buyya11is0YiDgtrUHTMZ4YFkOK3lnk= X-Google-Smtp-Source: ABdhPJyvfQ8tv4JMd1JWHovO7MtlGzuhBM9UFpa1aohVoqYRGbbFW6POb5SHu+QEvKTqMatjAvQf+A== X-Received: by 2002:adf:c78d:: with SMTP id l13mr9301780wrg.134.1633761739305; Fri, 08 Oct 2021 23:42:19 -0700 (PDT) Received: from [127.0.0.1] (dynamic-095-115-091-229.95.115.pool.telefonica.de. [95.115.91.229]) by smtp.gmail.com with ESMTPSA id k10sm13685907wmr.32.2021.10.08.23.42.18 (version=TLS1_2 cipher=ECDHE-ECDSA-AES128-GCM-SHA256 bits=128/128); Fri, 08 Oct 2021 23:42:18 -0700 (PDT) Date: Sat, 09 Oct 2021 08:42:16 +0200 From: Richard Biener To: Alexandre Oliva , Alexandre Oliva via Gcc-patches , gcc-patches@gcc.gnu.org Subject: Re: [PATCH] hardened conditionals User-Agent: K-9 Mail for Android In-Reply-To: References: Message-ID: <42A19672-C6EF-4C2F-A826-4CB9EE388B95@gmail.com> MIME-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable X-Spam-Status: No, score=-10.1 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, FREEMAIL_FROM, GIT_PATCH_0, KAM_SHORT, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.4 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on server2.sourceware.org X-BeenThere: gcc-patches@gcc.gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gcc-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Sat, 09 Oct 2021 06:42:24 -0000 On October 9, 2021 5:30:04 AM GMT+02:00, Alexandre Oliva via Gcc-patches wrote: > >This patch introduces optional passes to harden conditionals used in >branches, and in computing boolean expressions, by adding redundant >tests of the reversed conditions, and trapping in case of unexpected >results=2E Though in abstract machines the redundant tests should never >fail, CPUs may be led to misbehave under certain kinds of attacks, >such as of power deprivation, and these tests reduce the likelihood of >going too far down an unexpected execution path=2E > >This patch was regstrapped on x86_64-linux-gnu=2E It was also >bootstrapped along with an extra common=2Eopt that enables both passes >unconditionally=2E Ok to install? Why two passes (and two IL traverses?)=20 How do you prevent RTL optimizers (jump threading) from removing the redun= dant tests? I'd have expected such hardening to occur very late in the RTL = pipeline=2E=20 Richard=2E=20 > >for gcc/ChangeLog > > * common=2Eopt (fharden-compares): New=2E > (fharden-conditional-branches): New=2E > * doc/invoke=2Etexi: Document new options=2E > * gimple-harden-conditionals=2Ecc: New=2E > * passes=2Edef: Add new passes=2E > * tree-pass=2Eh (make_pass_harden_compares): Declare=2E > (make_pass_harden_conditional_branches): Declare=2E > >for gcc/ada/ChangeLog > > * doc/gnat_rm/security_hardening_features=2Erst > (Hardened Conditionals): New=2E > >for gcc/testsuite/ChangeLog > > * c-c++-common/torture/harden-comp=2Ec: New=2E > * c-c++-common/torture/harden-cond=2Ec: New=2E >--- > gcc/Makefile=2Ein | 1=20 > =2E=2E=2E/doc/gnat_rm/security_hardening_features=2Erst | 40 ++ > gcc/common=2Eopt | 8=20 > gcc/doc/invoke=2Etexi | 19 + > gcc/gimple-harden-conditionals=2Ecc | 379 ++++++++++++= ++++++++ > gcc/passes=2Edef | 2=20 > gcc/testsuite/c-c++-common/torture/harden-comp=2Ec | 14 + > gcc/testsuite/c-c++-common/torture/harden-cond=2Ec | 18 + > gcc/tree-pass=2Eh | 3=20 > 9 files changed, 484 insertions(+) > create mode 100644 gcc/gimple-harden-conditionals=2Ecc > create mode 100644 gcc/testsuite/c-c++-common/torture/harden-comp=2Ec > create mode 100644 gcc/testsuite/c-c++-common/torture/harden-cond=2Ec > >diff --git a/gcc/Makefile=2Ein b/gcc/Makefile=2Ein >index 64252697573a7=2E=2E7209ed117d09d 100644 >--- a/gcc/Makefile=2Ein >+++ b/gcc/Makefile=2Ein >@@ -1389,6 +1389,7 @@ OBJS =3D \ > gimple-if-to-switch=2Eo \ > gimple-iterator=2Eo \ > gimple-fold=2Eo \ >+ gimple-harden-conditionals=2Eo \ > gimple-laddress=2Eo \ > gimple-loop-interchange=2Eo \ > gimple-loop-jam=2Eo \ >diff --git a/gcc/ada/doc/gnat_rm/security_hardening_features=2Erst b/gcc/= ada/doc/gnat_rm/security_hardening_features=2Erst >index 1c46e3a4c7b88=2E=2E52240d7e3dd54 100644 >--- a/gcc/ada/doc/gnat_rm/security_hardening_features=2Erst >+++ b/gcc/ada/doc/gnat_rm/security_hardening_features=2Erst >@@ -87,3 +87,43 @@ types and subtypes, may be silently ignored=2E Specif= ically, it is not > currently recommended to rely on any effects this pragma might be > expected to have when calling subprograms through access-to-subprogram > variables=2E >+ >+ >+=2E=2E Hardened Conditionals: >+ >+Hardened Conditionals >+=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D=3D >+ >+GNAT can harden conditionals to protect against control flow attacks=2E >+ >+This is accomplished by two complementary transformations, each >+activated by a separate command-line option=2E >+ >+The option *-fharden-compares* enables hardening of compares that >+compute results stored in variables, adding verification that the >+reversed compare yields the opposite result=2E >+ >+The option *-fharden-conditional-branches* enables hardening of >+compares that guard conditional branches, adding verification of the >+reversed compare to both execution paths=2E >+ >+These transformations are introduced late in the compilation pipeline, >+long after boolean expressions are decomposed into separate compares, >+each one turned into either a conditional branch or a compare whose >+result is stored in a boolean variable or temporary=2E Compiler >+optimizations, if enabled, may also turn conditional branches into >+stored compares, and vice-versa=2E Conditionals may also be optimized >+out entirely, if their value can be determined at compile time, and >+occasionally multiple compares can be combined into one=2E >+ >+It is thus difficult to predict which of these two options will affect >+a specific compare operation expressed in source code=2E Using both >+options ensures that every compare that is not optimized out will be >+hardened=2E >+ >+The addition of reversed compares can be observed by enabling the dump >+files of the corresponding passes, through command line options >+*-fdump-tree-hardcmp* and *-fdump-tree-hardcbr*, respectively=2E >+ >+They are separate options, however, because of the significantly >+different performance impact of the hardening transformations=2E >diff --git a/gcc/common=2Eopt b/gcc/common=2Eopt >index e867055fc000d=2E=2E89f2e6da6e56e 100644 >--- a/gcc/common=2Eopt >+++ b/gcc/common=2Eopt >@@ -1719,6 +1719,14 @@ fguess-branch-probability > Common Var(flag_guess_branch_prob) Optimization > Enable guessing of branch probabilities=2E >=20 >+fharden-compares >+Common Var(flag_harden_compares) Optimization >+Harden conditionals not used in branches, checking reversed conditions= =2E >+ >+fharden-conditional-branches >+Common Var(flag_harden_conditional_branches) Optimization >+Harden conditional branches by checking reversed conditions=2E >+ > ; Nonzero means ignore `#ident' directives=2E 0 means handle them=2E > ; Generate position-independent code for executables if possible > ; On SVR4 targets, it also controls whether or not to emit a >diff --git a/gcc/doc/invoke=2Etexi b/gcc/doc/invoke=2Etexi >index 281dd10fff96c=2E=2E5ed6a55f729e1 100644 >--- a/gcc/doc/invoke=2Etexi >+++ b/gcc/doc/invoke=2Etexi >@@ -595,6 +595,7 @@ Objective-C and Objective-C++ Dialects}=2E > -fasan-shadow-offset=3D@var{number} -fsanitize-sections=3D@var{s1},@var= {s2},=2E=2E=2E @gol > -fsanitize-undefined-trap-on-error -fbounds-check @gol > -fcf-protection=3D@r{[}full@r{|}branch@r{|}return@r{|}none@r{|}check@r{]= } @gol >+-fharden-compares -fharden-conditional-branches @gol > -fstack-protector -fstack-protector-all -fstack-protector-strong @gol > -fstack-protector-explicit -fstack-check @gol > -fstack-limit-register=3D@var{reg} -fstack-limit-symbol=3D@var{sym} @go= l >@@ -15491,6 +15492,24 @@ which functions and calls should be skipped from= instrumentation > Currently the x86 GNU/Linux target provides an implementation based > on Intel Control-flow Enforcement Technology (CET)=2E >=20 >+@item -fharden-compares >+@opindex fharden-compares >+For every logical test that survives gimple optimizations and is >+@emph{not} the condition in a conditional branch (for example, >+conditions tested for conditional moves, or to store in boolean >+variables), emit extra code to compute and verify the reversed >+condition, and to call @code{__builtin_trap} if the results do not >+match=2E Use with @samp{-fharden-conditional-branches} to cover all >+conditionals=2E >+ >+@item -fharden-conditional-branches >+@opindex fharden-conditional-branches >+For every non-vectorized conditional branch that survives gimple >+optimizations, emit extra code to compute and verify the reversed >+condition, and to call @code{__builtin_trap} if the result is >+unexpected=2E Use with @samp{-fharden-compares} to cover all >+conditionals=2E >+ > @item -fstack-protector > @opindex fstack-protector > Emit extra code to check for buffer overflows, such as stack smashing >diff --git a/gcc/gimple-harden-conditionals=2Ecc b/gcc/gimple-harden-cond= itionals=2Ecc >new file mode 100644 >index 0000000000000=2E=2E08187b21ebddf >--- /dev/null >+++ b/gcc/gimple-harden-conditionals=2Ecc >@@ -0,0 +1,379 @@ >+/* Harden conditionals=2E >+ Copyright (C) 2021 Free Software Foundation, Inc=2E >+ Contributed by Alexandre Oliva =2E >+ >+This file is part of GCC=2E >+ >+GCC is free software; you can redistribute it and/or modify it under >+the terms of the GNU General Public License as published by the Free >+Software Foundation; either version 3, or (at your option) any later >+version=2E >+ >+GCC is distributed in the hope that it will be useful, but WITHOUT ANY >+WARRANTY; without even the implied warranty of MERCHANTABILITY or >+FITNESS FOR A PARTICULAR PURPOSE=2E See the GNU General Public License >+for more details=2E >+ >+You should have received a copy of the GNU General Public License >+along with GCC; see the file COPYING3=2E If not see >+=2E */ >+ >+#include "config=2Eh" >+#include "system=2Eh" >+#include "coretypes=2Eh" >+#include "backend=2Eh" >+#include "tree=2Eh" >+#include "fold-const=2Eh" >+#include "gimple=2Eh" >+#include "gimplify=2Eh" >+#include "tree-pass=2Eh" >+#include "ssa=2Eh" >+#include "gimple-iterator=2Eh" >+#include "tree-cfg=2Eh" >+#include "basic-block=2Eh" >+#include "cfghooks=2Eh" >+#include "cfgloop=2Eh" >+#include "diagnostic=2Eh" >+#include "intl=2Eh" >+ >+namespace { >+ >+/* This pass introduces redundant, but reversed conditionals at every >+ compare, be it used for conditional branches, other conditional >+ operations, or for boolean computation=2E This doesn't make sense >+ for abstract CPUs, but this kind of hardening may avoid undesirable >+ execution paths on CPUs under such attacks as of power >+ deprivation=2E */ >+ >+/* Define a pass to harden conditionals other than branches=2E */ >+const pass_data pass_data_harden_compares =3D { >+ GIMPLE_PASS, >+ "hardcmp", >+ OPTGROUP_NONE, >+ TV_NONE, >+ PROP_cfg | PROP_ssa, // properties_required >+ 0, // properties_provided >+ 0, // properties_destroyed >+ 0, // properties_start >+ TODO_update_ssa >+ | TODO_cleanup_cfg >+ | TODO_verify_il, // properties_finish >+}; >+ >+class pass_harden_compares : public gimple_opt_pass >+{ >+public: >+ pass_harden_compares (gcc::context *ctxt) >+ : gimple_opt_pass (pass_data_harden_compares, ctxt) >+ {} >+ opt_pass *clone () { return new pass_harden_compares (m_ctxt); } >+ virtual bool gate (function *) { >+ return flag_harden_compares; >+ } >+ virtual unsigned int execute (function *); >+}; >+ >+/* This pass introduces redundant, but reversed conditionals at every >+ conditional branch=2E This doesn't make sense for abstract CPUs, but >+ this kind of hardening may avoid undesirable execution paths on >+ CPUs under such attacks as of power deprivation=2E This pass must >+ run after the above, otherwise it will re-harden the checks >+ introduced by the above=2E */ >+ >+/* Define a pass to harden conditionals in branches=2E */ >+const pass_data pass_data_harden_conditional_branches =3D { >+ GIMPLE_PASS, >+ "hardcbr", >+ OPTGROUP_NONE, >+ TV_NONE, >+ PROP_cfg | PROP_ssa, // properties_required >+ 0, // properties_provided >+ 0, // properties_destroyed >+ 0, // properties_start >+ TODO_update_ssa >+ | TODO_cleanup_cfg >+ | TODO_verify_il, // properties_finish >+}; >+ >+class pass_harden_conditional_branches : public gimple_opt_pass >+{ >+public: >+ pass_harden_conditional_branches (gcc::context *ctxt) >+ : gimple_opt_pass (pass_data_harden_conditional_branches, ctxt) >+ {} >+ opt_pass *clone () { return new pass_harden_conditional_branches (m_ct= xt); } >+ virtual bool gate (function *) { >+ return flag_harden_conditional_branches; >+ } >+ virtual unsigned int execute (function *); >+}; >+ >+} >+ >+static inline tree >+detach_value (gimple_stmt_iterator *gsip, tree val) >+{ >+ if (TREE_CONSTANT (val) || TREE_CODE (val) !=3D SSA_NAME) >+ { >+ gcc_checking_assert (is_gimple_min_invariant (val)); >+ return val; >+ } >+ >+ tree ret =3D copy_ssa_name (val); >+ >+ vec *inputs =3D NULL; >+ vec *outputs =3D NULL; >+ vec_safe_push (outputs, >+ build_tree_list >+ (build_tree_list >+ (NULL_TREE, build_string (2, "=3Dg")), >+ ret)); >+ vec_safe_push (inputs, >+ build_tree_list >+ (build_tree_list >+ (NULL_TREE, build_string (1, "0")), >+ val)); >+ gasm *detach =3D gimple_build_asm_vec ("", inputs, outputs, >+ NULL, NULL); >+ gsi_insert_before (gsip, detach, GSI_SAME_STMT); >+ >+ SSA_NAME_DEF_STMT (ret) =3D detach; >+ >+ return ret; >+} >+ >+static inline void >+insert_check_and_trap (gimple_stmt_iterator *gsip, int flags, >+ enum tree_code cop, tree lhs, tree rhs) >+{ >+ basic_block chk =3D gsi_bb (*gsip); >+ >+ gcond *cond =3D gimple_build_cond (cop, lhs, rhs, NULL, NULL); >+ gsi_insert_before (gsip, cond, GSI_SAME_STMT); >+ >+ basic_block trp =3D create_empty_bb (chk); >+ >+ gimple_stmt_iterator gsit =3D gsi_after_labels (trp); >+ gcall *trap =3D gimple_build_call (builtin_decl_explicit (BUILT_IN_TRA= P), 0); >+ gsi_insert_before (&gsit, trap, GSI_SAME_STMT); >+ >+ if (dump_file) >+ fprintf (dump_file, >+ "Adding reversed compare to block %i, and trap to block %i\n", >+ chk->index, trp->index); >+ >+ if (BB_PARTITION (chk)) >+ BB_SET_PARTITION (trp, BB_COLD_PARTITION); >+ >+ int true_false_flag =3D flags & (EDGE_TRUE_VALUE | EDGE_FALSE_VALUE); >+ gcc_assert (true_false_flag); >+ int neg_true_false_flag =3D (~flags) & (EDGE_TRUE_VALUE | EDGE_FALSE_V= ALUE); >+ >+ single_succ_edge (chk)->flags &=3D ~EDGE_FALLTHRU; >+ single_succ_edge (chk)->flags |=3D neg_true_false_flag; >+ make_edge (chk, trp, true_false_flag); >+ >+ if (dom_info_available_p (CDI_DOMINATORS)) >+ set_immediate_dominator (CDI_DOMINATORS, trp, chk); >+ if (current_loops) >+ add_bb_to_loop (trp, current_loops->tree_root); >+} >+ >+static inline void >+insert_edge_check_and_trap (edge e, enum tree_code cop, tree lhs, tree r= hs) >+{ >+ int flags =3D e->flags; >+ basic_block src =3D e->src; >+ basic_block dest =3D e->dest; >+ >+ basic_block chk =3D split_edge (e); >+ e =3D NULL; >+ >+ if (dump_file) >+ fprintf (dump_file, >+ "Splitting edge %i->%i into block %i\n", >+ src->index, dest->index, chk->index); >+ >+ gimple_stmt_iterator gsik =3D gsi_after_labels (chk); >+ >+ bool same_p =3D (lhs =3D=3D rhs); >+ lhs =3D detach_value (&gsik, lhs); >+ rhs =3D same_p ? lhs : detach_value (&gsik, rhs); >+ >+ insert_check_and_trap (&gsik, flags, cop, lhs, rhs); >+} >+ >+unsigned int >+pass_harden_conditional_branches::execute (function *fun) >+{ >+ basic_block bb; >+ FOR_EACH_BB_REVERSE_FN (bb, fun) >+ { >+ gimple_stmt_iterator gsi =3D gsi_last_bb (bb); >+ >+ if (gsi_end_p (gsi)) >+ continue; >+ >+ gcond *cond =3D dyn_cast (gsi_stmt (gsi)); >+ if (!cond) >+ continue; >+ >+ /* Turn: >+ >+ if (x op y) goto l1; else goto l2; >+ >+ into: >+ >+ if (x op y) goto l1'; else goto l2'; >+ l1': if (x' cop y') goto l1'trap; else goto l1; >+ l1'trap: __builtin_trap (); >+ l2': if (x' cop y') goto l2; else goto l2'trap; >+ l2'trap: __builtin_trap (); >+ >+ where cop is a complementary boolean operation to op; l1', l1'trap, >+ l2' and l2'trap are newly-created labels; and x' and y' hold the same >+ value as x and y, but in a way that does not enable the compiler to >+ optimize the redundant compare away=2E >+ */ >+ >+ enum tree_code op =3D gimple_cond_code (cond); >+ tree lhs =3D gimple_cond_lhs (cond); >+ tree rhs =3D gimple_cond_rhs (cond); >+ >+ enum tree_code cop =3D invert_tree_comparison (op, HONOR_NANS (lhs= )); >+ >+ if (cop =3D=3D ERROR_MARK) >+ /* ??? Can we do better? */ >+ continue; >+ >+ insert_edge_check_and_trap (EDGE_SUCC (bb, 0), cop, lhs, rhs); >+ insert_edge_check_and_trap (EDGE_SUCC (bb, 1), cop, lhs, rhs); >+ } >+ >+ return 0; >+} >+ >+gimple_opt_pass * >+make_pass_harden_conditional_branches (gcc::context *ctxt) >+{ >+ return new pass_harden_conditional_branches (ctxt); >+} >+ >+unsigned int >+pass_harden_compares::execute (function *fun) >+{ >+ basic_block bb; >+ FOR_EACH_BB_REVERSE_FN (bb, fun) >+ for (gimple_stmt_iterator gsi =3D gsi_last_bb (bb); >+ !gsi_end_p (gsi); gsi_prev (&gsi)) >+ { >+ gassign *asgn =3D dyn_cast (gsi_stmt (gsi)); >+ if (!asgn) >+ continue; >+ >+ /* Turn: >+ >+ z =3D x op y; >+ >+ into: >+ >+ z =3D x op y; >+ z' =3D x' cop y'; >+ if (z =3D=3D z') __builtin_trap (); >+ >+ where cop is a complementary boolean operation to op; and x' >+ and y' hold the same value as x and y, but in a way that does >+ not enable the compiler to optimize the redundant compare >+ away=2E >+ */ >+ >+ enum tree_code op =3D gimple_assign_rhs_code (asgn); >+ >+ enum tree_code cop; >+ >+ switch (op) >+ { >+ case EQ_EXPR: >+ case NE_EXPR: >+ case GT_EXPR: >+ case GE_EXPR: >+ case LT_EXPR: >+ case LE_EXPR: >+ case LTGT_EXPR: >+ case UNEQ_EXPR: >+ case UNGT_EXPR: >+ case UNGE_EXPR: >+ case UNLT_EXPR: >+ case UNLE_EXPR: >+ case ORDERED_EXPR: >+ case UNORDERED_EXPR: >+ cop =3D invert_tree_comparison (op, >+ HONOR_NANS >+ (gimple_assign_rhs1 (asgn))); >+ >+ if (cop =3D=3D ERROR_MARK) >+ /* ??? Can we do better? */ >+ continue; >+ >+ break; >+ >+ /* ??? Maybe handle these too? */ >+ case TRUTH_NOT_EXPR: /* Unary! */ >+ case TRUTH_ANDIF_EXPR: >+ case TRUTH_ORIF_EXPR: >+ case TRUTH_AND_EXPR: >+ case TRUTH_OR_EXPR: >+ case TRUTH_XOR_EXPR: >+ default: >+ continue; >+ } >+ >+ /* These are the operands for the verification=2E */ >+ tree lhs =3D gimple_assign_lhs (asgn); >+ tree op1 =3D gimple_assign_rhs1 (asgn); >+ tree op2 =3D gimple_assign_rhs2 (asgn); >+ >+ /* Vector booleans can't be used in conditional branches=2E >+ ??? Can we do better? */ >+ if (VECTOR_TYPE_P (TREE_TYPE (op1))) >+ continue; >+ >+ gcc_checking_assert (TREE_CODE (TREE_TYPE (lhs)) =3D=3D BOOLEAN_TYPE); >+ >+ tree rhs =3D copy_ssa_name (lhs); >+ >+ gimple_stmt_iterator gsi_split =3D gsi; >+ gsi_next (&gsi_split); >+ >+ bool same_p =3D (op1 =3D=3D op2); >+ op1 =3D detach_value (&gsi_split, op1); >+ op2 =3D same_p ? op1 : detach_value (&gsi_split, op2); >+ >+ gassign *asgnck =3D gimple_build_assign (rhs, cop, op1, op2); >+ gsi_insert_before (&gsi_split, asgnck, GSI_SAME_STMT); >+ >+ if (!gsi_end_p (gsi_split)) >+ { >+ gsi_prev (&gsi_split); >+ split_block (bb, gsi_stmt (gsi_split)); >+ gsi_next (&gsi_split); >+ gcc_checking_assert (gsi_end_p (gsi_split)); >+ >+ if (dump_file) >+ fprintf (dump_file, "Splitting block %i\n", bb->index); >+ } >+ >+ gcc_checking_assert (single_succ_p (bb)); >+ >+ insert_check_and_trap (&gsi_split, EDGE_TRUE_VALUE, >+ EQ_EXPR, lhs, rhs); >+ } >+ >+ return 0; >+} >+ >+gimple_opt_pass * >+make_pass_harden_compares (gcc::context *ctxt) >+{ >+ return new pass_harden_compares (ctxt); >+} >diff --git a/gcc/passes=2Edef b/gcc/passes=2Edef >index 8e4638d20edac=2E=2E2d81086df1d39 100644 >--- a/gcc/passes=2Edef >+++ b/gcc/passes=2Edef >@@ -421,6 +421,8 @@ along with GCC; see the file COPYING3=2E If not see > NEXT_PASS (pass_lower_resx); > NEXT_PASS (pass_nrv); > NEXT_PASS (pass_gimple_isel); >+ NEXT_PASS (pass_harden_conditional_branches); >+ NEXT_PASS (pass_harden_compares); > NEXT_PASS (pass_cleanup_cfg_post_optimizing); > NEXT_PASS (pass_warn_function_noreturn); > NEXT_PASS (pass_warn_access); >diff --git a/gcc/testsuite/c-c++-common/torture/harden-comp=2Ec b/gcc/tes= tsuite/c-c++-common/torture/harden-comp=2Ec >new file mode 100644 >index 0000000000000=2E=2E1ee0b3663443d >--- /dev/null >+++ b/gcc/testsuite/c-c++-common/torture/harden-comp=2Ec >@@ -0,0 +1,14 @@ >+/* { dg-do compile } */ >+/* { dg-options "-fharden-compares -fdump-tree-hardcmp -ffat-lto-objects= " } */ >+ >+int >+f (int i, int j) >+{ >+ return i < j; >+} >+ >+/* { dg-final { scan-tree-dump-times "Splitting block" 1 "hardcmp" } } *= / >+/* { dg-final { scan-tree-dump-times "Adding reversed compare" 1 "hardcm= p" } } */ >+/* { dg-final { scan-tree-dump-times "__builtin_trap" 1 "hardcmp" } } */ >+/* { dg-final { scan-tree-dump-times "_\[0-9\]* =3D i_\[0-9\]*\[(\]D\[)\= ] < j_\[0-9\]*\[(\]D\[)\];" 1 "hardcmp" } } */ >+/* { dg-final { scan-tree-dump-times "_\[0-9\]* =3D i_\[0-9\]* >=3D j_\[= 0-9\]*;" 1 "hardcmp" } } */ >diff --git a/gcc/testsuite/c-c++-common/torture/harden-cond=2Ec b/gcc/tes= tsuite/c-c++-common/torture/harden-cond=2Ec >new file mode 100644 >index 0000000000000=2E=2E86de8e155ed38 >--- /dev/null >+++ b/gcc/testsuite/c-c++-common/torture/harden-cond=2Ec >@@ -0,0 +1,18 @@ >+/* { dg-do compile } */ >+/* { dg-options "-fharden-conditional-branches -fdump-tree-hardcbr -ffat= -lto-objects" } */ >+ >+extern int f1 (void); >+extern int f2 (void); >+ >+ >+int >+f (int i, int j) >+{ >+ return (i < j) ? f1 () : f2 (); >+} >+ >+/* { dg-final { scan-tree-dump-times "Splitting edge" 2 "hardcbr" } } */ >+/* { dg-final { scan-tree-dump-times "Adding reversed compare" 2 "hardcb= r" } } */ >+/* { dg-final { scan-tree-dump-times "__builtin_trap" 2 "hardcbr" } } */ >+/* { dg-final { scan-tree-dump-times "if \[(\]i_\[0-9\]*\[(\]D\[)\] < j_= \[0-9\]*\[(\]D\[)\]\[)\]" 1 "hardcbr" } } */ >+/* { dg-final { scan-tree-dump-times "if \[(\]i_\[0-9\]* >=3D j_\[0-9\]*= \[)\]" 2 "hardcbr" } } */ >diff --git a/gcc/tree-pass=2Eh b/gcc/tree-pass=2Eh >index 9d19228c385f7=2E=2E7eae2f26f5195 100644 >--- a/gcc/tree-pass=2Eh >+++ b/gcc/tree-pass=2Eh >@@ -643,6 +643,9 @@ extern gimple_opt_pass *make_pass_update_address_take= n (gcc::context *ctxt); > extern gimple_opt_pass *make_pass_convert_switch (gcc::context *ctxt); > extern gimple_opt_pass *make_pass_lower_vaarg (gcc::context *ctxt); > extern gimple_opt_pass *make_pass_gimple_isel (gcc::context *ctxt); >+extern gimple_opt_pass *make_pass_harden_compares (gcc::context *ctxt); >+extern gimple_opt_pass *make_pass_harden_conditional_branches (gcc::cont= ext >+ *ctxt); >=20 > /* Current optimization pass=2E */ > extern opt_pass *current_pass; > >