Skip to content
Snippets Groups Projects
  • Alexandre Oliva's avatar
    551935d1
    Control flow redundancy hardening · 551935d1
    Alexandre Oliva authored
    This patch introduces an optional hardening pass to catch unexpected
    execution flows.  Functions are transformed so that basic blocks set a
    bit in an automatic array, and (non-exceptional) function exit edges
    check that the bits in the array represent an expected execution path
    in the CFG.
    
    Functions with multiple exit edges, or with too many blocks, call an
    out-of-line checker builtin implemented in libgcc.  For simpler
    functions, the verification is performed in-line.
    
    -fharden-control-flow-redundancy enables the pass for eligible
    functions, --param hardcfr-max-blocks sets a block count limit for
    functions to be eligible, and --param hardcfr-max-inline-blocks
    tunes the "too many blocks" limit for in-line verification.
    -fhardcfr-skip-leaf makes leaf functions non-eligible.
    
    Additional -fhardcfr-check-* options are added to enable checking at
    exception escape points, before potential sibcalls, hereby dubbed
    returning calls, and before noreturn calls and exception raises.  A
    notable case is the distinction between noreturn calls expected to
    throw and those expected to terminate or loop forever: the default
    setting for -fhardcfr-check-noreturn-calls, no-xthrow, performs
    checking before the latter, but the former only gets checking in the
    exception handler.  GCC can only tell between them by explicit marking
    noreturn functions expected to raise with the newly-introduced
    expected_throw attribute, and corresponding ECF_XTHROW flag.
    
    
    for  gcc/ChangeLog
    
    	* tree-core.h (ECF_XTHROW): New macro.
    	* tree.cc (set_call_expr): Add expected_throw attribute when
    	ECF_XTHROW is set.
    	(build_common_builtin_node): Add ECF_XTHROW to
    	__cxa_end_cleanup and _Unwind_Resume or _Unwind_SjLj_Resume.
    	* calls.cc (flags_from_decl_or_type): Check for expected_throw
    	attribute to set ECF_XTHROW.
    	* gimple.cc (gimple_build_call_from_tree): Propagate
    	ECF_XTHROW from decl flags to gimple call...
    	(gimple_call_flags): ... and back.
    	* gimple.h (GF_CALL_XTHROW): New gf_mask flag.
    	(gimple_call_set_expected_throw): New.
    	(gimple_call_expected_throw_p): New.
    	* Makefile.in (OBJS): Add gimple-harden-control-flow.o.
    	* builtins.def (BUILT_IN___HARDCFR_CHECK): New.
    	* common.opt (fharden-control-flow-redundancy): New.
    	(-fhardcfr-check-returning-calls): New.
    	(-fhardcfr-check-exceptions): New.
    	(-fhardcfr-check-noreturn-calls=*): New.
    	(Enum hardcfr_check_noreturn_calls): New.
    	(fhardcfr-skip-leaf): New.
    	* doc/invoke.texi: Document them.
    	(hardcfr-max-blocks, hardcfr-max-inline-blocks): New params.
    	* flag-types.h (enum hardcfr_noret): New.
    	* gimple-harden-control-flow.cc: New.
    	* params.opt (-param=hardcfr-max-blocks=): New.
    	(-param=hradcfr-max-inline-blocks=): New.
    	* passes.def (pass_harden_control_flow_redundancy): Add.
    	* tree-pass.h (make_pass_harden_control_flow_redundancy):
    	Declare.
    	* doc/extend.texi: Document expected_throw attribute.
    
    for  gcc/ada/ChangeLog
    
    	* gcc-interface/trans.cc (gigi): Mark __gnat_reraise_zcx with
    	ECF_XTHROW.
    	(build_raise_check): Likewise for all rcheck subprograms.
    
    for  gcc/c-family/ChangeLog
    
    	* c-attribs.cc (handle_expected_throw_attribute): New.
    	(c_common_attribute_table): Add expected_throw.
    
    for  gcc/cp/ChangeLog
    
    	* decl.cc (push_throw_library_fn): Mark with ECF_XTHROW.
    	* except.cc (build_throw): Likewise __cxa_throw,
    	_ITM_cxa_throw, __cxa_rethrow.
    
    for  gcc/testsuite/ChangeLog
    
    	* c-c++-common/torture/harden-cfr.c: New.
    	* c-c++-common/harden-cfr-noret-never-O0.c: New.
    	* c-c++-common/torture/harden-cfr-noret-never.c: New.
    	* c-c++-common/torture/harden-cfr-noret-noexcept.c: New.
    	* c-c++-common/torture/harden-cfr-noret-nothrow.c: New.
    	* c-c++-common/torture/harden-cfr-noret.c: New.
    	* c-c++-common/torture/harden-cfr-notail.c: New.
    	* c-c++-common/torture/harden-cfr-returning.c: New.
    	* c-c++-common/torture/harden-cfr-tail.c: New.
    	* c-c++-common/torture/harden-cfr-abrt-always.c: New.
    	* c-c++-common/torture/harden-cfr-abrt-never.c: New.
    	* c-c++-common/torture/harden-cfr-abrt-no-xthrow.c: New.
    	* c-c++-common/torture/harden-cfr-abrt-nothrow.c: New.
    	* c-c++-common/torture/harden-cfr-abrt.c: New.
    	* c-c++-common/torture/harden-cfr-always.c: New.
    	* c-c++-common/torture/harden-cfr-never.c: New.
    	* c-c++-common/torture/harden-cfr-no-xthrow.c: New.
    	* c-c++-common/torture/harden-cfr-nothrow.c: New.
    	* c-c++-common/torture/harden-cfr-bret-always.c: New.
    	* c-c++-common/torture/harden-cfr-bret-never.c: New.
    	* c-c++-common/torture/harden-cfr-bret-noopt.c: New.
    	* c-c++-common/torture/harden-cfr-bret-noret.c: New.
    	* c-c++-common/torture/harden-cfr-bret-no-xthrow.c: New.
    	* c-c++-common/torture/harden-cfr-bret-nothrow.c: New.
    	* c-c++-common/torture/harden-cfr-bret-retcl.c: New.
    	* c-c++-common/torture/harden-cfr-bret.c: New.
    	* g++.dg/harden-cfr-throw-always-O0.C: New.
    	* g++.dg/harden-cfr-throw-returning-O0.C: New.
    	* g++.dg/torture/harden-cfr-noret-always-no-nothrow.C: New.
    	* g++.dg/torture/harden-cfr-noret-never-no-nothrow.C: New.
    	* g++.dg/torture/harden-cfr-noret-no-nothrow.C: New.
    	* g++.dg/torture/harden-cfr-throw-always.C: New.
    	* g++.dg/torture/harden-cfr-throw-never.C: New.
    	* g++.dg/torture/harden-cfr-throw-no-xthrow.C: New.
    	* g++.dg/torture/harden-cfr-throw-no-xthrow-expected.C: New.
    	* g++.dg/torture/harden-cfr-throw-nothrow.C: New.
    	* g++.dg/torture/harden-cfr-throw-nocleanup.C: New.
    	* g++.dg/torture/harden-cfr-throw-returning.C: New.
    	* g++.dg/torture/harden-cfr-throw.C: New.
    	* gcc.dg/torture/harden-cfr-noret-no-nothrow.c: New.
    	* gcc.dg/torture/harden-cfr-tail-ub.c: New.
    	* gnat.dg/hardcfr.adb: New.
    
    for  libgcc/ChangeLog
    
    	* Makefile.in (LIB2ADD): Add hardcfr.c.
    	* hardcfr.c: New.
    551935d1
    History
    Control flow redundancy hardening
    Alexandre Oliva authored
    This patch introduces an optional hardening pass to catch unexpected
    execution flows.  Functions are transformed so that basic blocks set a
    bit in an automatic array, and (non-exceptional) function exit edges
    check that the bits in the array represent an expected execution path
    in the CFG.
    
    Functions with multiple exit edges, or with too many blocks, call an
    out-of-line checker builtin implemented in libgcc.  For simpler
    functions, the verification is performed in-line.
    
    -fharden-control-flow-redundancy enables the pass for eligible
    functions, --param hardcfr-max-blocks sets a block count limit for
    functions to be eligible, and --param hardcfr-max-inline-blocks
    tunes the "too many blocks" limit for in-line verification.
    -fhardcfr-skip-leaf makes leaf functions non-eligible.
    
    Additional -fhardcfr-check-* options are added to enable checking at
    exception escape points, before potential sibcalls, hereby dubbed
    returning calls, and before noreturn calls and exception raises.  A
    notable case is the distinction between noreturn calls expected to
    throw and those expected to terminate or loop forever: the default
    setting for -fhardcfr-check-noreturn-calls, no-xthrow, performs
    checking before the latter, but the former only gets checking in the
    exception handler.  GCC can only tell between them by explicit marking
    noreturn functions expected to raise with the newly-introduced
    expected_throw attribute, and corresponding ECF_XTHROW flag.
    
    
    for  gcc/ChangeLog
    
    	* tree-core.h (ECF_XTHROW): New macro.
    	* tree.cc (set_call_expr): Add expected_throw attribute when
    	ECF_XTHROW is set.
    	(build_common_builtin_node): Add ECF_XTHROW to
    	__cxa_end_cleanup and _Unwind_Resume or _Unwind_SjLj_Resume.
    	* calls.cc (flags_from_decl_or_type): Check for expected_throw
    	attribute to set ECF_XTHROW.
    	* gimple.cc (gimple_build_call_from_tree): Propagate
    	ECF_XTHROW from decl flags to gimple call...
    	(gimple_call_flags): ... and back.
    	* gimple.h (GF_CALL_XTHROW): New gf_mask flag.
    	(gimple_call_set_expected_throw): New.
    	(gimple_call_expected_throw_p): New.
    	* Makefile.in (OBJS): Add gimple-harden-control-flow.o.
    	* builtins.def (BUILT_IN___HARDCFR_CHECK): New.
    	* common.opt (fharden-control-flow-redundancy): New.
    	(-fhardcfr-check-returning-calls): New.
    	(-fhardcfr-check-exceptions): New.
    	(-fhardcfr-check-noreturn-calls=*): New.
    	(Enum hardcfr_check_noreturn_calls): New.
    	(fhardcfr-skip-leaf): New.
    	* doc/invoke.texi: Document them.
    	(hardcfr-max-blocks, hardcfr-max-inline-blocks): New params.
    	* flag-types.h (enum hardcfr_noret): New.
    	* gimple-harden-control-flow.cc: New.
    	* params.opt (-param=hardcfr-max-blocks=): New.
    	(-param=hradcfr-max-inline-blocks=): New.
    	* passes.def (pass_harden_control_flow_redundancy): Add.
    	* tree-pass.h (make_pass_harden_control_flow_redundancy):
    	Declare.
    	* doc/extend.texi: Document expected_throw attribute.
    
    for  gcc/ada/ChangeLog
    
    	* gcc-interface/trans.cc (gigi): Mark __gnat_reraise_zcx with
    	ECF_XTHROW.
    	(build_raise_check): Likewise for all rcheck subprograms.
    
    for  gcc/c-family/ChangeLog
    
    	* c-attribs.cc (handle_expected_throw_attribute): New.
    	(c_common_attribute_table): Add expected_throw.
    
    for  gcc/cp/ChangeLog
    
    	* decl.cc (push_throw_library_fn): Mark with ECF_XTHROW.
    	* except.cc (build_throw): Likewise __cxa_throw,
    	_ITM_cxa_throw, __cxa_rethrow.
    
    for  gcc/testsuite/ChangeLog
    
    	* c-c++-common/torture/harden-cfr.c: New.
    	* c-c++-common/harden-cfr-noret-never-O0.c: New.
    	* c-c++-common/torture/harden-cfr-noret-never.c: New.
    	* c-c++-common/torture/harden-cfr-noret-noexcept.c: New.
    	* c-c++-common/torture/harden-cfr-noret-nothrow.c: New.
    	* c-c++-common/torture/harden-cfr-noret.c: New.
    	* c-c++-common/torture/harden-cfr-notail.c: New.
    	* c-c++-common/torture/harden-cfr-returning.c: New.
    	* c-c++-common/torture/harden-cfr-tail.c: New.
    	* c-c++-common/torture/harden-cfr-abrt-always.c: New.
    	* c-c++-common/torture/harden-cfr-abrt-never.c: New.
    	* c-c++-common/torture/harden-cfr-abrt-no-xthrow.c: New.
    	* c-c++-common/torture/harden-cfr-abrt-nothrow.c: New.
    	* c-c++-common/torture/harden-cfr-abrt.c: New.
    	* c-c++-common/torture/harden-cfr-always.c: New.
    	* c-c++-common/torture/harden-cfr-never.c: New.
    	* c-c++-common/torture/harden-cfr-no-xthrow.c: New.
    	* c-c++-common/torture/harden-cfr-nothrow.c: New.
    	* c-c++-common/torture/harden-cfr-bret-always.c: New.
    	* c-c++-common/torture/harden-cfr-bret-never.c: New.
    	* c-c++-common/torture/harden-cfr-bret-noopt.c: New.
    	* c-c++-common/torture/harden-cfr-bret-noret.c: New.
    	* c-c++-common/torture/harden-cfr-bret-no-xthrow.c: New.
    	* c-c++-common/torture/harden-cfr-bret-nothrow.c: New.
    	* c-c++-common/torture/harden-cfr-bret-retcl.c: New.
    	* c-c++-common/torture/harden-cfr-bret.c: New.
    	* g++.dg/harden-cfr-throw-always-O0.C: New.
    	* g++.dg/harden-cfr-throw-returning-O0.C: New.
    	* g++.dg/torture/harden-cfr-noret-always-no-nothrow.C: New.
    	* g++.dg/torture/harden-cfr-noret-never-no-nothrow.C: New.
    	* g++.dg/torture/harden-cfr-noret-no-nothrow.C: New.
    	* g++.dg/torture/harden-cfr-throw-always.C: New.
    	* g++.dg/torture/harden-cfr-throw-never.C: New.
    	* g++.dg/torture/harden-cfr-throw-no-xthrow.C: New.
    	* g++.dg/torture/harden-cfr-throw-no-xthrow-expected.C: New.
    	* g++.dg/torture/harden-cfr-throw-nothrow.C: New.
    	* g++.dg/torture/harden-cfr-throw-nocleanup.C: New.
    	* g++.dg/torture/harden-cfr-throw-returning.C: New.
    	* g++.dg/torture/harden-cfr-throw.C: New.
    	* gcc.dg/torture/harden-cfr-noret-no-nothrow.c: New.
    	* gcc.dg/torture/harden-cfr-tail-ub.c: New.
    	* gnat.dg/hardcfr.adb: New.
    
    for  libgcc/ChangeLog
    
    	* Makefile.in (LIB2ADD): Add hardcfr.c.
    	* hardcfr.c: New.