From: Richard Biener <richard.guenther@gmail.com>
To: Alexandre Oliva <oliva@adacore.com>
Cc: Alexandre Oliva via Gcc-patches <gcc-patches@gcc.gnu.org>
Subject: Re: [PATCH] hardened conditionals
Date: Tue, 26 Oct 2021 10:21:54 +0200 [thread overview]
Message-ID: <CAFiYyc1+=KN7Z6TUh7QAeObNZefNytXVWPjy84YuN-V2FXN64g@mail.gmail.com> (raw)
In-Reply-To: <orsfwtiyx2.fsf@lxoliva.fsfla.org>
On Fri, Oct 22, 2021 at 4:19 AM Alexandre Oliva <oliva@adacore.com> wrote:
>
> On Oct 20, 2021, Alexandre Oliva <oliva@adacore.com> wrote:
>
> > I suppose it's a latent issue exposed by the patch,
>
> I was mistaken. Though I even had bisected the -fcompare-debug problem
> back to a patch from back in May, that added a new sink_code pass before
> store_merging, it was actually a bug in my patch, it was just a little
> hard to hit with bootstrap-debug, but it came up with -fcompare-debug in
> ways that misled me.
>
> split_block remains slightly risky to use unless you know you have or
> are going to insert nondebug stmts/insns in both blocks. I've often
> pondered warning in case split_block completes with only debug
> stmts/insns in either block, but IIRC there are multiple passes that
> split first and insert code afterwards, which have to be rearranged to
> aovid the warning.
>
> Anyway, here's the fixed patch. Regstrapped on x86_64-linux-gnu, and
> bootstrapped with an additional patch that enables both new passes. Ok
> to install?
OK.
Thanks,
Richard.
>
> hardened conditionals
>
> From: Alexandre Oliva <oliva@adacore.com>
>
> 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. 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.
>
>
> for gcc/ChangeLog
>
> * common.opt (fharden-compares): New.
> (fharden-conditional-branches): New.
> * doc/invoke.texi: Document new options.
> * gimple-harden-conditionals.cc: New.
> * passes.def: Add new passes.
> * tree-pass.h (make_pass_harden_compares): Declare.
> (make_pass_harden_conditional_branches): Declare.
>
> for gcc/ada/ChangeLog
>
> * doc/gnat_rm/security_hardening_features.rst
> (Hardened Conditionals): New.
>
> for gcc/testsuite/ChangeLog
>
> * c-c++-common/torture/harden-comp.c: New.
> * c-c++-common/torture/harden-cond.c: New.
> ---
> gcc/Makefile.in | 1
> .../doc/gnat_rm/security_hardening_features.rst | 40 ++
> gcc/common.opt | 8
> gcc/doc/invoke.texi | 19 +
> gcc/gimple-harden-conditionals.cc | 439 ++++++++++++++++++++
> gcc/passes.def | 2
> gcc/testsuite/c-c++-common/torture/harden-comp.c | 14 +
> gcc/testsuite/c-c++-common/torture/harden-cond.c | 18 +
> gcc/tree-pass.h | 3
> 9 files changed, 544 insertions(+)
> create mode 100644 gcc/gimple-harden-conditionals.cc
> create mode 100644 gcc/testsuite/c-c++-common/torture/harden-comp.c
> create mode 100644 gcc/testsuite/c-c++-common/torture/harden-cond.c
>
> diff --git a/gcc/Makefile.in b/gcc/Makefile.in
> index f36ffa4740b78..a79ff93dd5999 100644
> --- a/gcc/Makefile.in
> +++ b/gcc/Makefile.in
> @@ -1389,6 +1389,7 @@ OBJS = \
> gimple-if-to-switch.o \
> gimple-iterator.o \
> gimple-fold.o \
> + gimple-harden-conditionals.o \
> gimple-laddress.o \
> gimple-loop-interchange.o \
> gimple-loop-jam.o \
> diff --git a/gcc/ada/doc/gnat_rm/security_hardening_features.rst b/gcc/ada/doc/gnat_rm/security_hardening_features.rst
> index 1c46e3a4c7b88..52240d7e3dd54 100644
> --- a/gcc/ada/doc/gnat_rm/security_hardening_features.rst
> +++ b/gcc/ada/doc/gnat_rm/security_hardening_features.rst
> @@ -87,3 +87,43 @@ types and subtypes, may be silently ignored. Specifically, 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.
> +
> +
> +.. Hardened Conditionals:
> +
> +Hardened Conditionals
> +=====================
> +
> +GNAT can harden conditionals to protect against control flow attacks.
> +
> +This is accomplished by two complementary transformations, each
> +activated by a separate command-line option.
> +
> +The option *-fharden-compares* enables hardening of compares that
> +compute results stored in variables, adding verification that the
> +reversed compare yields the opposite result.
> +
> +The option *-fharden-conditional-branches* enables hardening of
> +compares that guard conditional branches, adding verification of the
> +reversed compare to both execution paths.
> +
> +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. Compiler
> +optimizations, if enabled, may also turn conditional branches into
> +stored compares, and vice-versa. 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.
> +
> +It is thus difficult to predict which of these two options will affect
> +a specific compare operation expressed in source code. Using both
> +options ensures that every compare that is not optimized out will be
> +hardened.
> +
> +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.
> +
> +They are separate options, however, because of the significantly
> +different performance impact of the hardening transformations.
> diff --git a/gcc/common.opt b/gcc/common.opt
> index a2af7fb36e0dd..7144755f66d61 100644
> --- a/gcc/common.opt
> +++ b/gcc/common.opt
> @@ -1722,6 +1722,14 @@ fguess-branch-probability
> Common Var(flag_guess_branch_prob) Optimization
> Enable guessing of branch probabilities.
>
> +fharden-compares
> +Common Var(flag_harden_compares) Optimization
> +Harden conditionals not used in branches, checking reversed conditions.
> +
> +fharden-conditional-branches
> +Common Var(flag_harden_conditional_branches) Optimization
> +Harden conditional branches by checking reversed conditions.
> +
> ; Nonzero means ignore `#ident' directives. 0 means handle them.
> ; 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.texi b/gcc/doc/invoke.texi
> index 0cc8a8edd058c..a9129a6f11c64 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -596,6 +596,7 @@ Objective-C and Objective-C++ Dialects}.
> -fasan-shadow-offset=@var{number} -fsanitize-sections=@var{s1},@var{s2},... @gol
> -fsanitize-undefined-trap-on-error -fbounds-check @gol
> -fcf-protection=@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=@var{reg} -fstack-limit-symbol=@var{sym} @gol
> @@ -15532,6 +15533,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).
>
> +@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. Use with @samp{-fharden-conditional-branches} to cover all
> +conditionals.
> +
> +@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. Use with @samp{-fharden-compares} to cover all
> +conditionals.
> +
> @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.cc b/gcc/gimple-harden-conditionals.cc
> new file mode 100644
> index 0000000000000..8916420d7dfe9
> --- /dev/null
> +++ b/gcc/gimple-harden-conditionals.cc
> @@ -0,0 +1,439 @@
> +/* Harden conditionals.
> + Copyright (C) 2021 Free Software Foundation, Inc.
> + Contributed by Alexandre Oliva <oliva@adacore.com>.
> +
> +This file is part of GCC.
> +
> +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.
> +
> +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. See the GNU General Public License
> +for more details.
> +
> +You should have received a copy of the GNU General Public License
> +along with GCC; see the file COPYING3. If not see
> +<http://www.gnu.org/licenses/>. */
> +
> +#include "config.h"
> +#include "system.h"
> +#include "coretypes.h"
> +#include "backend.h"
> +#include "tree.h"
> +#include "fold-const.h"
> +#include "gimple.h"
> +#include "gimplify.h"
> +#include "tree-pass.h"
> +#include "ssa.h"
> +#include "gimple-iterator.h"
> +#include "tree-cfg.h"
> +#include "basic-block.h"
> +#include "cfghooks.h"
> +#include "cfgloop.h"
> +#include "diagnostic.h"
> +#include "intl.h"
> +
> +namespace {
> +
> +/* These passes introduces redundant, but reversed conditionals at
> + compares, such as those used in conditional branches, and those
> + that compute boolean results. This doesn't make much sense for
> + abstract CPUs, but this kind of hardening may avoid undesirable
> + execution paths on actual CPUs under such attacks as of power
> + deprivation. */
> +
> +/* Define a pass to harden conditionals other than branches. */
> +
> +const pass_data pass_data_harden_compares = {
> + 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 *);
> +};
> +
> +/* Define a pass to harden conditionals in branches. This pass must
> + run after the above, otherwise it will re-harden the checks
> + introduced by the above. */
> +
> +const pass_data pass_data_harden_conditional_branches = {
> + 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_ctxt); }
> + virtual bool gate (function *) {
> + return flag_harden_conditional_branches;
> + }
> + virtual unsigned int execute (function *);
> +};
> +
> +}
> +
> +/* If VAL is an SSA name, return an SSA name holding the same value,
> + but without the compiler's knowing that it holds the same value, so
> + that uses thereof can't be optimized the way VAL might. Insert
> + stmts that initialize it before *GSIP, with LOC.
> +
> + Otherwise, VAL must be an invariant, returned unchanged. */
> +
> +static inline tree
> +detach_value (location_t loc, gimple_stmt_iterator *gsip, tree val)
> +{
> + if (TREE_CONSTANT (val) || TREE_CODE (val) != SSA_NAME)
> + {
> + gcc_checking_assert (is_gimple_min_invariant (val));
> + return val;
> + }
> +
> + tree ret = copy_ssa_name (val);
> +
> + /* Output asm ("" : "=g" (ret) : "0" (val)); */
> + vec<tree, va_gc> *inputs = NULL;
> + vec<tree, va_gc> *outputs = NULL;
> + vec_safe_push (outputs,
> + build_tree_list
> + (build_tree_list
> + (NULL_TREE, build_string (2, "=g")),
> + ret));
> + vec_safe_push (inputs,
> + build_tree_list
> + (build_tree_list
> + (NULL_TREE, build_string (1, "0")),
> + val));
> + gasm *detach = gimple_build_asm_vec ("", inputs, outputs,
> + NULL, NULL);
> + gimple_set_location (detach, loc);
> + gsi_insert_before (gsip, detach, GSI_SAME_STMT);
> +
> + SSA_NAME_DEF_STMT (ret) = detach;
> +
> + return ret;
> +}
> +
> +/* Build a cond stmt out of COP, LHS, RHS, insert it before *GSIP with
> + location LOC. *GSIP must be at the end of a basic block. The succ
> + edge out of the block becomes the true or false edge opposite to
> + that in FLAGS. Create a new block with a single trap stmt, in the
> + cold partition if the function is partitioned,, and a new edge to
> + it as the other edge for the cond. */
> +
> +static inline void
> +insert_check_and_trap (location_t loc, gimple_stmt_iterator *gsip,
> + int flags, enum tree_code cop, tree lhs, tree rhs)
> +{
> + basic_block chk = gsi_bb (*gsip);
> +
> + gcond *cond = gimple_build_cond (cop, lhs, rhs, NULL, NULL);
> + gimple_set_location (cond, loc);
> + gsi_insert_before (gsip, cond, GSI_SAME_STMT);
> +
> + basic_block trp = create_empty_bb (chk);
> +
> + gimple_stmt_iterator gsit = gsi_after_labels (trp);
> + gcall *trap = gimple_build_call (builtin_decl_explicit (BUILT_IN_TRAP), 0);
> + gimple_set_location (trap, loc);
> + 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 = flags & (EDGE_TRUE_VALUE | EDGE_FALSE_VALUE);
> + gcc_assert (true_false_flag);
> + int neg_true_false_flag = (~flags) & (EDGE_TRUE_VALUE | EDGE_FALSE_VALUE);
> +
> + /* Remove the fallthru bit, and set the truth value for the
> + preexisting edge and for the newly-created one. In hardcbr,
> + FLAGS is taken from the edge of the original cond expr that we're
> + dealing with, so the reversed compare is expected to yield the
> + negated result, and the same result calls for a trap. In
> + hardcmp, we're comparing the boolean results of the original and
> + of the reversed compare, so we're passed FLAGS to trap on
> + equality. */
> + single_succ_edge (chk)->flags &= ~EDGE_FALLTHRU;
> + single_succ_edge (chk)->flags |= neg_true_false_flag;
> + edge e = make_edge (chk, trp, true_false_flag);
> + e->goto_locus = loc;
> +
> + 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);
> +}
> +
> +/* Split edge E, and insert_check_and_trap (see above) in the
> + newly-created block, using detached copies of LHS's and RHS's
> + values (see detach_value above) for the COP compare. */
> +
> +static inline void
> +insert_edge_check_and_trap (location_t loc, edge e,
> + enum tree_code cop, tree lhs, tree rhs)
> +{
> + int flags = e->flags;
> + basic_block src = e->src;
> + basic_block dest = e->dest;
> + location_t eloc = e->goto_locus;
> +
> + basic_block chk = split_edge (e);
> + e = NULL;
> +
> + single_pred_edge (chk)->goto_locus = loc;
> + single_succ_edge (chk)->goto_locus = eloc;
> +
> + if (dump_file)
> + fprintf (dump_file,
> + "Splitting edge %i->%i into block %i\n",
> + src->index, dest->index, chk->index);
> +
> + gimple_stmt_iterator gsik = gsi_after_labels (chk);
> +
> + bool same_p = (lhs == rhs);
> + lhs = detach_value (loc, &gsik, lhs);
> + rhs = same_p ? lhs : detach_value (loc, &gsik, rhs);
> +
> + insert_check_and_trap (loc, &gsik, flags, cop, lhs, rhs);
> +}
> +
> +/* Harden cond stmts at the end of FUN's blocks. */
> +
> +unsigned int
> +pass_harden_conditional_branches::execute (function *fun)
> +{
> + basic_block bb;
> + FOR_EACH_BB_REVERSE_FN (bb, fun)
> + {
> + gimple_stmt_iterator gsi = gsi_last_bb (bb);
> +
> + if (gsi_end_p (gsi))
> + continue;
> +
> + gcond *cond = dyn_cast <gcond *> (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.
> + */
> +
> + enum tree_code op = gimple_cond_code (cond);
> + tree lhs = gimple_cond_lhs (cond);
> + tree rhs = gimple_cond_rhs (cond);
> + location_t loc = gimple_location (cond);
> +
> + enum tree_code cop = invert_tree_comparison (op, HONOR_NANS (lhs));
> +
> + if (cop == ERROR_MARK)
> + /* ??? Can we do better? */
> + continue;
> +
> + insert_edge_check_and_trap (loc, EDGE_SUCC (bb, 0), cop, lhs, rhs);
> + insert_edge_check_and_trap (loc, EDGE_SUCC (bb, 1), cop, lhs, rhs);
> + }
> +
> + return 0;
> +}
> +
> +/* Instantiate a hardcbr pass. */
> +
> +gimple_opt_pass *
> +make_pass_harden_conditional_branches (gcc::context *ctxt)
> +{
> + return new pass_harden_conditional_branches (ctxt);
> +}
> +
> +/* Harden boolean-yielding compares in FUN. */
> +
> +unsigned int
> +pass_harden_compares::execute (function *fun)
> +{
> + basic_block bb;
> + /* Go backwards over BBs and stmts, so that, even if we split the
> + block multiple times to insert a cond_expr after each compare we
> + find, we remain in the same block, visiting every preexisting
> + stmt exactly once, and not visiting newly-added blocks or
> + stmts. */
> + FOR_EACH_BB_REVERSE_FN (bb, fun)
> + for (gimple_stmt_iterator gsi = gsi_last_bb (bb);
> + !gsi_end_p (gsi); gsi_prev (&gsi))
> + {
> + gassign *asgn = dyn_cast <gassign *> (gsi_stmt (gsi));
> + if (!asgn)
> + continue;
> +
> + /* Turn:
> +
> + z = x op y;
> +
> + into:
> +
> + z = x op y;
> + z' = x' cop y';
> + if (z == 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.
> + */
> +
> + enum tree_code op = 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 = invert_tree_comparison (op,
> + HONOR_NANS
> + (gimple_assign_rhs1 (asgn)));
> +
> + if (cop == ERROR_MARK)
> + /* ??? Can we do better? */
> + continue;
> +
> + break;
> +
> + /* ??? Maybe handle these too? */
> + case TRUTH_NOT_EXPR:
> + /* ??? The code below assumes binary ops, it would have to
> + be adjusted for TRUTH_NOT_EXPR, since it's 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. */
> + tree lhs = gimple_assign_lhs (asgn);
> + tree op1 = gimple_assign_rhs1 (asgn);
> + tree op2 = gimple_assign_rhs2 (asgn);
> + location_t loc = gimple_location (asgn);
> +
> + /* Vector booleans can't be used in conditional branches. ???
> + Can we do better? How to reduce compare and
> + reversed-compare result vectors to a single boolean? */
> + if (VECTOR_TYPE_P (TREE_TYPE (op1)))
> + continue;
> +
> + gcc_checking_assert (TREE_CODE (TREE_TYPE (lhs)) == BOOLEAN_TYPE);
> +
> + tree rhs = copy_ssa_name (lhs);
> +
> + gimple_stmt_iterator gsi_split = gsi;
> + /* Don't separate the original assignment from debug stmts
> + that might be associated with it, and arrange to split the
> + block after debug stmts, so as to make sure the split block
> + won't be debug stmts only. */
> + gsi_next_nondebug (&gsi_split);
> +
> + bool same_p = (op1 == op2);
> + op1 = detach_value (loc, &gsi_split, op1);
> + op2 = same_p ? op1 : detach_value (loc, &gsi_split, op2);
> +
> + gassign *asgnck = gimple_build_assign (rhs, cop, op1, op2);
> + gimple_set_location (asgnck, loc);
> + gsi_insert_before (&gsi_split, asgnck, GSI_SAME_STMT);
> +
> + /* We wish to insert a cond_expr after the compare, so arrange
> + for it to be at the end of a block if it isn't. */
> + 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));
> +
> + single_succ_edge (bb)->goto_locus = loc;
> +
> + if (dump_file)
> + fprintf (dump_file, "Splitting block %i\n", bb->index);
> + }
> +
> + gcc_checking_assert (single_succ_p (bb));
> +
> + insert_check_and_trap (loc, &gsi_split, EDGE_TRUE_VALUE,
> + EQ_EXPR, lhs, rhs);
> + }
> +
> + return 0;
> +}
> +
> +/* Instantiate a hardcmp pass. */
> +
> +gimple_opt_pass *
> +make_pass_harden_compares (gcc::context *ctxt)
> +{
> + return new pass_harden_compares (ctxt);
> +}
> diff --git a/gcc/passes.def b/gcc/passes.def
> index c11c237f6d204..268d8595a401e 100644
> --- a/gcc/passes.def
> +++ b/gcc/passes.def
> @@ -421,6 +421,8 @@ along with GCC; see the file COPYING3. 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.c b/gcc/testsuite/c-c++-common/torture/harden-comp.c
> new file mode 100644
> index 0000000000000..1ee0b3663443d
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/torture/harden-comp.c
> @@ -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 "hardcmp" } } */
> +/* { dg-final { scan-tree-dump-times "__builtin_trap" 1 "hardcmp" } } */
> +/* { dg-final { scan-tree-dump-times "_\[0-9\]* = i_\[0-9\]*\[(\]D\[)\] < j_\[0-9\]*\[(\]D\[)\];" 1 "hardcmp" } } */
> +/* { dg-final { scan-tree-dump-times "_\[0-9\]* = i_\[0-9\]* >= j_\[0-9\]*;" 1 "hardcmp" } } */
> diff --git a/gcc/testsuite/c-c++-common/torture/harden-cond.c b/gcc/testsuite/c-c++-common/torture/harden-cond.c
> new file mode 100644
> index 0000000000000..86de8e155ed38
> --- /dev/null
> +++ b/gcc/testsuite/c-c++-common/torture/harden-cond.c
> @@ -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 "hardcbr" } } */
> +/* { 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\]* >= j_\[0-9\]*\[)\]" 2 "hardcbr" } } */
> diff --git a/gcc/tree-pass.h b/gcc/tree-pass.h
> index d379769a94364..e807ad855efd1 100644
> --- a/gcc/tree-pass.h
> +++ b/gcc/tree-pass.h
> @@ -644,6 +644,9 @@ extern gimple_opt_pass *make_pass_update_address_taken (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::context
> + *ctxt);
>
> /* Current optimization pass. */
> extern opt_pass *current_pass;
>
>
> --
> Alexandre Oliva, happy hacker https://FSFLA.org/blogs/lxo/
> Free Software Activist GNU Toolchain Engineer
> Disinformation flourishes because many people care deeply about injustice
> but very few check the facts. Ask me about <https://stallmansupport.org>
next prev parent reply other threads:[~2021-10-26 8:22 UTC|newest]
Thread overview: 13+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-10-09 3:30 Alexandre Oliva
2021-10-09 6:42 ` Richard Biener
2021-10-12 6:35 ` Alexandre Oliva
2021-10-12 12:23 ` Richard Biener
2021-10-13 18:54 ` Alexandre Oliva
2021-10-14 7:49 ` Richard Biener
2021-10-15 18:35 ` Alexandre Oliva
2021-10-18 9:17 ` Richard Biener
2021-10-20 8:50 ` Alexandre Oliva
2021-10-22 2:19 ` Alexandre Oliva
2021-10-26 8:21 ` Richard Biener [this message]
2021-10-28 4:04 ` Alexandre Oliva
2021-10-30 9:44 ` Alexandre Oliva
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to='CAFiYyc1+=KN7Z6TUh7QAeObNZefNytXVWPjy84YuN-V2FXN64g@mail.gmail.com' \
--to=richard.guenther@gmail.com \
--cc=gcc-patches@gcc.gnu.org \
--cc=oliva@adacore.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).