aboutsummaryrefslogtreecommitdiff
path: root/gcc/testsuite/gnat.dg
diff options
context:
space:
mode:
authorAlexandre Oliva <oliva@adacore.com>2023-10-20 07:50:33 -0300
committerAlexandre Oliva <oliva@gnu.org>2023-10-20 07:50:33 -0300
commit551935d11817dd5b139d66c36f62c0f0eba0db06 (patch)
treea7e31a9c19e1648559924732f586f94311c00165 /gcc/testsuite/gnat.dg
parente90c7bd520545b31fee687aab58cb4b258d1db16 (diff)
downloadgcc-551935d11817dd5b139d66c36f62c0f0eba0db06.zip
gcc-551935d11817dd5b139d66c36f62c0f0eba0db06.tar.gz
gcc-551935d11817dd5b139d66c36f62c0f0eba0db06.tar.bz2
Control flow redundancy hardening
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.
Diffstat (limited to 'gcc/testsuite/gnat.dg')
-rw-r--r--gcc/testsuite/gnat.dg/hardcfr.adb76
1 files changed, 76 insertions, 0 deletions
diff --git a/gcc/testsuite/gnat.dg/hardcfr.adb b/gcc/testsuite/gnat.dg/hardcfr.adb
new file mode 100644
index 0000000..abe1605
--- /dev/null
+++ b/gcc/testsuite/gnat.dg/hardcfr.adb
@@ -0,0 +1,76 @@
+-- { dg-do run }
+-- { dg-options "-fharden-control-flow-redundancy -fno-hardcfr-check-exceptions -fdump-tree-hardcfr --param=hardcfr-max-blocks=22 --param=hardcfr-max-inline-blocks=12 -O0" }
+
+procedure HardCFR is
+ function F (I, J : Integer) return Integer is
+ begin
+ if (I < J) then
+ return 2 * I;
+ else
+ return 3 * J;
+ end if;
+ end F;
+
+ function G (I : Natural; J : Integer) return Integer is
+ begin
+ case I is
+ when 0 =>
+ return J * 2;
+
+ when 1 =>
+ return J * 3;
+
+ when 2 =>
+ return J * 5;
+
+ when others =>
+ return J * 7;
+ end case;
+ end G;
+
+ function H (I : Natural; -- { dg-warning "has more than 22 blocks, the requested maximum" }
+ J : Integer)
+ return Integer is
+ begin
+ case I is
+ when 0 =>
+ return J * 2;
+
+ when 1 =>
+ return J * 3;
+
+ when 2 =>
+ return J * 5;
+
+ when 3 =>
+ return J * 7;
+
+ when 4 =>
+ return J * 11;
+
+ when 5 =>
+ return J * 13;
+
+ when 6 =>
+ return J * 17;
+
+ when 7 =>
+ return J * 19;
+
+ when others =>
+ return J * 23;
+ end case;
+ end H;
+begin
+ if (F (1, 2) /= 2 or else F (3, 2) /= 6
+ or else G (2, 5) /= 25 or else H (4, 3) /= 33)
+ then
+ raise Program_Error;
+ end if;
+end HardCFR;
+
+-- HardCFR and HardCFR.F:
+-- { dg-final { scan-tree-dump-times ".builtin_trap" 2 "hardcfr" } }
+
+-- This is __builtin___hardcfr_check in HardCFR.G:
+-- { dg-final { scan-tree-dump-times ".builtin " 1 "hardcfr" } }