[RFC][patch for gcc12][version 1] add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc

Qing Zhao QING.ZHAO@ORACLE.COM
Thu Feb 18 17:17:00 GMT 2021


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.zhao@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.zhao@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.zhao@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: New test.
	* g++.dg/auto-init-uninit-pred-loop-1_b.cc: New test.
	* g++.dg/auto-init-uninit-pred-loop-1_c.cc: New test.
	* g++.dg/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.
-------------- next part --------------
A non-text attachment was scrubbed...
Name: 0001-First-version-of-auto-variable-initialization.patch
Type: application/octet-stream
Size: 123713 bytes
Desc: not available
URL: <https://gcc.gnu.org/pipermail/gcc-patches/attachments/20210218/8547c927/attachment-0001.obj>
-------------- next part --------------




More information about the Gcc-patches mailing list