(CC’ing Kees Cook on this topic) Hi,
This is the first version of the complete patch for the new security feature for GCC: Initialize automatic variables with new first class option -ftrivial-auto-var-init=[uninitialized|pattern|zero] and a new variable attribute “uninitialized” to exclude some variables from automatical initialization to Control runtime overhead. ==== '-ftrivial-auto-var-init=CHOICE' Initialize automatic variables with either a pattern or with zeroes to increase program security by preventing uninitialized memory disclosure and use. The three values of CHOICE are: * 'uninitialized' doesn't initialize any automatic variables. This is C and C++'s default. * 'pattern' Initialize automatic variables with values which will likely transform logic bugs into crashes down the line, are easily recognized in a crash dump and without being values that programmers can rely on for useful program semantics. The values used for pattern initialization might be changed in the future. * 'zero' Initialize automatic variables with zeroes. The default is 'uninitialized'. You can control this behavior for a specific variable by using the variable attribute 'uninitialized' (*note Variable Attributes::). 'uninitialized' This attribute, attached to a variable with automatic storage, means that the variable should not be automatically initialized by the compiler when the option '-ftrivial-auto-var-init' presents. With the option '-ftrivial-auto-var-init', all the automatic variables that do not have explicit initializers will be initialized by the compiler. These additional compiler initializations might incur run-time overhead, sometimes dramatically. This attribute can be used to mark some variables to be excluded from such automatical initialization in order to reduce runtime overhead. This attribute has no effect when the option '-ftrivial-auto-var-init' does not present. ==== ******This implementation has the following features: 1. A new internal function .DEFERRED_INIT is introduced; 2. During gimplification phase, calls to .DEFERRED_INIT will be inserted for the initialization; 3. During expand phase, calls to .DEFERRED_INIT are expanded to real “zero” or “pattern” initialization; 4. In order to maintain the -Wuninitialized warning, uninitialized warning phase is adjusted to specially handling the calls to .DEFERRED_INIT; 5. In order to reduce the stack usage per strength reduction transformation, the strength reduction phase Is adjusted to specially handle the calls to .DEFERRED_INIT; 6. Point to analysis also is adjusted to specially handle the calls to .DEFERRED_INIT; 7. VLA auto variables are initialized specially, for “zero” initialization, add a call to MEMSET to initialize it; for “pattern” initialization, add a loop of calls to MEMCPY to initialize it; 8. For “pattern” initialization, used the similar patten as LLVM implementation for integers and pointers: + /* The following value is a guaranteed unmappable pointer value and has a + repeated byte-pattern which makes it easier to synthesize. We use it for + pointers as well as integers so that aggregates are likely to be + initialized with this repeated value. */ + uint64_t largevalue = 0xAAAAAAAAAAAAAAAAull; + /* For 32-bit platforms it's a bit trickier because, across systems, only the + zero page can reasonably be expected to be unmapped, and even then we need + a very low address. We use a smaller value, and that value sadly doesn't + have a repeated byte-pattern. We don't use it for integers. */ + uint32_t smallvalue = 0x000000AA; Use quiet NAN for real type. ******testing cases: 1. In c-c++-common, verification at gimple level for all types, all combination of options, new attributes; 2. In gcc.target, (for x86 and aarch64) verification at RTL or assembly level for all types, all combination of options, new attributes; 3. In gcc.dg and g++.dg, verification of the new option still keep the -Wuninitialized warnings. Copy the existing uninit-*.c to auto-init-uninit-*.c, add the new option -ftrivial-auto-var-init=zero to it. ******NOTE for the review: ****In this version implementation, I still keep the implementation to the following two approaches for your references: A. Adding real initialization during gimplification, not maintain the uninitialized warnings. D. Adding .DEFFERED_INIT during gimplification, expand the .DEFFERED_INIT during expand to real initialization. Adjusting uninitialized pass with the new refs with “.DEFFERED_INIT” A is the approach that I will delete in the next version. D will be the one we choose. (The reason I kept both implementation is, please check the implementation for both A and D since the performance, code size, stack size data are all based on the comparison between A and D, Please help me to make sure both the implementation is correct) Currently, there is a first class option -fauto-var-init-approach=[A|B|C|D]. is added to choose A or D. If after the review, there is no issue, I will delete the code related to “A” in the next version. ****There are several places, I put “FIXME” in the comments, please review those part and let me know any issues with those parts. *******Changelog: gcc/ChangeLog: 2021-02-17 qing zhao <qing.z...@oracle.com <mailto:qing.z...@oracle.com>> * common.opt (ftrivial-auto-var-init=): New. (fauto-var-init-approach=): Likewise. * doc/extend.texi: Document the uninitialized attribute. * doc/invoke.texi: Document -ftrivial-auto-var-init. * flag-types.h (enum auto_init_type): New enumerated type auto_init_type. (enum auto_init_approach): New enumerated type auto_init_approach. * gimple.h (enum gf_mask): Add GF_CALL_MEMSET_FOR_UNINIT case. (gimple_call_set_memset_for_uninit): New function. (gimple_call_memset_for_uninit_p): Likewise. * gimplify.c (gimplify_vla_decl): Add initialization to vla per users' requests. (build_deferred_init): New function. (gimple_add_init_for_auto_var): Likewise. (gimplify_decl_expr): Add initialization to automatic variables per users' requests. * internal-fn.c (expand_DEFERRED_INIT): New function. * internal-fn.def (DEFERRED_INIT): New internal function. * tree-cfg.c (verify_gimple_call): Skip calls to DEFERRED_INIT. * tree-core.h (tree_decl_with_vis): Add uninitialized field. * tree-sra.c (sra_stats): Add two new fields deferred_init and subtree_deferred_init. (generate_subtree_deferred_init): New function. (sra_modify_deferred_init): Likewise. (sra_modify_function_body): Handle calls to DEFERRED_INIT specially. * tree-ssa-structalias.c (find_func_aliases_for_deferred_init): New function. (find_func_aliases_for_call): Handle calls to DEFERRED_INIT specially. * tree-ssa-uninit.c (warn_uninit): Handle calls to DEFERRED_INIT specially. (check_defs): Handle calls to DEFERRED_INIT and MEMSET for uninitialized variable specially. (warn_uninitialized_vars): Handle calls to DEFERRED_INIT specially. * tree-ssa.c (ssa_undefined_value_p): Handle calls to DEFERRED_INIT specially. * tree.c (build_pattern_cst): New function. * tree.h (DECL_UNINITIALIZED): New macro. (build_pattern_cst): New declaration. gcc/c-family/ChangeLog: 2021-02-17 qing zhao <qing.z...@oracle.com <mailto:qing.z...@oracle.com>> * c-attribs.c (handle_uninitialized_attribute): New function. (c_common_attribute_table): Add "uninitialized" attribute. gcc/testsuite/ChangeLog: 2021-02-17 qing zhao <qing.z...@oracle.com <mailto:qing.z...@oracle.com>> * c-c++-common/auto-init-1.c: New test. * c-c++-common/auto-init-10.c: New test. * c-c++-common/auto-init-11.c: New test. * c-c++-common/auto-init-12.c: New test. * c-c++-common/auto-init-2.c: New test. * c-c++-common/auto-init-3.c: New test. * c-c++-common/auto-init-4.c: New test. * c-c++-common/auto-init-5.c: New test. * c-c++-common/auto-init-6.c: New test. * c-c++-common/auto-init-7.c: New test. * c-c++-common/auto-init-8.c: New test. * c-c++-common/auto-init-9.c: New test. * c-c++-common/auto-init-esra.c: New test. * g++.dg/auto-init-uninit-pred-1_a.C: New test. * g++.dg/auto-init-uninit-pred-1_b.C: New test. * g++.dg/auto-init-uninit-pred-2_a.C: New test. * g++.dg/auto-init-uninit-pred-2_b.C: New test. * g++.dg/auto-init-uninit-pred-3_a.C: New test. * g++.dg/auto-init-uninit-pred-3_b.C: New test. * g++.dg/auto-init-uninit-pred-4.C: New test. * g++.dg/auto-init-uninit-pred-loop-1_a.cc <http://auto-init-uninit-pred-loop-1_a.cc/>: New test. * g++.dg/auto-init-uninit-pred-loop-1_b.cc <http://auto-init-uninit-pred-loop-1_b.cc/>: New test. * g++.dg/auto-init-uninit-pred-loop-1_c.cc <http://auto-init-uninit-pred-loop-1_c.cc/>: New test. * g++.dg/auto-init-uninit-pred-loop_1.cc <http://auto-init-uninit-pred-loop_1.cc/>: New test. * gcc.dg/auto-init-uninit-1.c: New test. * gcc.dg/auto-init-uninit-11.c: New test. * gcc.dg/auto-init-uninit-12.c: New test. * gcc.dg/auto-init-uninit-13.c: New test. * gcc.dg/auto-init-uninit-14.c: New test. * gcc.dg/auto-init-uninit-15.c: New test. * gcc.dg/auto-init-uninit-16.c: New test. * gcc.dg/auto-init-uninit-17.c: New test. * gcc.dg/auto-init-uninit-18.c: New test. * gcc.dg/auto-init-uninit-19.c: New test. * gcc.dg/auto-init-uninit-2.c: New test. * gcc.dg/auto-init-uninit-20.c: New test. * gcc.dg/auto-init-uninit-21.c: New test. * gcc.dg/auto-init-uninit-22.c: New test. * gcc.dg/auto-init-uninit-23.c: New test. * gcc.dg/auto-init-uninit-24.c: New test. * gcc.dg/auto-init-uninit-25.c: New test. * gcc.dg/auto-init-uninit-26.c: New test. * gcc.dg/auto-init-uninit-3.c: New test. * gcc.dg/auto-init-uninit-34.c: New test. * gcc.dg/auto-init-uninit-36.c: New test. * gcc.dg/auto-init-uninit-37.c: New test. * gcc.dg/auto-init-uninit-4.c: New test. * gcc.dg/auto-init-uninit-5.c: New test. * gcc.dg/auto-init-uninit-6.c: New test. * gcc.dg/auto-init-uninit-8.c: New test. * gcc.dg/auto-init-uninit-9.c: New test. * gcc.dg/auto-init-uninit-A.c: New test. * gcc.dg/auto-init-uninit-B.c: New test. * gcc.dg/auto-init-uninit-C.c: New test. * gcc.dg/auto-init-uninit-H.c: New test. * gcc.dg/auto-init-uninit-I.c: New test. * gcc.target/aarch64/auto-init-1.c: New test. * gcc.target/aarch64/auto-init-2.c: New test. * gcc.target/aarch64/auto-init-3.c: New test. * gcc.target/aarch64/auto-init-4.c: New test. * gcc.target/aarch64/auto-init-5.c: New test. * gcc.target/aarch64/auto-init-6.c: New test. * gcc.target/aarch64/auto-init-7.c: New test. * gcc.target/aarch64/auto-init-8.c: New test. * gcc.target/i386/auto-init-1.c: New test. * gcc.target/i386/auto-init-2.c: New test. * gcc.target/i386/auto-init-3.c: New test. * gcc.target/i386/auto-init-4.c: New test. * gcc.target/i386/auto-init-5.c: New test. * gcc.target/i386/auto-init-6.c: New test. * gcc.target/i386/auto-init-7.c: New test. * gcc.target/i386/auto-init-8.c: New test. ******the complete patch: See the attachment.