public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
* [PATCH][version 3]add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
@ 2021-05-12 17:16 Qing Zhao
  2021-05-25 19:26 ` Qing Zhao
  2021-05-26 11:18 ` Richard Biener
  0 siblings, 2 replies; 57+ messages in thread
From: Qing Zhao @ 2021-05-12 17:16 UTC (permalink / raw)
  To: richard Sandiford, Richard Biener; +Cc: kees Cook, gcc-patches Qing Zhao via

[-- Attachment #1: Type: text/plain, Size: 2557 bytes --]

Hi, 

This is the 3rd version of the patch for the new security feature for GCC.

Please take look and let me know your comments and suggestions.

thanks.

Qing

******Compare with the 2nd version, the following are the major changes:

1. use "lookup_attribute ("uninitialized",) directly instead of adding
   one new field "uninitialized" into tree_decl_with_vis.
2. update documentation to mention that the new option will not confuse
   -Wuninitialized, GCC still consider an auto without explicit initializer
   as uninitialized.
3. change the name of "build_pattern_cst" to more specific name as
   "build_pattern_cst_for_auto_init".
4. handling of nested VLA;
   Adding new testing cases (auto-init-15/16.c) for this new handling.
5. Add  new verifications of calls to .DEFERRED_INIT in tree-cfg.c;
6. in tree-sra.c, update the handling of "grp_to_be_debug_replaced",
   bind the lhs variable to a call to .DEFERRED_INIT.
7. In tree-ssa-structalias.c, delete "find_func_aliases_for_deferred_init",
   return directly for a call to .DEFERRED_INIT in "find_func_aliases_for_call".
8. Add more detailed comments in tree-ssa-uninit.c and tree-ssa.c to explain
   the special handling on REALPART_EXPR/IMAGPRT_EXPR.
9. in build_pattern_cst_for_auto_init:
   BOOLEAN_TYPE will be set to zero always;
   INTEGER_TYPE (?and ENUMERAL_TYPE) use wi::from_buffer in order to
                correctly handle 128-bit integers.
   POINTER_TYPE will not assert on SIZE < 32.
   REAL_TYPE add fallback;
10. changed gcc_assert to gcc_unreachable in several places;
11. add more comments;
12. some style issue changes.

******Please see the version 2 at:
https://gcc.gnu.org/pipermail/gcc-patches/2021-March/567262.html


******The following 2 items are the ones I didn’t addressed in this version due to further study and might need more discussion:

1. Using __builtin_clear_padding  to replace type_has_padding.

My study shows: the call to __builtin_clear_padding is expanded during gimplification phase.  
And there is no __bultin_clear_padding expanding during rtx expanding phase.
If so,  for -ftrivial-auto-var-init, padding initialization should be done both in gimplification phase and rtx expanding phase. 
And since the __builtin_clear_padding might not be good for rtx expanding, reusing __builtin_clear_padding might not work.

2. Pattern init to NULLPTR_TYPE and ENUMERAL_TYPE: need more comments from Richard Biener on this.

******The change of the 3rd version compared to the 2nd version are:


[-- Attachment #2: change-against-2nd-version.patch --]
[-- Type: application/octet-stream, Size: 28385 bytes --]

From 1b2317d1444b3ba43302223a7ba40f899ff2bdc0 Mon Sep 17 00:00:00 2001
From: qing zhao <qing.zhao@oracle.com>
Date: Mon, 3 May 2021 22:40:03 +0000
Subject: [PATCH] change of 2nd version

---
 gcc/c-family/c-attribs.c                  |  6 +-
 gcc/doc/invoke.texi                       |  6 +-
 gcc/gimplify.c                            | 24 ++++---
 gcc/internal-fn.c                         |  2 +-
 gcc/testsuite/c-c++-common/auto-init-15.c | 13 ++++
 gcc/testsuite/c-c++-common/auto-init-16.c | 13 ++++
 gcc/tree-cfg.c                            | 57 ++++++++++++-----
 gcc/tree-core.h                           |  3 +-
 gcc/tree-sra.c                            | 76 ++++++++++++++---------
 gcc/tree-ssa-structalias.c                | 28 +--------
 gcc/tree-ssa-uninit.c                     | 33 ++++++++--
 gcc/tree-ssa.c                            | 27 +++++++-
 gcc/tree.c                                | 75 +++++++++++++---------
 gcc/tree.h                                |  6 +-
 14 files changed, 239 insertions(+), 130 deletions(-)
 create mode 100644 gcc/testsuite/c-c++-common/auto-init-15.c
 create mode 100644 gcc/testsuite/c-c++-common/auto-init-16.c

diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c
index 7684b83ed67f..de53c3a2da88 100644
--- a/gcc/c-family/c-attribs.c
+++ b/gcc/c-family/c-attribs.c
@@ -1526,16 +1526,14 @@ handle_unused_attribute (tree *node, tree name, tree ARG_UNUSED (args),
   return NULL_TREE;
 }
 
-/* Handle a "uninitialized" attribute; arguments as in
+/* Handle an "uninitialized" attribute; arguments as in
    struct attribute_spec.handler.  */
 
 static tree
 handle_uninitialized_attribute (tree *node, tree name, tree ARG_UNUSED (args),
 				int ARG_UNUSED (flags), bool *no_add_attrs)
 {
-  if (VAR_P (*node))
-    DECL_UNINITIALIZED (*node) = 1;
-  else
+  if (!VAR_P (*node))
     {
       warning (OPT_Wattributes, "%qE attribute ignored", name);
       *no_add_attrs = true;
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 508f27fd7a91..e68cbb13d9e8 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -11553,7 +11553,11 @@ and @option{-fauto-profile}.
 @item -ftrivial-auto-var-init=@var{choice}
 @opindex ftrivial-auto-var-init
 Initialize automatic variables with either a pattern or with zeroes to increase
-program security by preventing uninitialized memory disclosure and use.
+the security and predictability of a program by preventing uninitialized memory
+disclosure and use.
+GCC still considers an automatic variable that doesn't have an explicit
+initializer as uninitialized, -Wuninitialized will still report warning messages
+on such automatic variables.
 
 The three values of @var{choice} are:
 
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index 3be830199f67..b14e79a84fd4 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -1718,7 +1718,7 @@ gimplify_vla_decl (tree decl, gimple_seq *seq_p)
       && VAR_P (decl)
       && !DECL_EXTERNAL (decl)
       && !TREE_STATIC (decl)
-      && !DECL_UNINITIALIZED (decl))
+      && !lookup_attribute ("uninitialized", DECL_ATTRIBUTES (decl)))
     switch (flag_trivial_auto_var_init)
       {
       case AUTO_INIT_UNINITIALIZED:
@@ -1743,7 +1743,7 @@ gimplify_vla_decl (tree decl, gimple_seq *seq_p)
 	      {
 		element_type = TREE_TYPE (TREE_TYPE (decl));
 		size_of_element = DECL_SIZE_UNIT (element_type);
-		init_node = build_pattern_cst (element_type);
+		init_node = build_pattern_cst_for_auto_init (element_type);
 		cur = addr;
 		offset = DECL_SIZE_UNIT (decl) - size_of_element;
 		end = addr + offset;
@@ -1769,6 +1769,10 @@ gimplify_vla_decl (tree decl, gimple_seq *seq_p)
 	  tree label_loop = create_artificial_label (UNKNOWN_LOCATION);
 
 	  element_type = TREE_TYPE (TREE_TYPE (decl));
+	  /* If this is a nested array, we should go down to the element that
+	     is not an array.  */
+	  while (TREE_CODE (element_type) == ARRAY_TYPE)
+	    element_type = TREE_TYPE (element_type);
 
 	  gcond *cond_stmt = gimple_build_cond (GT_EXPR, DECL_SIZE_UNIT (decl),
 						build_zero_cst (sizetype),
@@ -1787,7 +1791,9 @@ gimplify_vla_decl (tree decl, gimple_seq *seq_p)
 
 	  gimplify_assign (size_of_element, TYPE_SIZE_UNIT (element_type),
 			   seq_p);
-	  gimplify_assign (init_node, build_pattern_cst (element_type), seq_p);
+	  gimplify_assign (init_node,
+			   build_pattern_cst_for_auto_init (element_type),
+			   seq_p);
 
 	  cur = create_tmp_var (ptr_type, ".cur_addr");
 	  end = create_tmp_var (ptr_type, ".end_addr");
@@ -1849,10 +1855,7 @@ force_labels_r (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
    1st argument: DECL;
    2nd argument: INIT_TYPE;
 
-   as DEFERRED_INIT (DECL, INIT_TYPE)
-
-   DEFERRED_INIT is defined as:
-   DEF_INTERNAL_FN(DEFERRED_INIT, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL).  */
+   as DEFERRED_INIT (DECL, INIT_TYPE).  */
 
 static gimple *
 build_deferred_init (tree decl,
@@ -1882,7 +1885,7 @@ gimple_add_init_for_auto_var (tree decl,
     if (init_approach == AUTO_INIT_A)
     {
       tree init = (init_type == AUTO_INIT_PATTERN)
-		   ? build_pattern_cst (TREE_TYPE (decl)) :
+		   ? build_pattern_cst_for_auto_init (TREE_TYPE (decl)) :
 		   build_zero_cst (TREE_TYPE (decl));
       init = build2 (INIT_EXPR, void_type_node, decl, init);
       gimplify_and_add (init, seq_p);
@@ -1992,9 +1995,10 @@ gimplify_decl_expr (tree *stmt_p, gimple_seq *seq_p)
 	}
       /* When there is no explicit initializer, if the user requested,
 	 We should insert an artifical initializer for this automatic
-	 variable for non vla variables.  */
+	 variable for non VLA variables.  VLA variables are handled
+	 in gimplify_vla_decl differently.  */
       else if (flag_trivial_auto_var_init > AUTO_INIT_UNINITIALIZED
-	       && !DECL_UNINITIALIZED (decl)
+	       && !lookup_attribute ("uninitialized", DECL_ATTRIBUTES (decl))
 	       && !TREE_STATIC (decl)
 	       && !is_vla)
 	gimple_add_init_for_auto_var (decl,
diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c
index 35de829dcf83..28d23e923b3c 100644
--- a/gcc/internal-fn.c
+++ b/gcc/internal-fn.c
@@ -2985,7 +2985,7 @@ expand_DEFERRED_INIT (internal_fn, gcall *stmt)
     default:
       gcc_unreachable ();
     case AUTO_INIT_PATTERN:
-      init = build_pattern_cst (TREE_TYPE (var));
+      init = build_pattern_cst_for_auto_init (TREE_TYPE (var));
       expand_assignment (var, init, false);
       break;
     case AUTO_INIT_ZERO:
diff --git a/gcc/testsuite/c-c++-common/auto-init-15.c b/gcc/testsuite/c-c++-common/auto-init-15.c
new file mode 100644
index 000000000000..6f12f96ac1e2
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/auto-init-15.c
@@ -0,0 +1,13 @@
+/* Verify the auto initialization of nested VLA.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=zero -fdump-tree-gimple" } */
+
+void g(void *);
+
+void foo(int a)
+{
+  int x[a][a];
+  g(x);
+}
+
+/* { dg-final { scan-tree-dump "__builtin_memset" "gimple" } } */
diff --git a/gcc/testsuite/c-c++-common/auto-init-16.c b/gcc/testsuite/c-c++-common/auto-init-16.c
new file mode 100644
index 000000000000..c6a3627da542
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/auto-init-16.c
@@ -0,0 +1,13 @@
+/* Verify the auto initialization of nested VLA.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern -fdump-tree-gimple" } */
+
+void g(void *);
+
+void foo(int a)
+{
+  int x[a][a];
+  g(x);
+}
+
+/* { dg-final { scan-tree-dump "__builtin_memcpy" "gimple" } } */
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index 3717c6d26a54..8ffcc6675893 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -3433,27 +3433,56 @@ verify_gimple_call (gcall *stmt)
 	}
     }
 
+  /* For a call to .DEFERRED_INIT, we should guarantee that the lhs is
+     the same as the first argument of the call.  */
   if (gimple_call_internal_p (stmt, IFN_DEFERRED_INIT))
-    return false;
+    {
+      tree arg0 = gimple_call_arg (stmt, 0);
+      if (TREE_CODE (lhs) == SSA_NAME)
+	lhs = SSA_NAME_VAR (lhs);
+      if (TREE_CODE (arg0) == SSA_NAME)
+	arg0 = SSA_NAME_VAR (arg0);
+      if (lhs != arg0)
+	{
+	  error ("%<DEFFERED_INIT%> calls should have the same LHS as the "
+		 "first argument");
+	  return true;
+	}
+    }
 
+  /* We will not verify the arguments for the calls to .DEFERRED_INIT.
+     Such call is not a real call, just a placeholder for a later
+     initialization during expand phase.
+     This is mainly to avoid assertion failure for the following
+     case:
+
+     uni_var = .DEFERRED_INIT (uni_var, INIT_TYPE);
+     foo (&uni_var);
+
+     in the above, the uninitialized auto variable "uni_var" is
+     addressable, therefore should not be in registers, resulting
+     the assertion failure in the following argument verification.  */
+  if (gimple_call_internal_p (stmt, IFN_DEFERRED_INIT))
+    return false;
   /* ???  The C frontend passes unpromoted arguments in case it
      didn't see a function declaration before the call.  So for now
      leave the call arguments mostly unverified.  Once we gimplify
      unit-at-a-time we have a chance to fix this.  */
 
-  for (i = 0; i < gimple_call_num_args (stmt); ++i)
-    {
-      tree arg = gimple_call_arg (stmt, i);
-      if ((is_gimple_reg_type (TREE_TYPE (arg))
-	   && !is_gimple_val (arg))
-	  || (!is_gimple_reg_type (TREE_TYPE (arg))
-	      && !is_gimple_lvalue (arg)))
-	{
-	  error ("invalid argument to gimple call");
-	  debug_generic_expr (arg);
-	  return true;
-	}
-    }
+  else
+    for (i = 0; i < gimple_call_num_args (stmt); ++i)
+      {
+	tree arg = gimple_call_arg (stmt, i);
+	if ((is_gimple_reg_type (TREE_TYPE (arg))
+	     && !is_gimple_val (arg))
+	    || (!is_gimple_reg_type (TREE_TYPE (arg))
+		&& !is_gimple_lvalue (arg)))
+	  {
+	    error ("invalid argument to gimple call");
+	    debug_generic_expr (arg);
+	    return true;
+	  }
+      }
 
   return false;
 }
diff --git a/gcc/tree-core.h b/gcc/tree-core.h
index 02f580e5f04c..2e0e76ea8838 100644
--- a/gcc/tree-core.h
+++ b/gcc/tree-core.h
@@ -1808,7 +1808,6 @@ struct GTY(()) tree_decl_with_vis {
  unsigned in_text_section : 1;
  unsigned in_constant_pool : 1;
  unsigned dllimport_flag : 1;
- unsigned uninitialized : 1;
  /* Don't belong to VAR_DECL exclusively.  */
  unsigned weak_flag : 1;
 
@@ -1830,7 +1829,7 @@ struct GTY(()) tree_decl_with_vis {
  unsigned final : 1;
  /* Belong to FUNCTION_DECL exclusively.  */
  unsigned regdecl_flag : 1;
- /* 13 unused bits.  */
+ /* 14 unused bits.  */
  /* 32 more unused on 64 bit HW. */
 };
 
diff --git a/gcc/tree-sra.c b/gcc/tree-sra.c
index 302a123bf549..4c74df272141 100644
--- a/gcc/tree-sra.c
+++ b/gcc/tree-sra.c
@@ -4079,15 +4079,12 @@ get_repl_default_def_ssa_name (struct access *racc, tree reg_type)
 
 
 /* Generate statements to call .DEFERRED_INIT to initialize scalar replacements
-   of accesses within a subtree ACCESS, all its children, siblings and their
-   children are to be processed.  TOP_OFFSET is the offset  of the processed
-   subtree which has to be subtracted from offsets of individual accesses to
-   get corresponding offsets for AGG.  GSI is a statement iterator used to place
-   the new statements.  */
+   of accesses within a subtree ACCESS; all its children, siblings and their
+   children are to be processed.
+   GSI is a statement iterator used to place the new statements.  */
 static void
-generate_subtree_deferred_init (struct access *access, tree agg,
+generate_subtree_deferred_init (struct access *access,
 				enum auto_init_type init_type,
-				HOST_WIDE_INT top_offset,
 				gimple_stmt_iterator *gsi,
 				location_t loc)
 {
@@ -4109,17 +4106,19 @@ generate_subtree_deferred_init (struct access *access, tree agg,
 	}
       else if (access->grp_to_be_debug_replaced)
 	{
-	  /* FIXME, this part might have some issue.  */
-	  tree drhs = build_debug_ref_for_model (loc, agg,
-						 access->offset - top_offset,
-						 access);
-	  gdebug *ds = gimple_build_debug_bind (get_access_replacement (access),
-						drhs, gsi_stmt (*gsi));
+	  tree drepl = get_access_replacement (access);
+	  tree init_type_node
+	    = build_int_cst (integer_type_node, (int) init_type);
+	  tree call = build_call_expr_internal_loc
+		     (UNKNOWN_LOCATION, IFN_DEFERRED_INIT,
+		      TREE_TYPE (drepl), 2, drepl, init_type_node);
+	  gdebug *ds = gimple_build_debug_bind (drepl, call,
+						gsi_stmt (*gsi));
 	  gsi_insert_before (gsi, ds, GSI_SAME_STMT);
 	}
       if (access->first_child)
-	generate_subtree_deferred_init (access->first_child, agg, init_type,
-					top_offset, gsi, loc);
+	generate_subtree_deferred_init (access->first_child, init_type,
+					gsi, loc);
 
       access = access ->next_sibling;
     }
@@ -4132,40 +4131,55 @@ generate_subtree_deferred_init (struct access *access, tree agg,
    there is one, also replace the RHS call to a call to .DEFERRED_INIT of
    the corresponding scalar relacement variable.  Examine the subtree and
    do the scalar replacements in the subtree too.  STMT is the call, GSI is
-   the statment iterator to place newly created statements.  */
+   the statment iterator to place newly created statement.  */
 
 static enum assignment_mod_result
 sra_modify_deferred_init (gimple *stmt, gimple_stmt_iterator *gsi)
 {
   tree lhs = gimple_call_lhs (stmt);
+  tree arg0 = gimple_call_arg (stmt, 0);
   enum auto_init_type init_type
     = (enum auto_init_type) TREE_INT_CST_LOW (gimple_call_arg (stmt, 1));
-  struct access *access = get_access_for_expr (lhs);
-  if (!access)
+  struct access *lhs_access = get_access_for_expr (lhs);
+  struct access *arg0_access = get_access_for_expr (arg0);
+  if (!lhs_access && !arg0_access)
     return SRA_AM_NONE;
+  gcc_assert (lhs_access && arg0_access);
+
   location_t loc = gimple_location (stmt);
 
-  if (access->grp_to_be_replaced)
+  if (lhs_access->grp_to_be_replaced)
     {
-      tree repl = get_access_replacement (access);
-      gimple_call_set_lhs (stmt, repl);
-      gimple_call_set_arg (stmt, 0, repl);
+      tree lhs_repl = get_access_replacement (lhs_access);
+      tree arg0_repl = get_access_replacement (arg0_access);
+      if (TREE_CODE (lhs_repl) == SSA_NAME)
+	{
+	  gcc_assert (TREE_CODE (arg0_repl) == SSA_NAME);
+	  gcc_assert (SSA_NAME_VAR (lhs_repl) == SSA_NAME_VAR (arg0_repl));
+	}
+      else
+	gcc_assert (lhs_repl == arg0_repl);
+      gimple_call_set_lhs (stmt, lhs_repl);
+      gimple_call_set_arg (stmt, 0, arg0_repl);
       sra_stats.deferred_init++;
     }
-  else if (access->grp_to_be_debug_replaced)
+  else if (lhs_access->grp_to_be_debug_replaced)
     {
-      /* FIXME, this part might have some issues.  */
-      tree drepl = get_access_replacement (access);
-      gdebug *ds = gimple_build_debug_bind (drepl, NULL_TREE,
+      tree lhs_drepl = get_access_replacement (lhs_access);
+      tree init_type_node
+	   = build_int_cst (integer_type_node, (int) init_type);
+      tree call = build_call_expr_internal_loc
+		  (UNKNOWN_LOCATION, IFN_DEFERRED_INIT,
+		  TREE_TYPE (lhs_drepl), 2, lhs_drepl, init_type_node);
+      gdebug *ds = gimple_build_debug_bind (lhs_drepl, call,
 					    gsi_stmt (*gsi));
       gsi_insert_before (gsi, ds, GSI_SAME_STMT);
     }
 
-  if (access->first_child)
-    generate_subtree_deferred_init (access->first_child, lhs,
-				    init_type, access->offset,
-				    gsi, loc);
-  if (access->grp_covered)
+  if (lhs_access->first_child)
+    generate_subtree_deferred_init (lhs_access->first_child,
+				    init_type, gsi, loc);
+  if (lhs_access->grp_covered)
     {
       unlink_stmt_vdef (stmt);
       gsi_remove (gsi, true);
diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c
index e4ee3ff93f09..547df1c7b41d 100644
--- a/gcc/tree-ssa-structalias.c
+++ b/gcc/tree-ssa-structalias.c
@@ -4851,29 +4851,6 @@ find_func_aliases_for_builtin_call (struct function *fn, gcall *t)
   return false;
 }
 
-static void
-find_func_aliases_for_deferred_init (gcall *t)
-{
-  tree lhsop = gimple_call_lhs (t);
-  enum auto_init_type init_type
-    = (enum auto_init_type) TREE_INT_CST_LOW (gimple_call_arg (t, 1));
-  auto_vec<ce_s, 2> lhsc;
-  auto_vec<ce_s, 4> rhsc;
-  struct constraint_expr temp;
-
-  get_constraint_for (lhsop, &lhsc);
-  if (init_type == AUTO_INIT_ZERO && flag_delete_null_pointer_checks)
-    temp.var = nothing_id;
-  else
-    temp.var = nonlocal_id;
-  temp.type = ADDRESSOF;
-  temp.offset = 0;
-  rhsc.safe_push (temp);
-
-  process_all_all_constraints (lhsc, rhsc);
-  return;
-}
-
 /* Create constraints for the call T.  */
 
 static void
@@ -4888,10 +4865,7 @@ find_func_aliases_for_call (struct function *fn, gcall *t)
     return;
 
   if (gimple_call_internal_p (t, IFN_DEFERRED_INIT))
-    {
-      find_func_aliases_for_deferred_init (t);
-      return;
-    }
+    return;
 
   fi = get_fi_for_callee (t);
   if (!in_ipa_mode
diff --git a/gcc/tree-ssa-uninit.c b/gcc/tree-ssa-uninit.c
index e8ca1469a083..c86c59cbabd4 100644
--- a/gcc/tree-ssa-uninit.c
+++ b/gcc/tree-ssa-uninit.c
@@ -136,8 +136,30 @@ warn_uninit (enum opt_code wc, tree t, tree expr, tree var,
       && gimple_assign_rhs_code (context) == COMPLEX_EXPR)
     return;
 
-  /* Ignore REALPART_EXPR or IMAGPART_EXPR if its operand is
-     a call to .DEFERRED_INIT.  */
+  /* Ignore REALPART_EXPR or IMAGPART_EXPR if its operand is a call to
+     .DEFERRED_INIT.  This is for handling the following case correctly:
+
+  1 typedef _Complex float C;
+  2 C foo(int cond)
+  3 {
+  4   C f;
+  5   __imag__ f = 0;
+  6   if (cond)
+  7     {
+  8       __real__ f = 1;
+  9       return f;
+ 10     }
+ 11   return f;
+ 12 }
+
+    with -ftrivial-auto-var-init, compiler will insert the following
+    artificial initialization at line 4:
+  f = .DEFERRED_INIT (f, 2);
+  _1 = REALPART_EXPR <f>;
+
+    without the following special handling, _1 = REALPART_EXPR <f> will
+    be treated as the uninitialized use point, which is incorrect. (the
+    real uninitialized use point is at line 11).  */
   if (is_gimple_assign (context)
       && (gimple_assign_rhs_code (context) == REALPART_EXPR
 	  || gimple_assign_rhs_code (context) == IMAGPART_EXPR))
@@ -224,12 +246,12 @@ check_defs (ao_ref *ref, tree vdef, void *data_)
   check_defs_data *data = (check_defs_data *)data_;
   gimple *def_stmt = SSA_NAME_DEF_STMT (vdef);
 
-  /* Ignore the vdef iff the definition statement is a call
+  /* Ignore the vdef if the definition statement is a call
      to .DEFERRED_INIT function.  */
   if (gimple_call_internal_p (def_stmt, IFN_DEFERRED_INIT))
     return false;
 
-  /* Ignore the vdef iff the definition statement is a call
+  /* Ignore the vdef if the definition statement is a call
      to builtin_memset function that is added for uninitialized
      auto variable initialization.  */
   if (gimple_call_builtin_p (def_stmt, BUILT_IN_MEMSET)
@@ -638,6 +660,9 @@ warn_uninitialized_vars (bool wmaybe_uninit)
 	  ssa_op_iter op_iter;
 	  tree use;
 
+	  /* The call is an artificial use, will not provide meaningful
+	     error message.  If the result of the call is used somewhere
+	     else, we warn there instead.  */
 	  if (gimple_call_internal_p (stmt, IFN_DEFERRED_INIT))
 	    continue;
 
diff --git a/gcc/tree-ssa.c b/gcc/tree-ssa.c
index 2058849a3a4c..0c285f7b4f0f 100644
--- a/gcc/tree-ssa.c
+++ b/gcc/tree-ssa.c
@@ -1325,11 +1325,35 @@ ssa_undefined_value_p (tree t, bool partial)
   if (gimple_nop_p (def_stmt))
     return true;
 
-  /* The value is undefined iff the definition statement is a call
+  /* The value is undefined if the definition statement is a call
      to .DEFERRED_INIT function.  */
   if (gimple_call_internal_p (def_stmt, IFN_DEFERRED_INIT))
     return true;
 
+  /* The value is partially undefined if the definition statement is
+     a REALPART_EXPR or IMAGPART_EXPR and its operand is defined by
+     the call to .DEFERRED_INIT function.  This is for handling the
+     following case:
+
+  1 typedef _Complex float C;
+  2 C foo(int cond)
+  3 {
+  4   C f;
+  5   __imag__ f = 0;
+  6   if (cond)
+  7     {
+  8       __real__ f = 1;
+  9       return f;
+ 10     }
+ 11   return f;
+ 12 }
+
+    with -ftrivial-auto-var-init, compiler will insert the following
+    artificial initialization:
+  f = .DEFERRED_INIT (f, 2);
+  _1 = REALPART_EXPR <f>;
+
+    we should treat the definition _1 = REALPART_EXPR <f> as undefined.  */
   if (partial && is_gimple_assign (def_stmt)
       && (gimple_assign_rhs_code (def_stmt) == REALPART_EXPR
 	  || gimple_assign_rhs_code (def_stmt) == IMAGPART_EXPR))
@@ -1341,7 +1365,6 @@ ssa_undefined_value_p (tree t, bool partial)
 	return true;
     }
 
-
   /* Check if the complex was not only partially defined.  */
   if (partial && is_gimple_assign (def_stmt)
       && gimple_assign_rhs_code (def_stmt) == COMPLEX_EXPR)
diff --git a/gcc/tree.c b/gcc/tree.c
index a199fa773fb7..c320781befec 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -2533,7 +2533,7 @@ build_zero_cst (tree type)
    auto variables.  */
 
 tree
-build_pattern_cst (tree type)
+build_pattern_cst_for_auto_init (tree type)
 {
   /* 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
@@ -2548,13 +2548,20 @@ build_pattern_cst (tree type)
 
   switch (TREE_CODE (type))
     {
-    case INTEGER_TYPE:
-    case ENUMERAL_TYPE:
     case BOOLEAN_TYPE:
-      /* This will initialize a boolean type variable to 0 instead of 1.
- 	 We think that initializint a boolean variable to 0 other than 1
+      /* We think that initializing the boolean variable to 0 other than 1
 	 is better even for pattern initialization.  */
-      return build_int_cstu (type, largevalue);
+      return build_zero_cst (type);
+    case INTEGER_TYPE:
+    case ENUMERAL_TYPE:
+      {
+	unsigned char ptr[16]
+	  = {0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
+	     0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA};
+	int total_bytes = GET_MODE_SIZE (SCALAR_INT_TYPE_MODE (type));
+	wide_int result = wi::from_buffer (ptr, total_bytes);
+	return wide_int_to_tree (type, result);
+      }
     case POINTER_TYPE:
     case OFFSET_TYPE:
     case REFERENCE_TYPE:
@@ -2564,25 +2571,28 @@ build_pattern_cst (tree type)
 
 	if (POINTER_SIZE == 64)
 	  intvalue = largevalue;
-	else if (POINTER_SIZE == 32)
-	  intvalue = smallvalue;
 	else
-	  gcc_assert (0);
+	  intvalue = smallvalue;
 	return build_int_cstu (type, intvalue);
       }
     case REAL_TYPE:
       {
 	REAL_VALUE_TYPE rnan;
+	machine_mode mode = TYPE_MODE (type);
 
-	/* create an quiet NAN for REAL TYPE.  */
-	if (real_nan (&rnan, "", 1, TYPE_MODE (type)))
-	  return build_real (type, rnan);
-	return NULL_TREE;
+	/* create an quiet NAN for REAL TYPE.
+	   if failed, fallback to MAX_FLOAT instead.  */
+	if (!real_nan (&rnan, "", 1, mode))
+	  {
+	    char buf[128];
+ 
+	    get_max_float (REAL_MODE_FORMAT (mode), buf, sizeof (buf), false);
+	    real_from_string (&rnan, buf);
+	  }
+	return build_real (type, rnan);
       }
-
     case FIXED_POINT_TYPE:
       {
-	/* FIXME.  What should we put into a fixed point?  */
 	FIXED_VALUE_TYPE fixed;
 	fixed_from_string (&fixed, "0xFFFFFFFFFFFFFFFF",
 			   SCALAR_TYPE_MODE (type));
@@ -2590,12 +2600,12 @@ build_pattern_cst (tree type)
       }
     case VECTOR_TYPE:
       {
-	tree scalar = build_pattern_cst (TREE_TYPE (type));
+	tree scalar = build_pattern_cst_for_auto_init (TREE_TYPE (type));
 	return build_vector_from_val (type, scalar);
       }
     case COMPLEX_TYPE:
       {
-	tree element = build_pattern_cst (TREE_TYPE (type));
+	tree element = build_pattern_cst_for_auto_init (TREE_TYPE (type));
 	return build_complex (type, element, element);
       }
     case RECORD_TYPE:
@@ -2607,8 +2617,8 @@ build_pattern_cst (tree type)
 	  {
 	    if (TREE_CODE (field) != FIELD_DECL)
 	      continue;
-	    /* if the field is a variable length array, it should be the last
-	       field of the record, and no need to initialize.  */
+	    /* If the field is a flexible array member, it should be the last
+	       field of the record, and no need to initialize it.  */
 	    if (TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE
 		&& TYPE_SIZE (TREE_TYPE (field)) == NULL_TREE
 		&& ((TYPE_DOMAIN (TREE_TYPE (field)) != NULL_TREE
@@ -2616,7 +2626,7 @@ build_pattern_cst (tree type)
 				       == NULL_TREE)
 		   || TYPE_DOMAIN (TREE_TYPE (field)) == NULL_TREE))
 	      continue;
-	    field_value = build_pattern_cst (TREE_TYPE (field));
+	    field_value = build_pattern_cst_for_auto_init (TREE_TYPE (field));
 	    CONSTRUCTOR_APPEND_ELT (v, field, field_value);
 	  }
 	return build_constructor (type, v);
@@ -2628,25 +2638,30 @@ build_pattern_cst (tree type)
 	unsigned max_size = 0;
 	tree field_value;
 	vec<constructor_elt, va_gc> *v = NULL;
-	/* find the field with the largest size.  */
+	/* Find the field with the largest size.  */
 	for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
 	  {
 	    if (TREE_CODE (field) != FIELD_DECL)
 	      continue;
-	    if (tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (field))) >= max_size)
+	    if (tree_fits_uhwi_p (TYPE_SIZE_UNIT (TREE_TYPE (field))))
+	      if (tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (field))) >= max_size)
 	      {
 		max_size = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (field)));
 		max_field = field;
 	      }
 	  }
-	  field_value = build_pattern_cst (TREE_TYPE (max_field));
-	  CONSTRUCTOR_APPEND_ELT (v, max_field, field_value);
+	if (max_field)
+	  {
+	    field_value
+	      = build_pattern_cst_for_auto_init (TREE_TYPE (max_field));
+	    CONSTRUCTOR_APPEND_ELT (v, max_field, field_value);
+	  }
 	return build_constructor (type, v);
       }
     case ARRAY_TYPE:
       {
 	vec<constructor_elt, va_gc> *elts = NULL;
-	tree element = build_pattern_cst (TREE_TYPE (type));
+	tree element = build_pattern_cst_for_auto_init (TREE_TYPE (type));
 	tree nelts = array_type_nelts (type);
 	if (nelts && tree_fits_uhwi_p (nelts))
 	  {
@@ -2655,14 +2670,16 @@ build_pattern_cst (tree type)
 	      CONSTRUCTOR_APPEND_ELT (elts, NULL_TREE, element);
 	    return build_constructor (type, elts);
 	  }
-	/* variable length array should not be here.  */
-	gcc_assert (0);
+	/* Variable length array should not be here.  */
+	gcc_unreachable ();
       }
     default:
       if (!AGGREGATE_TYPE_P (type))
-	return fold_convert (type, build_pattern_cst (unsigned_type_node));
+	return
+	  fold_convert (type,
+			build_pattern_cst_for_auto_init (unsigned_type_node));
       else
-	gcc_assert (0);
+	gcc_unreachable ();
 
     }
 }
diff --git a/gcc/tree.h b/gcc/tree.h
index 089494e020a8..7b7d5bf76bd1 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -2874,10 +2874,6 @@ extern void decl_value_expr_insert (tree, tree);
 #define DECL_HARD_REGISTER(NODE)  \
   (VAR_DECL_CHECK (NODE)->decl_with_vis.hard_register)
 
-/* In a VAR_DECL, nonzero if the decl is intentionly not initialized.  */
-#define DECL_UNINITIALIZED(NODE)  \
-  (VAR_DECL_CHECK (NODE)->decl_with_vis.uninitialized)
-
   /* Used to indicate that this DECL has weak linkage.  */
 #define DECL_WEAK(NODE) (DECL_WITH_VIS_CHECK (NODE)->decl_with_vis.weak_flag)
 
@@ -4464,7 +4460,7 @@ extern tree build_one_cst (tree);
 extern tree build_minus_one_cst (tree);
 extern tree build_all_ones_cst (tree);
 extern tree build_zero_cst (tree);
-extern tree build_pattern_cst (tree);
+extern tree build_pattern_cst_for_auto_init (tree);
 extern tree build_string (unsigned, const char * = NULL);
 extern tree build_poly_int_cst (tree, const poly_wide_int_ref &);
 extern tree build_tree_list (tree, tree CXX_MEM_STAT_INFO);
-- 
2.27.0


[-- Attachment #3: Type: text/plain, Size: 51 bytes --]



******The complete 3rd version of the patch are:

[-- Attachment #4: 3rd-version-ftrivial-auto-var-init.patch --]
[-- Type: application/octet-stream, Size: 161034 bytes --]

From c0ed5c4f536da38987602bd2c9a1150196f7937c Mon Sep 17 00:00:00 2001
From: qing zhao <qinzhao@gcc.gnu.org>
Date: Sat, 12 Dec 2020 00:02:28 +0100
Subject: [PATCH] 3rd version
add -ftrivial-auto-var-init and variable attribute 
 uninitialized to gcc.

---
 gcc/c-family/c-attribs.c                      |  19 ++
 gcc/common.opt                                |  29 +++
 gcc/doc/extend.texi                           |  16 ++
 gcc/doc/invoke.texi                           |  38 ++-
 gcc/expr.c                                    |  17 +-
 gcc/flag-types.h                              |  12 +
 gcc/gimple.h                                  |  24 ++
 gcc/gimplify.c                                | 195 ++++++++++++++
 gcc/internal-fn.c                             |  24 ++
 gcc/internal-fn.def                           |   5 +
 gcc/testsuite/c-c++-common/auto-init-1.c      |  39 +++
 gcc/testsuite/c-c++-common/auto-init-10.c     |  17 ++
 gcc/testsuite/c-c++-common/auto-init-11.c     |  14 ++
 gcc/testsuite/c-c++-common/auto-init-12.c     |  14 ++
 gcc/testsuite/c-c++-common/auto-init-13.c     |  23 ++
 gcc/testsuite/c-c++-common/auto-init-14.c     |  23 ++
 gcc/testsuite/c-c++-common/auto-init-15.c     |  13 +
 gcc/testsuite/c-c++-common/auto-init-16.c     |  13 +
 gcc/testsuite/c-c++-common/auto-init-2.c      |  39 +++
 gcc/testsuite/c-c++-common/auto-init-3.c      |  19 ++
 gcc/testsuite/c-c++-common/auto-init-4.c      |  19 ++
 gcc/testsuite/c-c++-common/auto-init-5.c      |  21 ++
 gcc/testsuite/c-c++-common/auto-init-6.c      |  21 ++
 gcc/testsuite/c-c++-common/auto-init-7.c      |  35 +++
 gcc/testsuite/c-c++-common/auto-init-8.c      |  35 +++
 gcc/testsuite/c-c++-common/auto-init-9.c      |  17 ++
 gcc/testsuite/c-c++-common/auto-init-esra.c   |  35 +++
 .../g++.dg/auto-init-uninit-pred-1_a.C        |  63 +++++
 .../g++.dg/auto-init-uninit-pred-1_b.C        |  63 +++++
 .../g++.dg/auto-init-uninit-pred-2_a.C        |  62 +++++
 .../g++.dg/auto-init-uninit-pred-2_b.C        |  62 +++++
 .../g++.dg/auto-init-uninit-pred-3_a.C        |  77 ++++++
 .../g++.dg/auto-init-uninit-pred-3_b.C        |  87 +++++++
 .../g++.dg/auto-init-uninit-pred-4.C          |  16 ++
 .../g++.dg/auto-init-uninit-pred-loop-1_a.cc  |  21 ++
 .../g++.dg/auto-init-uninit-pred-loop-1_b.cc  |  21 ++
 .../g++.dg/auto-init-uninit-pred-loop-1_c.cc  |  23 ++
 .../g++.dg/auto-init-uninit-pred-loop_1.cc    |  21 ++
 gcc/testsuite/gcc.dg/auto-init-uninit-1.c     |  30 +++
 gcc/testsuite/gcc.dg/auto-init-uninit-11.c    |  42 ++++
 gcc/testsuite/gcc.dg/auto-init-uninit-12.c    |  12 +
 gcc/testsuite/gcc.dg/auto-init-uninit-13.c    |  10 +
 gcc/testsuite/gcc.dg/auto-init-uninit-14.c    |  20 ++
 gcc/testsuite/gcc.dg/auto-init-uninit-15.c    |  26 ++
 gcc/testsuite/gcc.dg/auto-init-uninit-16.c    |  23 ++
 gcc/testsuite/gcc.dg/auto-init-uninit-17.c    |  15 ++
 gcc/testsuite/gcc.dg/auto-init-uninit-18.c    |  24 ++
 gcc/testsuite/gcc.dg/auto-init-uninit-19.c    |  26 ++
 gcc/testsuite/gcc.dg/auto-init-uninit-2.c     |  52 ++++
 gcc/testsuite/gcc.dg/auto-init-uninit-20.c    |  18 ++
 gcc/testsuite/gcc.dg/auto-init-uninit-21.c    |  33 +++
 gcc/testsuite/gcc.dg/auto-init-uninit-22.c    |  69 +++++
 gcc/testsuite/gcc.dg/auto-init-uninit-23.c    |  27 ++
 gcc/testsuite/gcc.dg/auto-init-uninit-24.c    |  10 +
 gcc/testsuite/gcc.dg/auto-init-uninit-25.c    |  23 ++
 gcc/testsuite/gcc.dg/auto-init-uninit-26.c    |  23 ++
 gcc/testsuite/gcc.dg/auto-init-uninit-3.c     |  33 +++
 gcc/testsuite/gcc.dg/auto-init-uninit-34.c    |  58 +++++
 gcc/testsuite/gcc.dg/auto-init-uninit-36.c    | 238 ++++++++++++++++++
 gcc/testsuite/gcc.dg/auto-init-uninit-37.c    | 154 ++++++++++++
 gcc/testsuite/gcc.dg/auto-init-uninit-4.c     |  52 ++++
 gcc/testsuite/gcc.dg/auto-init-uninit-5.c     |  39 +++
 gcc/testsuite/gcc.dg/auto-init-uninit-6.c     |  47 ++++
 gcc/testsuite/gcc.dg/auto-init-uninit-8.c     |  32 +++
 gcc/testsuite/gcc.dg/auto-init-uninit-9.c     |  42 ++++
 gcc/testsuite/gcc.dg/auto-init-uninit-A.c     | 117 +++++++++
 gcc/testsuite/gcc.dg/auto-init-uninit-B.c     |  15 ++
 gcc/testsuite/gcc.dg/auto-init-uninit-C.c     |  21 ++
 gcc/testsuite/gcc.dg/auto-init-uninit-H.c     |  33 +++
 gcc/testsuite/gcc.dg/auto-init-uninit-I.c     |   8 +
 .../gcc.target/aarch64/auto-init-1.c          |  32 +++
 .../gcc.target/aarch64/auto-init-10.c         |  18 ++
 .../gcc.target/aarch64/auto-init-11.c         |  27 ++
 .../gcc.target/aarch64/auto-init-12.c         |  27 ++
 .../gcc.target/aarch64/auto-init-13.c         |  22 ++
 .../gcc.target/aarch64/auto-init-14.c         |  20 ++
 .../gcc.target/aarch64/auto-init-15.c         |  20 ++
 .../gcc.target/aarch64/auto-init-16.c         |  22 ++
 .../gcc.target/aarch64/auto-init-17.c         |  21 ++
 .../gcc.target/aarch64/auto-init-18.c         |  21 ++
 .../gcc.target/aarch64/auto-init-19.c         |  27 ++
 .../gcc.target/aarch64/auto-init-2.c          |  37 +++
 .../gcc.target/aarch64/auto-init-20.c         |  27 ++
 .../gcc.target/aarch64/auto-init-3.c          |  19 ++
 .../gcc.target/aarch64/auto-init-4.c          |  19 ++
 .../gcc.target/aarch64/auto-init-5.c          |  19 ++
 .../gcc.target/aarch64/auto-init-6.c          |  21 ++
 .../gcc.target/aarch64/auto-init-7.c          |  32 +++
 .../gcc.target/aarch64/auto-init-8.c          |  33 +++
 .../gcc.target/aarch64/auto-init-9.c          |  19 ++
 gcc/testsuite/gcc.target/i386/auto-init-1.c   |  32 +++
 gcc/testsuite/gcc.target/i386/auto-init-10.c  |  19 ++
 gcc/testsuite/gcc.target/i386/auto-init-11.c  |  30 +++
 gcc/testsuite/gcc.target/i386/auto-init-12.c  |  30 +++
 gcc/testsuite/gcc.target/i386/auto-init-13.c  |  22 ++
 gcc/testsuite/gcc.target/i386/auto-init-14.c  |  22 ++
 gcc/testsuite/gcc.target/i386/auto-init-15.c  |  22 ++
 gcc/testsuite/gcc.target/i386/auto-init-16.c  |  22 ++
 gcc/testsuite/gcc.target/i386/auto-init-17.c  |  23 ++
 gcc/testsuite/gcc.target/i386/auto-init-18.c  |  21 ++
 gcc/testsuite/gcc.target/i386/auto-init-19.c  |  26 ++
 gcc/testsuite/gcc.target/i386/auto-init-2.c   |  37 +++
 gcc/testsuite/gcc.target/i386/auto-init-20.c  |  26 ++
 gcc/testsuite/gcc.target/i386/auto-init-3.c   |  20 ++
 gcc/testsuite/gcc.target/i386/auto-init-4.c   |  23 ++
 gcc/testsuite/gcc.target/i386/auto-init-5.c   |  19 ++
 gcc/testsuite/gcc.target/i386/auto-init-6.c   |  22 ++
 gcc/testsuite/gcc.target/i386/auto-init-7.c   |  32 +++
 gcc/testsuite/gcc.target/i386/auto-init-8.c   |  33 +++
 gcc/testsuite/gcc.target/i386/auto-init-9.c   |  19 ++
 gcc/tree-cfg.c                                |  58 ++++-
 gcc/tree-core.h                               |   2 +-
 gcc/tree-sra.c                                | 146 ++++++++++-
 gcc/tree-ssa-structalias.c                    |   3 +
 gcc/tree-ssa-uninit.c                         |  55 ++++
 gcc/tree-ssa.c                                |  40 +++
 gcc/tree.c                                    | 221 ++++++++++++++++
 gcc/tree.h                                    |   2 +
 118 files changed, 4143 insertions(+), 31 deletions(-)
 create mode 100644 gcc/testsuite/c-c++-common/auto-init-1.c
 create mode 100644 gcc/testsuite/c-c++-common/auto-init-10.c
 create mode 100644 gcc/testsuite/c-c++-common/auto-init-11.c
 create mode 100644 gcc/testsuite/c-c++-common/auto-init-12.c
 create mode 100644 gcc/testsuite/c-c++-common/auto-init-13.c
 create mode 100644 gcc/testsuite/c-c++-common/auto-init-14.c
 create mode 100644 gcc/testsuite/c-c++-common/auto-init-15.c
 create mode 100644 gcc/testsuite/c-c++-common/auto-init-16.c
 create mode 100644 gcc/testsuite/c-c++-common/auto-init-2.c
 create mode 100644 gcc/testsuite/c-c++-common/auto-init-3.c
 create mode 100644 gcc/testsuite/c-c++-common/auto-init-4.c
 create mode 100644 gcc/testsuite/c-c++-common/auto-init-5.c
 create mode 100644 gcc/testsuite/c-c++-common/auto-init-6.c
 create mode 100644 gcc/testsuite/c-c++-common/auto-init-7.c
 create mode 100644 gcc/testsuite/c-c++-common/auto-init-8.c
 create mode 100644 gcc/testsuite/c-c++-common/auto-init-9.c
 create mode 100644 gcc/testsuite/c-c++-common/auto-init-esra.c
 create mode 100644 gcc/testsuite/g++.dg/auto-init-uninit-pred-1_a.C
 create mode 100644 gcc/testsuite/g++.dg/auto-init-uninit-pred-1_b.C
 create mode 100644 gcc/testsuite/g++.dg/auto-init-uninit-pred-2_a.C
 create mode 100644 gcc/testsuite/g++.dg/auto-init-uninit-pred-2_b.C
 create mode 100644 gcc/testsuite/g++.dg/auto-init-uninit-pred-3_a.C
 create mode 100644 gcc/testsuite/g++.dg/auto-init-uninit-pred-3_b.C
 create mode 100644 gcc/testsuite/g++.dg/auto-init-uninit-pred-4.C
 create mode 100644 gcc/testsuite/g++.dg/auto-init-uninit-pred-loop-1_a.cc
 create mode 100644 gcc/testsuite/g++.dg/auto-init-uninit-pred-loop-1_b.cc
 create mode 100644 gcc/testsuite/g++.dg/auto-init-uninit-pred-loop-1_c.cc
 create mode 100644 gcc/testsuite/g++.dg/auto-init-uninit-pred-loop_1.cc
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-1.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-11.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-12.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-13.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-14.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-15.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-16.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-17.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-18.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-19.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-2.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-20.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-21.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-22.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-23.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-24.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-25.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-26.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-3.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-34.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-36.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-37.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-4.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-5.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-6.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-8.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-9.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-A.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-B.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-C.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-H.c
 create mode 100644 gcc/testsuite/gcc.dg/auto-init-uninit-I.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/auto-init-1.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/auto-init-10.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/auto-init-11.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/auto-init-12.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/auto-init-13.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/auto-init-14.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/auto-init-15.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/auto-init-16.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/auto-init-17.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/auto-init-18.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/auto-init-19.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/auto-init-2.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/auto-init-20.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/auto-init-3.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/auto-init-4.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/auto-init-5.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/auto-init-6.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/auto-init-7.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/auto-init-8.c
 create mode 100644 gcc/testsuite/gcc.target/aarch64/auto-init-9.c
 create mode 100644 gcc/testsuite/gcc.target/i386/auto-init-1.c
 create mode 100644 gcc/testsuite/gcc.target/i386/auto-init-10.c
 create mode 100644 gcc/testsuite/gcc.target/i386/auto-init-11.c
 create mode 100644 gcc/testsuite/gcc.target/i386/auto-init-12.c
 create mode 100644 gcc/testsuite/gcc.target/i386/auto-init-13.c
 create mode 100644 gcc/testsuite/gcc.target/i386/auto-init-14.c
 create mode 100644 gcc/testsuite/gcc.target/i386/auto-init-15.c
 create mode 100644 gcc/testsuite/gcc.target/i386/auto-init-16.c
 create mode 100644 gcc/testsuite/gcc.target/i386/auto-init-17.c
 create mode 100644 gcc/testsuite/gcc.target/i386/auto-init-18.c
 create mode 100644 gcc/testsuite/gcc.target/i386/auto-init-19.c
 create mode 100644 gcc/testsuite/gcc.target/i386/auto-init-2.c
 create mode 100644 gcc/testsuite/gcc.target/i386/auto-init-20.c
 create mode 100644 gcc/testsuite/gcc.target/i386/auto-init-3.c
 create mode 100644 gcc/testsuite/gcc.target/i386/auto-init-4.c
 create mode 100644 gcc/testsuite/gcc.target/i386/auto-init-5.c
 create mode 100644 gcc/testsuite/gcc.target/i386/auto-init-6.c
 create mode 100644 gcc/testsuite/gcc.target/i386/auto-init-7.c
 create mode 100644 gcc/testsuite/gcc.target/i386/auto-init-8.c
 create mode 100644 gcc/testsuite/gcc.target/i386/auto-init-9.c

diff --git a/gcc/c-family/c-attribs.c b/gcc/c-family/c-attribs.c
index f7dad7a91d70..de53c3a2da88 100644
--- a/gcc/c-family/c-attribs.c
+++ b/gcc/c-family/c-attribs.c
@@ -81,6 +81,7 @@ static tree handle_artificial_attribute (tree *, tree, tree, int, bool *);
 static tree handle_flatten_attribute (tree *, tree, tree, int, bool *);
 static tree handle_error_attribute (tree *, tree, tree, int, bool *);
 static tree handle_used_attribute (tree *, tree, tree, int, bool *);
+static tree handle_uninitialized_attribute (tree *, tree, tree, int, bool *);
 static tree handle_externally_visible_attribute (tree *, tree, tree, int,
 						 bool *);
 static tree handle_no_reorder_attribute (tree *, tree, tree, int,
@@ -324,6 +325,8 @@ const struct attribute_spec c_common_attribute_table[] =
 			      handle_used_attribute, NULL },
   { "unused",                 0, 0, false, false, false, false,
 			      handle_unused_attribute, NULL },
+  { "uninitialized",	      0, 0, true, false, false, false,
+			      handle_uninitialized_attribute, NULL },
   { "externally_visible",     0, 0, true,  false, false, false,
 			      handle_externally_visible_attribute, NULL },
   { "no_reorder",	      0, 0, true, false, false, false,
@@ -1523,6 +1526,22 @@ handle_unused_attribute (tree *node, tree name, tree ARG_UNUSED (args),
   return NULL_TREE;
 }
 
+/* Handle an "uninitialized" attribute; arguments as in
+   struct attribute_spec.handler.  */
+
+static tree
+handle_uninitialized_attribute (tree *node, tree name, tree ARG_UNUSED (args),
+				int ARG_UNUSED (flags), bool *no_add_attrs)
+{
+  if (!VAR_P (*node))
+    {
+      warning (OPT_Wattributes, "%qE attribute ignored", name);
+      *no_add_attrs = true;
+    }
+
+  return NULL_TREE;
+}
+
 /* Handle a "externally_visible" attribute; arguments as in
    struct attribute_spec.handler.  */
 
diff --git a/gcc/common.opt b/gcc/common.opt
index 6645539f5e52..b62c99c4325b 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -3053,6 +3053,35 @@ ftree-scev-cprop
 Common Report Var(flag_tree_scev_cprop) Init(1) Optimization
 Enable copy propagation of scalar-evolution information.
 
+ftrivial-auto-var-init=
+Common Joined RejectNegative Enum(auto_init_type) Var(flag_trivial_auto_var_init) Init(AUTO_INIT_UNINITIALIZED)
+-ftrivial-auto-var-init=[uninitialized|pattern|zero]	Add initializations to automatic variables.
+
+Enum
+Name(auto_init_type) Type(enum auto_init_type) UnknownError(unrecognized automatic variable initialization type %qs)
+
+EnumValue
+Enum(auto_init_type) String(uninitialized) Value(AUTO_INIT_UNINITIALIZED)
+
+EnumValue
+Enum(auto_init_type) String(pattern) Value(AUTO_INIT_PATTERN)
+
+EnumValue
+Enum(auto_init_type) String(zero) Value(AUTO_INIT_ZERO)
+
+fauto-var-init-approach=
+Common Joined RejectNegative Enum(auto_init_approach) Var(flag_auto_init_approach) Init(AUTO_INIT_D))
+-fauto-var-init-approach=[A|D]	Choose the approach to initialize automatic variables.
+
+Enum
+Name(auto_init_approach) Type(enum auto_init_approach) UnknownError(unrecognized automatic variable initialization approach %qs)
+
+EnumValue
+Enum(auto_init_approach) String(A) Value(AUTO_INIT_A)
+
+EnumValue
+Enum(auto_init_approach) String(D) Value(AUTO_INIT_D)
+
 ; -fverbose-asm causes extra commentary information to be produced in
 ; the generated assembly code (to make it more readable).  This option
 ; is generally only of use to those who actually need to read the
diff --git a/gcc/doc/extend.texi b/gcc/doc/extend.texi
index 0c969085d1f2..a876d9e7a353 100644
--- a/gcc/doc/extend.texi
+++ b/gcc/doc/extend.texi
@@ -7436,6 +7436,22 @@ will be placed in new, unique sections.
 
 This additional functionality requires Binutils version 2.36 or later.
 
+@item uninitialized
+@cindex @code{uninitialized} variable attribute
+This attribute, attached to a variable with automatic storage, means that
+the variable should not be automatically initialized by the compiler when
+the option @code{-ftrivial-auto-var-init} presents.
+
+With the option @code{-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 @code{-ftrivial-auto-var-init}
+does not present.
+
 @item vector_size (@var{bytes})
 @cindex @code{vector_size} variable attribute
 This attribute specifies the vector size for the type of the declared
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index f7e8c8b29b0e..e68cbb13d9e8 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -554,9 +554,9 @@ Objective-C and Objective-C++ Dialects}.
 -ftree-parallelize-loops=@var{n}  -ftree-pre  -ftree-partial-pre  -ftree-pta @gol
 -ftree-reassoc  -ftree-scev-cprop  -ftree-sink  -ftree-slsr  -ftree-sra @gol
 -ftree-switch-conversion  -ftree-tail-merge @gol
--ftree-ter  -ftree-vectorize  -ftree-vrp  -funconstrained-commons @gol
--funit-at-a-time  -funroll-all-loops  -funroll-loops @gol
--funsafe-math-optimizations  -funswitch-loops @gol
+-ftree-ter  -ftree-vectorize  -ftree-vrp  -ftrivial-auto-var-init @gol
+-funconstrained-commons -funit-at-a-time  -funroll-all-loops @gol
+-funroll-loops -funsafe-math-optimizations  -funswitch-loops @gol
 -fipa-ra  -fvariable-expansion-in-unroller  -fvect-cost-model  -fvpt @gol
 -fweb  -fwhole-program  -fwpa  -fuse-linker-plugin -fzero-call-used-regs @gol
 --param @var{name}=@var{value}
@@ -11550,6 +11550,38 @@ Perform basic block vectorization on trees. This flag is enabled by default at
 @option{-O3} and by @option{-ftree-vectorize}, @option{-fprofile-use},
 and @option{-fauto-profile}.
 
+@item -ftrivial-auto-var-init=@var{choice}
+@opindex ftrivial-auto-var-init
+Initialize automatic variables with either a pattern or with zeroes to increase
+the security and predictability of a program by preventing uninitialized memory
+disclosure and use.
+GCC still considers an automatic variable that doesn't have an explicit
+initializer as uninitialized, -Wuninitialized will still report warning messages
+on such automatic variables.
+
+The three values of @var{choice} are:
+
+@itemize @bullet
+@item
+@samp{uninitialized} doesn't initialize any automatic variables.
+This is C and C++'s default.
+
+@item
+@samp{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.
+
+@item
+@samp{zero} Initialize automatic variables with zeroes.
+@end itemize
+
+The default is @samp{uninitialized}.
+
+You can control this behavior for a specific variable by using the variable
+attribute @code{uninitialized} (@pxref{Variable Attributes}).
+
 @item -fvect-cost-model=@var{model}
 @opindex fvect-cost-model
 Alter the cost model used for vectorization.  The @var{model} argument
diff --git a/gcc/expr.c b/gcc/expr.c
index 798285eb52ca..9092349d7017 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -6539,14 +6539,19 @@ store_constructor (tree exp, rtx target, int cleared, poly_int64 size,
 	    cleared = 1;
 	  }
 
-        /* If the constructor has fewer fields than the structure or
-	   if we are initializing the structure to mostly zeros, clear
-	   the whole structure first.  Don't do this if TARGET is a
-	   register whose mode size isn't equal to SIZE since
-	   clear_storage can't handle this case.  */
+	/* If the constructor has fewer fields than the structure,
+	   or if we are initializing the structure to mostly zeros,
+	   or if the user requests to initialize automatic variables with
+	   paddings inside the type,
+	   we should clear the whole structure first.
+	   Don't do this if TARGET is a register whose mode size isn't equal
+	   SIZE since clear_storage can't handle this case.  */
 	else if (known_size_p (size)
 		 && (((int) CONSTRUCTOR_NELTS (exp) != fields_length (type))
-		     || mostly_zeros_p (exp))
+		     || mostly_zeros_p (exp)
+		     || (flag_trivial_auto_var_init > AUTO_INIT_UNINITIALIZED
+			 && !TREE_STATIC (exp)
+			 && type_has_padding (type)))
 		 && (!REG_P (target)
 		     || known_eq (GET_MODE_SIZE (GET_MODE (target)), size)))
 	  {
diff --git a/gcc/flag-types.h b/gcc/flag-types.h
index 9342bd87be30..0bd93256f9ca 100644
--- a/gcc/flag-types.h
+++ b/gcc/flag-types.h
@@ -242,6 +242,18 @@ enum vect_cost_model {
   VECT_COST_MODEL_DEFAULT = 1
 };
 
+/* Automatic variable initialization type.  */
+enum auto_init_type {
+  AUTO_INIT_UNINITIALIZED = 0,
+  AUTO_INIT_PATTERN = 1,
+  AUTO_INIT_ZERO = 2
+};
+
+enum auto_init_approach {
+  AUTO_INIT_A = 0,
+  AUTO_INIT_D = 1
+};
+
 /* Different instrumentation modes.  */
 enum sanitize_code {
   /* AddressSanitizer.  */
diff --git a/gcc/gimple.h b/gcc/gimple.h
index 8a1db3cc7db6..d5597120008e 100644
--- a/gcc/gimple.h
+++ b/gcc/gimple.h
@@ -150,6 +150,7 @@ enum gf_mask {
     GF_CALL_BY_DESCRIPTOR	= 1 << 10,
     GF_CALL_NOCF_CHECK		= 1 << 11,
     GF_CALL_FROM_NEW_OR_DELETE	= 1 << 12,
+    GF_CALL_MEMSET_FOR_UNINIT	= 1 << 13,
     GF_OMP_PARALLEL_COMBINED	= 1 << 0,
     GF_OMP_TASK_TASKLOOP	= 1 << 0,
     GF_OMP_TASK_TASKWAIT	= 1 << 1,
@@ -3488,6 +3489,29 @@ gimple_call_alloca_for_var_p (gimple *s)
   return (gc->subcode & GF_CALL_ALLOCA_FOR_VAR) != 0;
 }
 
+/* If FOR_UNINIT is true, GIMPLE_CALL S is a call to builtin_memset that
+   is known to be emitted for unintialized VLA objects.  */
+
+static inline void
+gimple_call_set_memset_for_uninit (gcall *s, bool for_uninit)
+{
+  if (for_uninit)
+    s->subcode |= GF_CALL_MEMSET_FOR_UNINIT;
+  else
+    s->subcode &= ~GF_CALL_MEMSET_FOR_UNINIT;
+}
+
+/* Return true if S is a call to builtin_memset emitted for uninitialized
+   VLA objects.  */
+
+static inline bool
+gimple_call_memset_for_uninit_p (gimple *s)
+{
+  const gcall *gc = GIMPLE_CHECK2<gcall *> (s);
+  return (gc->subcode & GF_CALL_MEMSET_FOR_UNINIT) != 0;
+}
+
+
 /* If BY_DESCRIPTOR_P is true, GIMPLE_CALL S is an indirect call for which
    pointers to nested function are descriptors instead of trampolines.  */
 
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index 54cb66bd1dd5..b14e79a84fd4 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -1712,6 +1712,122 @@ gimplify_vla_decl (tree decl, gimple_seq *seq_p)
 
   gimplify_and_add (t, seq_p);
 
+  /* Add a call to memset or calls to memcpy to initialize this vla
+     when the user requested.  */
+  if (!DECL_ARTIFICIAL (decl)
+      && VAR_P (decl)
+      && !DECL_EXTERNAL (decl)
+      && !TREE_STATIC (decl)
+      && !lookup_attribute ("uninitialized", DECL_ATTRIBUTES (decl)))
+    switch (flag_trivial_auto_var_init)
+      {
+      case AUTO_INIT_UNINITIALIZED:
+	break;
+      case AUTO_INIT_ZERO:
+	{
+	  /* Generate a call to memset to initialize this vla.  */
+	  gcall *gs;
+	  t = builtin_decl_implicit (BUILT_IN_MEMSET);
+	  gs = gimple_build_call (t, 3, addr, integer_zero_node,
+				  DECL_SIZE_UNIT (decl));
+	  gimple_call_set_memset_for_uninit (gs, true);
+	  gimplify_seq_add_stmt (seq_p, gs);
+	}
+	break;
+      case AUTO_INIT_PATTERN:
+	{
+	  /* Generate the following sequence to initialize this vla:
+	     if (DECL_SIZE_UNIT (decl) > 0) goto label_true;
+					    else goto label_cont;
+	     label_true:
+	      {
+		element_type = TREE_TYPE (TREE_TYPE (decl));
+		size_of_element = DECL_SIZE_UNIT (element_type);
+		init_node = build_pattern_cst_for_auto_init (element_type);
+		cur = addr;
+		offset = DECL_SIZE_UNIT (decl) - size_of_element;
+		end = addr + offset;
+
+		label_loop:
+		  {
+		    memcpy (cur, &init_node, size_of_element);
+		    cur  += size_of_element;
+		    if (cur <= end) goto label_loop;
+				    else goto label_cont;
+		  }
+	      }
+	      label_cont:
+	  */
+
+	  tree size_of_element, element_type;
+	  tree cur, end, offset;
+	  tree init_node, addrof_init_node;
+	  tree t;
+
+	  tree label_true = create_artificial_label (UNKNOWN_LOCATION);
+	  tree label_cont = create_artificial_label (UNKNOWN_LOCATION);
+	  tree label_loop = create_artificial_label (UNKNOWN_LOCATION);
+
+	  element_type = TREE_TYPE (TREE_TYPE (decl));
+	  /* If this is a nested array, we should go down to the element that
+	     is not an array.  */
+	  while (TREE_CODE (element_type) == ARRAY_TYPE)
+	    element_type = TREE_TYPE (element_type);
+
+	  gcond *cond_stmt = gimple_build_cond (GT_EXPR, DECL_SIZE_UNIT (decl),
+						build_zero_cst (sizetype),
+						label_true,
+						label_cont);
+	  gimplify_seq_add_stmt (seq_p, cond_stmt);
+	  gimplify_seq_add_stmt (seq_p, gimple_build_label (label_true));
+
+	  size_of_element = create_tmp_var (sizetype,
+					    ".size_of_element");
+
+	  init_node = create_tmp_var (element_type, ".init_node");
+	  mark_addressable (init_node);
+	  addrof_init_node = build_fold_addr_expr_loc (UNKNOWN_LOCATION,
+						       init_node);
+
+	  gimplify_assign (size_of_element, TYPE_SIZE_UNIT (element_type),
+			   seq_p);
+	  gimplify_assign (init_node,
+			   build_pattern_cst_for_auto_init (element_type),
+			   seq_p);
+
+	  cur = create_tmp_var (ptr_type, ".cur_addr");
+	  end = create_tmp_var (ptr_type, ".end_addr");
+	  offset = create_tmp_var (sizetype, ".offset");
+
+	  gimplify_assign (cur, addr, seq_p);
+	  gimplify_seq_add_stmt (seq_p,
+				 gimple_build_assign (offset, MINUS_EXPR,
+						      DECL_SIZE_UNIT (decl),
+						      size_of_element));
+	  gimplify_seq_add_stmt (seq_p,
+				 gimple_build_assign (end, POINTER_PLUS_EXPR,
+						      addr, offset));
+
+	  gimplify_seq_add_stmt (seq_p, gimple_build_label (label_loop));
+
+	  t = builtin_decl_implicit (BUILT_IN_MEMCPY);
+	  gimplify_seq_add_stmt (seq_p,
+				 gimple_build_call (t, 3, cur,
+						    addrof_init_node,
+						    size_of_element));
+	  gimplify_seq_add_stmt (seq_p,
+				 gimple_build_assign (cur, POINTER_PLUS_EXPR,
+						      cur, size_of_element));
+	  cond_stmt = gimple_build_cond (LE_EXPR, cur, end, label_loop,
+					 label_cont);
+	  gimplify_seq_add_stmt (seq_p, cond_stmt);
+	  gimplify_seq_add_stmt (seq_p, gimple_build_label (label_cont));
+	}
+	break;
+      default:
+	gcc_assert (0);
+      }
+
   /* Record the dynamic allocation associated with DECL if requested.  */
   if (flag_callgraph_info & CALLGRAPH_INFO_DYNAMIC_ALLOC)
     record_dynamic_alloc (decl);
@@ -1734,6 +1850,62 @@ force_labels_r (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
   return NULL_TREE;
 }
 
+
+/* Build a call to internal const function DEFERRED_INIT:
+   1st argument: DECL;
+   2nd argument: INIT_TYPE;
+
+   as DEFERRED_INIT (DECL, INIT_TYPE).  */
+
+static gimple *
+build_deferred_init (tree decl,
+		     enum auto_init_type init_type)
+{
+  tree init_type_node
+    = build_int_cst (integer_type_node, (int) init_type);
+   return gimple_build_call_internal (IFN_DEFERRED_INIT, 2,
+				      decl, init_type_node);
+}
+
+/* Generate initialization to automatic variable DECL based on INIT_TYPE.  */
+static void
+gimple_add_init_for_auto_var (tree decl,
+			      enum auto_init_type init_type,
+			      enum auto_init_approach init_approach,
+			      gimple_seq *seq_p)
+{
+  gcc_assert (VAR_P (decl) && !DECL_EXTERNAL (decl) && !TREE_STATIC (decl));
+  switch (init_type)
+  {
+  case AUTO_INIT_UNINITIALIZED:
+    gcc_assert (0);
+    break;
+  case AUTO_INIT_PATTERN:
+  case AUTO_INIT_ZERO:
+    if (init_approach == AUTO_INIT_A)
+    {
+      tree init = (init_type == AUTO_INIT_PATTERN)
+		   ? build_pattern_cst_for_auto_init (TREE_TYPE (decl)) :
+		   build_zero_cst (TREE_TYPE (decl));
+      init = build2 (INIT_EXPR, void_type_node, decl, init);
+      gimplify_and_add (init, seq_p);
+      ggc_free (init);
+    }
+    else if (init_approach == AUTO_INIT_D)
+    {
+      gimple *call = build_deferred_init (decl, init_type);
+      gimple_call_set_lhs (call, decl);
+      gimplify_seq_add_stmt (seq_p, call);
+    }
+    else
+      gcc_assert (0);
+    break;
+  default:
+    gcc_unreachable ();
+  }
+}
+
+
 /* Gimplify a DECL_EXPR node *STMT_P by making any necessary allocation
    and initialization explicit.  */
 
@@ -1821,6 +1993,18 @@ gimplify_decl_expr (tree *stmt_p, gimple_seq *seq_p)
 	       as they may contain a label address.  */
 	    walk_tree (&init, force_labels_r, NULL, NULL);
 	}
+      /* When there is no explicit initializer, if the user requested,
+	 We should insert an artifical initializer for this automatic
+	 variable for non VLA variables.  VLA variables are handled
+	 in gimplify_vla_decl differently.  */
+      else if (flag_trivial_auto_var_init > AUTO_INIT_UNINITIALIZED
+	       && !lookup_attribute ("uninitialized", DECL_ATTRIBUTES (decl))
+	       && !TREE_STATIC (decl)
+	       && !is_vla)
+	gimple_add_init_for_auto_var (decl,
+				      flag_trivial_auto_var_init,
+				      flag_auto_init_approach,
+				      seq_p);
     }
 
   return GS_ALL_DONE;
@@ -5001,6 +5185,17 @@ gimplify_init_constructor (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
 	  /* If a single access to the target must be ensured and all elements
 	     are zero, then it's optimal to clear whatever their number.  */
 	  cleared = true;
+	else if (flag_trivial_auto_var_init > AUTO_INIT_UNINITIALIZED
+		 && !TREE_STATIC (object)
+		 && type_has_padding (type))
+	  /* If the user requests to initialize automatic variables with
+	     paddings inside the type, we should initialize the paddings too.
+	     C guarantees that brace-init with fewer initializers than members
+	     aggregate will initialize the rest of the aggregate as-if it were
+	     static initialization.  In turn static initialization guarantees
+	     that pad is initialized to zero bits.
+	     So, it's better to clear the whole record under such situation.  */
+	  cleared = true;
 	else
 	  cleared = false;
 
diff --git a/gcc/internal-fn.c b/gcc/internal-fn.c
index 41223ff7d82b..28d23e923b3c 100644
--- a/gcc/internal-fn.c
+++ b/gcc/internal-fn.c
@@ -2971,6 +2971,30 @@ expand_UNIQUE (internal_fn, gcall *stmt)
     emit_insn (pattern);
 }
 
+/* Expand the IFN_DEFERRED_INIT function according to its second argument.  */
+static void
+expand_DEFERRED_INIT (internal_fn, gcall *stmt)
+{
+  tree var = gimple_call_lhs (stmt);
+  tree init = NULL_TREE;
+  enum auto_init_type init_type
+    = (enum auto_init_type) TREE_INT_CST_LOW (gimple_call_arg (stmt, 1));
+
+  switch (init_type)
+    {
+    default:
+      gcc_unreachable ();
+    case AUTO_INIT_PATTERN:
+      init = build_pattern_cst_for_auto_init (TREE_TYPE (var));
+      expand_assignment (var, init, false);
+      break;
+    case AUTO_INIT_ZERO:
+      init = build_zero_cst (TREE_TYPE (var));
+      expand_assignment (var, init, false);
+      break;
+    }
+}
+
 /* The size of an OpenACC compute dimension.  */
 
 static void
diff --git a/gcc/internal-fn.def b/gcc/internal-fn.def
index 91a7bfea3eec..77e4fd69312e 100644
--- a/gcc/internal-fn.def
+++ b/gcc/internal-fn.def
@@ -347,6 +347,11 @@ DEF_INTERNAL_FN (VEC_CONVERT, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL)
 DEF_INTERNAL_FN (UNIQUE, ECF_NOTHROW, NULL)
 DEF_INTERNAL_FN (PHI, 0, NULL)
 
+/* A function to represent an artifical initialization to an uninitialized
+   automatic variable.  The first argument is the variable itself, the
+   second argument is the initialization type.  */
+DEF_INTERNAL_FN (DEFERRED_INIT, ECF_CONST | ECF_LEAF | ECF_NOTHROW, NULL)
+
 /* DIM_SIZE and DIM_POS return the size of a particular compute
    dimension and the executing thread's position within that
    dimension.  DIM_POS is pure (and not const) so that it isn't
diff --git a/gcc/testsuite/c-c++-common/auto-init-1.c b/gcc/testsuite/c-c++-common/auto-init-1.c
new file mode 100644
index 000000000000..a29b18e2a6f0
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/auto-init-1.c
@@ -0,0 +1,39 @@
+/* Verify zero initialization for integer and pointer type automatic variables.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=zero -fdump-tree-gimple" } */
+
+#ifndef __cplusplus
+# define bool _Bool
+#endif
+
+enum E {
+  N1 = 0,
+  N2,
+  N3
+};
+
+extern void bar (char, short, int, enum E, long, long long, int *, bool);
+
+void foo()
+{
+  char temp1;
+  short temp2;
+  int temp3;
+  enum E temp4;
+  long temp5;
+  long long temp6;
+  int *temp7;
+  bool temp8;
+
+  bar (temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8);
+  return;
+}
+
+/* { dg-final { scan-tree-dump "temp1 = .DEFERRED_INIT \\(temp1, 2\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp2 = .DEFERRED_INIT \\(temp2, 2\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp3 = .DEFERRED_INIT \\(temp3, 2\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp4 = .DEFERRED_INIT \\(temp4, 2\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp5 = .DEFERRED_INIT \\(temp5, 2\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp6 = .DEFERRED_INIT \\(temp6, 2\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp7 = .DEFERRED_INIT \\(temp7, 2\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp8 = .DEFERRED_INIT \\(temp8, 2\\)" "gimple" } } */
diff --git a/gcc/testsuite/c-c++-common/auto-init-10.c b/gcc/testsuite/c-c++-common/auto-init-10.c
new file mode 100644
index 000000000000..095588931658
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/auto-init-10.c
@@ -0,0 +1,17 @@
+/* Verify the variable attribute "uninitialized".  */ 
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern -fdump-tree-gimple" } */
+
+extern void bar (char, long long *) __attribute__ ((uninitialized)); /* { dg-warning "'uninitialized' attribute ignored" } */
+
+void foo()
+{
+  short temp1;
+  long long __attribute__ ((uninitialized)) temp2[10];
+
+  bar (temp1, temp2);
+  return;
+}
+
+/* { dg-final { scan-tree-dump "temp1 = .DEFERRED_INIT \\(temp1, 1\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump-not "temp2 = .DEFERRED_INIT \\(temp2, 1\\)" "gimple" } } */
diff --git a/gcc/testsuite/c-c++-common/auto-init-11.c b/gcc/testsuite/c-c++-common/auto-init-11.c
new file mode 100644
index 000000000000..12d9ed682f0f
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/auto-init-11.c
@@ -0,0 +1,14 @@
+/* Verify zero initialization for VLA automatic variables.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=zero -fdump-tree-gimple" } */
+
+extern void bar (int);
+
+void foo(int n)
+{
+  int arr[n];
+  bar (arr[2]);
+  return;
+}
+
+/* { dg-final { scan-tree-dump "__builtin_memset" "gimple" } } */
diff --git a/gcc/testsuite/c-c++-common/auto-init-12.c b/gcc/testsuite/c-c++-common/auto-init-12.c
new file mode 100644
index 000000000000..189f6506dbcf
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/auto-init-12.c
@@ -0,0 +1,14 @@
+/* Verify zero initialization for VLA automatic variables.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern -fdump-tree-gimple" } */
+
+extern void bar (int);
+
+void foo(int n)
+{
+  int arr[n];
+  bar (arr[2]);
+  return;
+}
+
+/* { dg-final { scan-tree-dump "__builtin_memcpy" "gimple" } } */
diff --git a/gcc/testsuite/c-c++-common/auto-init-13.c b/gcc/testsuite/c-c++-common/auto-init-13.c
new file mode 100644
index 000000000000..177659ce89e3
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/auto-init-13.c
@@ -0,0 +1,23 @@
+/* Verify the auto initialization of structure or union with a flexible array
+   member.  */ 
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern -fdump-tree-gimple" } */
+
+struct a {
+  int b;
+  int array[];
+};
+union tar {
+  struct a bar;
+  char buf;
+};
+
+int foo()
+{
+  struct a d;
+  union tar var;
+  return d.b + var.bar.b;
+}
+
+/* { dg-final { scan-tree-dump "d = .DEFERRED_INIT \\(d, 1\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "var = .DEFERRED_INIT \\(var, 1\\)" "gimple" } } */
diff --git a/gcc/testsuite/c-c++-common/auto-init-14.c b/gcc/testsuite/c-c++-common/auto-init-14.c
new file mode 100644
index 000000000000..59d0503b854f
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/auto-init-14.c
@@ -0,0 +1,23 @@
+/* Verify the auto initialization of structure or union with a flexible array
+   member.  */ 
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=zero -fdump-tree-gimple" } */
+
+struct a {
+  int b;
+  int array[];
+};
+union tar {
+  struct a bar;
+  char buf;
+};
+
+int foo()
+{
+  struct a d;
+  union tar var;
+  return d.b + var.bar.b;
+}
+
+/* { dg-final { scan-tree-dump "d = .DEFERRED_INIT \\(d, 2\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "var = .DEFERRED_INIT \\(var, 2\\)" "gimple" } } */
diff --git a/gcc/testsuite/c-c++-common/auto-init-15.c b/gcc/testsuite/c-c++-common/auto-init-15.c
new file mode 100644
index 000000000000..6f12f96ac1e2
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/auto-init-15.c
@@ -0,0 +1,13 @@
+/* Verify the auto initialization of nested VLA.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=zero -fdump-tree-gimple" } */
+
+void g(void *);
+
+void foo(int a)
+{
+  int x[a][a];
+  g(x);
+}
+
+/* { dg-final { scan-tree-dump "__builtin_memset" "gimple" } } */
diff --git a/gcc/testsuite/c-c++-common/auto-init-16.c b/gcc/testsuite/c-c++-common/auto-init-16.c
new file mode 100644
index 000000000000..c6a3627da542
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/auto-init-16.c
@@ -0,0 +1,13 @@
+/* Verify the auto initialization of nested VLA.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern -fdump-tree-gimple" } */
+
+void g(void *);
+
+void foo(int a)
+{
+  int x[a][a];
+  g(x);
+}
+
+/* { dg-final { scan-tree-dump "__builtin_memcpy" "gimple" } } */
diff --git a/gcc/testsuite/c-c++-common/auto-init-2.c b/gcc/testsuite/c-c++-common/auto-init-2.c
new file mode 100644
index 000000000000..07c2f38b673b
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/auto-init-2.c
@@ -0,0 +1,39 @@
+/* Verify pattern initialization for integer and pointer type automatic variables.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern -fdump-tree-gimple" } */
+
+#ifndef __cplusplus
+# define bool _Bool
+#endif
+
+enum E {
+  N1 = 0,
+  N2,
+  N3
+};
+
+extern void bar (char, short, int, enum E, long, long long, int *, bool);
+
+void foo()
+{
+  char temp1;
+  short temp2;
+  int temp3;
+  enum E temp4;
+  long temp5;
+  long long temp6;
+  int *temp7;
+  bool temp8;
+
+  bar (temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8);
+  return;
+}
+
+/* { dg-final { scan-tree-dump "temp1 = .DEFERRED_INIT \\(temp1, 1\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp2 = .DEFERRED_INIT \\(temp2, 1\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp3 = .DEFERRED_INIT \\(temp3, 1\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp4 = .DEFERRED_INIT \\(temp4, 1\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp5 = .DEFERRED_INIT \\(temp5, 1\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp6 = .DEFERRED_INIT \\(temp6, 1\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp7 = .DEFERRED_INIT \\(temp7, 1\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp8 = .DEFERRED_INIT \\(temp8, 1\\)" "gimple" } } */
diff --git a/gcc/testsuite/c-c++-common/auto-init-3.c b/gcc/testsuite/c-c++-common/auto-init-3.c
new file mode 100644
index 000000000000..c6b301d9a0ce
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/auto-init-3.c
@@ -0,0 +1,19 @@
+/* Verify zero initialization for floating point type automatic variables.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=zero -fdump-tree-gimple" } */
+
+long double result;
+
+long double foo()
+{
+  float temp1;
+  double temp2;
+  long double temp3;
+  
+  result = temp1 + temp2 + temp3;
+  return result;
+}
+
+/* { dg-final { scan-tree-dump "temp1 = .DEFERRED_INIT \\(temp1, 2\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp2 = .DEFERRED_INIT \\(temp2, 2\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp3 = .DEFERRED_INIT \\(temp3, 2\\)" "gimple" } } */
diff --git a/gcc/testsuite/c-c++-common/auto-init-4.c b/gcc/testsuite/c-c++-common/auto-init-4.c
new file mode 100644
index 000000000000..db23469f2412
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/auto-init-4.c
@@ -0,0 +1,19 @@
+/* Verify pattern initialization for floating point type automatic variables.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern -fdump-tree-gimple" } */
+
+long double result;
+
+long double foo()
+{
+  float temp1;
+  double temp2;
+  long double temp3;
+  
+  result = temp1 + temp2 + temp3;
+  return result;
+}
+
+/* { dg-final { scan-tree-dump "temp1 = .DEFERRED_INIT \\(temp1, 1\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp2 = .DEFERRED_INIT \\(temp2, 1\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp3 = .DEFERRED_INIT \\(temp3, 1\\)" "gimple" } } */
diff --git a/gcc/testsuite/c-c++-common/auto-init-5.c b/gcc/testsuite/c-c++-common/auto-init-5.c
new file mode 100644
index 000000000000..596b066196f6
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/auto-init-5.c
@@ -0,0 +1,21 @@
+/* Verify zero initialization for complex type automatic variables.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=zero -fdump-tree-gimple" } */
+
+
+_Complex long double result;
+
+_Complex long double foo()
+{
+  _Complex float temp1;
+  _Complex double temp2;
+  _Complex long double temp3;
+
+  result = temp1 + temp2 + temp3;
+  return result;
+}
+
+/* { dg-final { scan-tree-dump "temp1 = .DEFERRED_INIT \\(temp1, 2\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp2 = .DEFERRED_INIT \\(temp2, 2\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp3 = .DEFERRED_INIT \\(temp3, 2\\)" "gimple" } } */
+
diff --git a/gcc/testsuite/c-c++-common/auto-init-6.c b/gcc/testsuite/c-c++-common/auto-init-6.c
new file mode 100644
index 000000000000..725d80acdcc0
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/auto-init-6.c
@@ -0,0 +1,21 @@
+/* Verify pattern initialization for complex type automatic variables.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern -fdump-tree-gimple" } */
+
+
+_Complex long double result;
+
+_Complex long double foo()
+{
+  _Complex float temp1;
+  _Complex double temp2;
+  _Complex long double temp3;
+
+  result = temp1 + temp2 + temp3;
+  return result;
+}
+
+/* { dg-final { scan-tree-dump "temp1 = .DEFERRED_INIT \\(temp1, 1\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp2 = .DEFERRED_INIT \\(temp2, 1\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp3 = .DEFERRED_INIT \\(temp3, 1\\)" "gimple" } } */
+
diff --git a/gcc/testsuite/c-c++-common/auto-init-7.c b/gcc/testsuite/c-c++-common/auto-init-7.c
new file mode 100644
index 000000000000..9fd2edc6b642
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/auto-init-7.c
@@ -0,0 +1,35 @@
+/* Verify zero initialization for array, union, and structure type automatic variables.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=zero -fdump-tree-gimple" } */
+
+struct S
+{
+  int f1;
+  float f2;
+  char f3[20];
+};
+
+union U
+{
+  char u1[5];
+  int u2;
+  float u3; 
+};
+
+double result;
+
+double foo()
+{
+  int temp1[3];
+  double temp2[3];
+  struct S temp3;
+  union U temp4;
+  
+  result = temp1[2] + temp2[1] + temp3.f2 + temp4.u3;
+  return result;
+}
+
+/* { dg-final { scan-tree-dump "temp1 = .DEFERRED_INIT \\(temp1, 2\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp2 = .DEFERRED_INIT \\(temp2, 2\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp3 = .DEFERRED_INIT \\(temp3, 2\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp4 = .DEFERRED_INIT \\(temp4, 2\\)" "gimple" } } */
diff --git a/gcc/testsuite/c-c++-common/auto-init-8.c b/gcc/testsuite/c-c++-common/auto-init-8.c
new file mode 100644
index 000000000000..06dfc9709c40
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/auto-init-8.c
@@ -0,0 +1,35 @@
+/* Verify pattern initialization for array, union, and structure type automatic variables.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern -fdump-tree-gimple" } */
+
+struct S
+{
+  int f1;
+  float f2;
+  char f3[20];
+};
+
+union U
+{
+  char u1[5];
+  int u2;
+  float u3; 
+};
+
+double result;
+
+double foo()
+{
+  int temp1[3];
+  double temp2[3];
+  struct S temp3;
+  union U temp4;
+  
+  result = temp1[2] + temp2[1] + temp3.f2 + temp4.u3;
+  return result;
+}
+
+/* { dg-final { scan-tree-dump "temp1 = .DEFERRED_INIT \\(temp1, 1\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp2 = .DEFERRED_INIT \\(temp2, 1\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp3 = .DEFERRED_INIT \\(temp3, 1\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump "temp4 = .DEFERRED_INIT \\(temp4, 1\\)" "gimple" } } */
diff --git a/gcc/testsuite/c-c++-common/auto-init-9.c b/gcc/testsuite/c-c++-common/auto-init-9.c
new file mode 100644
index 000000000000..32dd342c2454
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/auto-init-9.c
@@ -0,0 +1,17 @@
+/* Verify the variable attribute "uninitialized".  */ 
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=zero -fdump-tree-gimple" } */
+
+extern void bar (char, long long *) __attribute__ ((uninitialized)); /* { dg-warning "'uninitialized' attribute ignored" } */
+
+void foo()
+{
+  short temp1;
+  long long __attribute__ ((uninitialized)) temp2[10];
+
+  bar (temp1, temp2);
+  return;
+}
+
+/* { dg-final { scan-tree-dump "temp1 = .DEFERRED_INIT \\(temp1, 2\\)" "gimple" } } */
+/* { dg-final { scan-tree-dump-not "temp2 = .DEFERRED_INIT \\(temp2, 2\\)" "gimple" } } */
diff --git a/gcc/testsuite/c-c++-common/auto-init-esra.c b/gcc/testsuite/c-c++-common/auto-init-esra.c
new file mode 100644
index 000000000000..b204374f02cd
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/auto-init-esra.c
@@ -0,0 +1,35 @@
+/* Verify the strength reduction adjustment for -ftrivial-auto-var-init.  */ 
+/* { dg-do compile } */
+/* { dg-options "-O2 -ftrivial-auto-var-init=zero -fauto-var-init-approach=D -fdump-tree-gimple -fdump-tree-esra" } */
+
+
+typedef double VECTOR[3];
+
+enum
+{
+ X = 0,
+ Y = 1,
+ Z = 2,
+ T = 3
+};
+
+void Assign_Vector(VECTOR d, VECTOR s)
+{
+ d[X] = s[X];
+ d[Y] = s[Y];
+ d[Z] = s[Z];
+}
+
+void VCross(VECTOR a, const VECTOR b, const VECTOR c)
+{
+ VECTOR tmp;
+
+ tmp[X] = b[Y] * c[Z] - b[Z] * c[Y];
+ tmp[Y] = b[Z] * c[X] - b[X] * c[Z];
+ tmp[Z] = b[X] * c[Y] - b[Y] * c[X];
+
+ Assign_Vector(a, tmp);
+}
+
+/* { dg-final { scan-tree-dump-times "tmp = .DEFERRED_INIT \\(tmp, 2\\)" 1 "gimple" } } */
+/* { dg-final { scan-tree-dump-times ".DEFERRED_INIT \\(tmp" 3 "esra" } } */
diff --git a/gcc/testsuite/g++.dg/auto-init-uninit-pred-1_a.C b/gcc/testsuite/g++.dg/auto-init-uninit-pred-1_a.C
new file mode 100644
index 000000000000..33c17441384f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/auto-init-uninit-pred-1_a.C
@@ -0,0 +1,63 @@
+/* { dg-do compile } */
+/* { dg-options "-Wuninitialized -O2 -ftrivial-auto-var-init=zero" } */
+
+typedef long long int64;
+void incr ();
+bool is_valid (int);
+int  get_time ();
+
+class A 
+{
+public:
+  A ();
+  ~A () {
+    if (I) delete I;
+  }
+
+private:
+  int* I;
+};
+
+bool get_url (A *);
+
+class M {
+
+ public:
+__attribute__ ((always_inline))  int GetC (int *c)  {
+
+    A details_str;
+    if (!get_url (&details_str))
+      {
+        incr ();
+        return 1;
+      }
+
+    *c = get_time ();
+    return -1;
+  }
+
+  void do_sth();
+  void do_sth2();
+   
+  void P (int64 t)
+    {
+      int cc; /* { dg-bogus "uninitialized" "uninitialized variable warning" }  */ 
+      if (GetC (&cc) >= 0 )
+        return;
+      
+      if (t && cc <= 0 )  /* { dg-bogus "uninitialized" "uninitialized variable warning" } */
+        {
+          this->do_sth();
+          return;
+        }
+
+    do_sth2();
+  }
+};
+
+M* m; 
+void foo(int x)
+{
+  m = new M;
+  m->P(x);
+}
diff --git a/gcc/testsuite/g++.dg/auto-init-uninit-pred-1_b.C b/gcc/testsuite/g++.dg/auto-init-uninit-pred-1_b.C
new file mode 100644
index 000000000000..6b6bdaed71e0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/auto-init-uninit-pred-1_b.C
@@ -0,0 +1,63 @@
+/* { dg-do compile } */
+/* { dg-options "-Wuninitialized -O2 -ftrivial-auto-var-init=zero" } */
+
+typedef long long int64;
+void incr ();
+bool is_valid (int);
+int  get_time ();
+
+class A 
+{
+public:
+  A ();
+  ~A () {
+    if (I) delete I;
+  }
+
+private:
+  int* I;
+};
+
+bool get_url (A *);
+
+class M {
+
+ public:
+__attribute__ ((always_inline))  int GetC (int *c)  {
+
+    A details_str;
+    if (!get_url (&details_str))
+      {
+        incr ();
+        return 1;
+      }
+
+    *c = get_time ();
+    return -1;
+  }
+
+  void do_sth();
+  void do_sth2();
+   
+  void P (int64 t)
+    {
+      int cc; /* { dg-message "note: 'cc' was declared here" } */
+      if (GetC (&cc) <= 0 ) /* return flag checked wrongly */
+        return;
+      
+      if (t && cc <= 0 )  /* { dg-warning "uninitialized" "uninitialized variable warning" } */
+        {
+          this->do_sth();
+          return;
+        }
+
+    do_sth2();
+  }
+};
+
+M* m; 
+void foo(int x)
+{
+  m = new M;
+  m->P(x);
+}
diff --git a/gcc/testsuite/g++.dg/auto-init-uninit-pred-2_a.C b/gcc/testsuite/g++.dg/auto-init-uninit-pred-2_a.C
new file mode 100644
index 000000000000..fc18cb1e7c91
--- /dev/null
+++ b/gcc/testsuite/g++.dg/auto-init-uninit-pred-2_a.C
@@ -0,0 +1,62 @@
+/* { dg-do compile } */
+/* { dg-options "-Wuninitialized -O2 -ftrivial-auto-var-init=zero" } */
+
+typedef long long int64;
+void incr ();
+bool is_valid (int);
+int  get_time ();
+
+class A 
+{
+public:
+  A ();
+  ~A () {
+    if (I) delete I;
+  }
+
+private:
+  int* I;
+};
+
+bool get_url (A *);
+
+class M {
+
+ public:
+__attribute__ ((always_inline))  bool GetC (int *c)  {
+
+    A details_str;
+    if (get_url (&details_str))
+      {
+        *c = get_time ();
+        return true;
+      }
+
+    return false;
+  }
+
+  void do_sth();
+  void do_sth2();
+   
+  void P (int64 t)
+    {
+      int cc; 
+      if (!GetC (&cc)) /* return flag checked properly */
+        return;
+      
+      if (cc <= 0)  /* { dg-bogus "uninitialized" "uninitialized variable warning" } */
+        {
+          this->do_sth();
+          return;
+        }
+
+    do_sth2();
+  }
+};
+
+M* m; 
+void foo(int x)
+{
+  m = new M;
+  m->P(x);
+}
diff --git a/gcc/testsuite/g++.dg/auto-init-uninit-pred-2_b.C b/gcc/testsuite/g++.dg/auto-init-uninit-pred-2_b.C
new file mode 100644
index 000000000000..e85a36f16fff
--- /dev/null
+++ b/gcc/testsuite/g++.dg/auto-init-uninit-pred-2_b.C
@@ -0,0 +1,62 @@
+/* { dg-do compile } */
+/* { dg-options "-Wuninitialized -O2 -ftrivial-auto-var-init=zero" } */
+
+typedef long long int64;
+void incr ();
+bool is_valid (int);
+int  get_time ();
+
+class A 
+{
+public:
+  A ();
+  ~A () {
+    if (I) delete I;
+  }
+
+private:
+  int* I;
+};
+
+bool get_url (A *);
+
+class M {
+
+ public:
+__attribute__ ((always_inline))  bool GetC (int *c)  {
+
+    A details_str;
+    if (get_url (&details_str))
+      {
+        *c = get_time ();
+        return true;
+      }
+
+    return false;
+  }
+
+  void do_sth();
+  void do_sth2();
+   
+  void P (int64 t)
+    {
+      int cc; /* { dg-message "note: 'cc' was declared here" } */
+      if (GetC (&cc)) /* return flag checked wrongly */
+        return;
+      
+      if (cc <= 0)  /* { dg-warning "uninitialized" "uninitialized variable warning" } */
+        {
+          this->do_sth();
+          return;
+        }
+
+    do_sth2();
+  }
+};
+
+M* m; 
+void foo(int x)
+{
+  m = new M;
+  m->P(x);
+}
diff --git a/gcc/testsuite/g++.dg/auto-init-uninit-pred-3_a.C b/gcc/testsuite/g++.dg/auto-init-uninit-pred-3_a.C
new file mode 100644
index 000000000000..09ed69215320
--- /dev/null
+++ b/gcc/testsuite/g++.dg/auto-init-uninit-pred-3_a.C
@@ -0,0 +1,77 @@
+/* { dg-do compile } */
+/* { dg-options "-Wuninitialized -O2 -ftrivial-auto-var-init=zero" } */
+
+/* Multiple initialization paths.  */
+
+typedef long long int64;
+void incr ();
+bool is_valid (int);
+int  get_time ();
+
+class A
+{
+public:
+  A ();
+  ~A () {
+    if (I) delete I;
+  }
+
+private:
+  int* I;
+};
+
+bool get_url (A *);
+bool get_url2 (A *);
+
+class M {
+
+ public:
+ __attribute__ ((always_inline))
+ bool GetC (int *c)  {
+
+    A details_str;
+    /* Intialization path 1  */
+    if (get_url (&details_str))
+      {
+        *c = get_time ();
+        return true;
+      }
+
+    /* insert dtor calls (inlined) into following return paths  */
+    A tmp_str;
+
+    /* Intializtion path 2  */
+    if (get_url2 (&details_str))
+      {
+        *c = get_time ();
+        return true;
+      }
+
+    return false;
+  }
+
+  void do_sth();
+  void do_sth2();
+
+  void P (int64 t)
+    {
+      int cc;
+      if (!GetC (&cc)) /* return flag checked properly */
+        return;
+
+      if (cc <= 0)   /* { dg-bogus "uninitialized" "uninitialized variable warning" } */
+        {
+          this->do_sth();
+          return;
+        }
+
+    do_sth2();
+  }
+};
+
+M* m;
+void test(int x)
+{
+  m = new M;
+  m->P(x);
+}
diff --git a/gcc/testsuite/g++.dg/auto-init-uninit-pred-3_b.C b/gcc/testsuite/g++.dg/auto-init-uninit-pred-3_b.C
new file mode 100644
index 000000000000..8e7b8541725e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/auto-init-uninit-pred-3_b.C
@@ -0,0 +1,87 @@
+/* { dg-do compile } */
+/* { dg-options "-Wuninitialized -O2 -ftrivial-auto-var-init=zero" } */
+
+/* Multiple initialization paths.  */
+
+typedef long long int64;
+void incr ();
+bool is_valid (int);
+int  get_time ();
+
+class A
+{
+public:
+  A ();
+  ~A () {
+    if (I) delete I;
+  }
+
+private:
+  int* I;
+};
+
+bool get_url (A *);
+bool get_url2 (A *);
+bool get_url3 (A *);
+
+class M {
+
+ public:
+ __attribute__ ((always_inline))
+ bool GetC (int *c)  {
+
+    A details_str;
+
+    /* Initialization path 1  */
+    if (get_url (&details_str))
+      {
+        *c = get_time ();
+        return true;
+      }
+
+    /* Destructor call before return*/
+    A tmp_str;
+
+    /* Initialization path 2  */
+    if (get_url2 (&details_str))
+      {
+        *c = get_time ();
+        return true;
+      }
+
+    /* Fail to initialize in this path but
+       still returns true  */
+    if (get_url2 (&details_str))
+      {
+        /* Fail to initialize *c  */
+        return true;
+      }
+
+    return false;
+  }
+
+  void do_sth();
+  void do_sth2();
+
+  void P (int64 t)
+    {
+      int cc;
+      if (!GetC (&cc))
+        return;
+
+      if (cc <= 0)   /* { dg-warning "uninitialized" "uninitialized variable warning" } */
+        {
+          this->do_sth();
+          return;
+        }
+
+    do_sth2();
+  }
+};
+
+M* m;
+void test(int x)
+{
+  m = new M;
+  m->P(x);
+}
diff --git a/gcc/testsuite/g++.dg/auto-init-uninit-pred-4.C b/gcc/testsuite/g++.dg/auto-init-uninit-pred-4.C
new file mode 100644
index 000000000000..c48770ae44dd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/auto-init-uninit-pred-4.C
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+/* { dg-options "-Wuninitialized -Og -ftrivial-auto-var-init=zero" } */
+
+int pop ();
+int pop_first_bucket;
+
+int my_pop ()
+{
+  int out;  // { dg-bogus "uninitialized" "uninitialized variable warning" }
+
+  while (pop_first_bucket)
+    if (pop_first_bucket && (out = pop()))
+      return out;
+
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/auto-init-uninit-pred-loop-1_a.cc b/gcc/testsuite/g++.dg/auto-init-uninit-pred-loop-1_a.cc
new file mode 100644
index 000000000000..629677a60259
--- /dev/null
+++ b/gcc/testsuite/g++.dg/auto-init-uninit-pred-loop-1_a.cc
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-options "-Wuninitialized -O2 -ftrivial-auto-var-init=zero" } */
+
+extern int bar();
+int foo(void)
+{
+ for (;;) {
+   int err = ({int _err; /*  { dg-bogus "uninitialized" "false warning" } */
+     for (int i = 0; i < 16; ++i) {
+       _err = 17;
+       _err = bar();
+     }
+     _err; /*  { dg-bogus "uninitialized" "false warning" } */
+   });
+
+   if (err == 0) return 17; 
+ }
+
+ return 18;
+}
+
diff --git a/gcc/testsuite/g++.dg/auto-init-uninit-pred-loop-1_b.cc b/gcc/testsuite/g++.dg/auto-init-uninit-pred-loop-1_b.cc
new file mode 100644
index 000000000000..04ab364ac83e
--- /dev/null
+++ b/gcc/testsuite/g++.dg/auto-init-uninit-pred-loop-1_b.cc
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-options "-Wuninitialized -O2 -ftrivial-auto-var-init=zero" } */
+
+extern int bar();
+int foo(int n)
+{
+ for (;;) {
+   int err = ({int _err; 
+     for (int i = 0; i < n; ++i) {
+       _err = 17;
+       _err = bar();
+     }
+     _err; 
+   }); /* { dg-warning "uninitialized" "warn on _err" } */
+
+   if (err == 0) return 17; 
+ }
+
+ return 18;
+}
+
diff --git a/gcc/testsuite/g++.dg/auto-init-uninit-pred-loop-1_c.cc b/gcc/testsuite/g++.dg/auto-init-uninit-pred-loop-1_c.cc
new file mode 100644
index 000000000000..82a1846c6e0b
--- /dev/null
+++ b/gcc/testsuite/g++.dg/auto-init-uninit-pred-loop-1_c.cc
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-options "-Wuninitialized -O2 -ftrivial-auto-var-init=zero" } */
+
+extern int bar();
+int foo(int n, int m)
+{
+ for (;;) {
+   int err = ({int _err; 
+     for (int i = 0; i < 16; ++i) {
+       if (m+i > n)
+          break;
+       _err = 17;
+       _err = bar();
+     }
+     _err; 
+   }); 
+
+   if (err == 0) return 17; }); /* { dg-warning "uninitialized" "warn on _err" } */
+ }
+
+ return 18;
+}
+
diff --git a/gcc/testsuite/g++.dg/auto-init-uninit-pred-loop_1.cc b/gcc/testsuite/g++.dg/auto-init-uninit-pred-loop_1.cc
new file mode 100644
index 000000000000..629677a60259
--- /dev/null
+++ b/gcc/testsuite/g++.dg/auto-init-uninit-pred-loop_1.cc
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-options "-Wuninitialized -O2 -ftrivial-auto-var-init=zero" } */
+
+extern int bar();
+int foo(void)
+{
+ for (;;) {
+   int err = ({int _err; /*  { dg-bogus "uninitialized" "false warning" } */
+     for (int i = 0; i < 16; ++i) {
+       _err = 17;
+       _err = bar();
+     }
+     _err; /*  { dg-bogus "uninitialized" "false warning" } */
+   });
+
+   if (err == 0) return 17; 
+ }
+
+ return 18;
+}
+
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-1.c b/gcc/testsuite/gcc.dg/auto-init-uninit-1.c
new file mode 100644
index 000000000000..cb0e7cc62545
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-1.c
@@ -0,0 +1,30 @@
+/* Spurious uninitialized variable warnings, case 1.
+   Taken from cppfiles.c (merge_include_chains) */
+/* { dg-do compile } */
+/* { dg-options "-O -Wuninitialized -ftrivial-auto-var-init=zero" } */
+
+struct list
+{
+  struct list *next;
+  int id;
+};
+
+extern void free (void *);
+
+void remove_dupes (struct list *el)
+{
+  struct list *p, *q, *r;  /* { dg-bogus "r" "uninitialized variable warning" } */
+
+  for (p = el; p; p = p->next)
+  {
+    for (q = el; q != p; q = q->next)
+      if (q->id == p->id)
+      {
+	r->next = p->next;
+	free (p);
+	p = r;
+	break;
+      }
+    r = p;
+  }
+}
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-11.c b/gcc/testsuite/gcc.dg/auto-init-uninit-11.c
new file mode 100644
index 000000000000..559e2d963376
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-11.c
@@ -0,0 +1,42 @@
+/* Positive test for uninitialized variables.  */
+/* { dg-do compile } */
+/* { dg-options "-O -Wuninitialized -ftrivial-auto-var-init=zero" } */
+
+int sink;
+
+void f1(int parm)	/* { dg-bogus "uninitialized" "parameter" } */
+{
+  sink = parm;		/* { dg-bogus "uninitialized" "parameter" } */
+}
+
+void f2(void)
+{
+  int x;
+  sink = x;		/* { dg-warning "is used" "unconditional" } */
+}
+
+void f3(int p)
+{
+  int x;		
+  if (p)
+    x = p;
+  sink = x;            /* { dg-warning "may be used" "conditional" } */
+}
+
+void f4(int p)
+{
+  int x;		/* { dg-bogus "uninitialized" "easy if" } */
+  if (p)
+    x = 1;
+  else
+    x = 2;
+  sink = x;
+}
+
+void f5(void)
+{
+  int x, i;		/* { dg-bogus "uninitialized" "easy loop" } */
+  for (i = 0; i < 10; ++i)
+    x = 1;
+  sink = x;
+}
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-12.c b/gcc/testsuite/gcc.dg/auto-init-uninit-12.c
new file mode 100644
index 000000000000..acff725722dc
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-12.c
@@ -0,0 +1,12 @@
+/* PR 23497 */
+/* { dg-do compile } */
+/* { dg-options "-O -Wuninitialized -ftrivial-auto-var-init=zero" } */
+
+typedef _Complex float C;
+C foo()
+{
+  C f;
+  __real__ f = 0;
+  __imag__ f = 0;
+  return f;
+}
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-13.c b/gcc/testsuite/gcc.dg/auto-init-uninit-13.c
new file mode 100644
index 000000000000..87dd8b587e00
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-13.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-O -Wuninitialized -ftrivial-auto-var-init=zero" } */
+
+typedef _Complex float C;
+C foo()
+{
+  C f;
+  __imag__ f = 0;
+  return f;	/* { dg-warning "is used" "unconditional" } */
+}
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-14.c b/gcc/testsuite/gcc.dg/auto-init-uninit-14.c
new file mode 100644
index 000000000000..592052a9e9d0
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-14.c
@@ -0,0 +1,20 @@
+/* PR 24931 */
+/* { dg-do compile } */
+/* { dg-options "-O -Wuninitialized -ftrivial-auto-var-init=zero" } */
+
+struct p {
+        short x, y;
+};
+
+struct s {
+        int i;
+        struct p p;
+};
+
+struct s f()
+{
+        struct s s;
+        s.p = (struct p){};
+        s.i = (s.p.x || s.p.y);
+        return s;
+}
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-15.c b/gcc/testsuite/gcc.dg/auto-init-uninit-15.c
new file mode 100644
index 000000000000..121f0cff274a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-15.c
@@ -0,0 +1,26 @@
+/* PR tree-optimization/17506
+   We issue an uninitialized variable warning at a wrong location at
+   line 11, which is very confusing.  Make sure we print out a note to
+   make it less confusing.  (not xfailed alternative)
+   But it is of course ok if we warn in bar about uninitialized use
+   of j.  (not xfailed alternative)  */
+/* { dg-do compile } */
+/* { dg-options "-O1 -Wuninitialized -ftrivial-auto-var-init=zero" } */
+
+inline int
+foo (int i)
+{
+  if (i) /* { dg-warning "used uninitialized" } */
+    return 1;
+  return 0;
+}
+
+void baz (void);
+
+void
+bar (void)
+{
+  int j; /* { dg-message "note: 'j' was declared here" "" } */
+  for (; foo (j); ++j)  /* { dg-warning "'j' is used uninitialized" "" { xfail *-*-* } } */
+    baz ();
+}
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-16.c b/gcc/testsuite/gcc.dg/auto-init-uninit-16.c
new file mode 100644
index 000000000000..0e4f336f726f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-16.c
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -Wuninitialized -ftrivial-auto-var-init=zero" } */
+
+int foo, bar;
+
+static
+void decode_reloc(int reloc, int *is_alt)
+{
+  if (reloc >= 20)
+      *is_alt = 1;
+  else if (reloc >= 10)
+      *is_alt = 0;
+}
+
+void testfunc()
+{
+  int alt_reloc;
+
+  decode_reloc(foo, &alt_reloc);
+
+  if (alt_reloc) /* { dg-warning "may be used uninitialized" } */
+    bar = 42;
+}
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-17.c b/gcc/testsuite/gcc.dg/auto-init-uninit-17.c
new file mode 100644
index 000000000000..9eec9440c75e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-17.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O -Wuninitialized -ftrivial-auto-var-init=zero" } */
+
+typedef _Complex float C;
+C foo(int cond)
+{
+  C f;
+  __imag__ f = 0;
+  if (cond)
+    {
+      __real__ f = 1;
+      return f;
+    }
+  return f;	/* { dg-warning "may be used" "unconditional" } */
+}
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-18.c b/gcc/testsuite/gcc.dg/auto-init-uninit-18.c
new file mode 100644
index 000000000000..4922848f6dc7
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-18.c
@@ -0,0 +1,24 @@
+/* { dg-do compile }  */
+/* { dg-options "-O -Wuninitialized -ftrivial-auto-var-init=zero" } */
+
+char *foo(int bar, char *baz)
+{
+  char *tmp;
+
+  if (bar & 3)
+    tmp = baz;
+
+  switch (bar) {
+  case 1:
+    tmp[5] = 7;    /* { dg-bogus "may be used uninitialized" } */
+    break;
+  case 2:
+    tmp[11] = 15;  /* { dg-bogus "may be used uninitialized" } */
+    break;
+  default:
+    tmp = 0;
+    break;
+  }
+
+  return tmp;      /* { dg-bogus "may be used uninitialized" } */
+}
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-19.c b/gcc/testsuite/gcc.dg/auto-init-uninit-19.c
new file mode 100644
index 000000000000..38d27e4f9548
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-19.c
@@ -0,0 +1,26 @@
+/* { dg-do compile } */
+/* { dg-options "-O -Wuninitialized -ftrivial-auto-var-init=zero" } */
+/* { dg-additional-options "-finline-small-functions" { target avr-*-* } } */
+
+int a, l, m;
+float *b;
+float c, d, e, g, h;
+unsigned char i, k;
+void
+fn1 (int p1, float *f1, float *f2, float *f3, unsigned char *c1, float *f4,
+     unsigned char *c2, float *p10)
+{
+  if (p1 & 8)
+    b[3] = p10[a];
+  /* { dg-warning "may be used uninitialized" "" { target { { nonpic || pie_enabled } || { hppa*64*-*-* *-*-darwin* } } } .-1 } */
+}
+
+void
+fn2 ()
+{
+  float *n;
+  if (l & 6)
+    n = &c + m;
+  fn1 (l, &d, &e, &g, &i, &h, &k, n);
+  /* { dg-warning "may be used uninitialized" "" { target { ! { { nonpic || pie_enabled } || { hppa*64*-*-* *-*-darwin* } } } } .-1 } */
+}
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-2.c b/gcc/testsuite/gcc.dg/auto-init-uninit-2.c
new file mode 100644
index 000000000000..da03bf8f6d98
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-2.c
@@ -0,0 +1,52 @@
+/* Spurious uninitialized variable warnings, case 2.
+   Taken from cpphash.c (macroexpand) */
+/* { dg-do compile } */
+/* { dg-options "-O -Wuninitialized -ftrivial-auto-var-init=zero" } */
+
+struct definition
+{
+  int nargs;
+  int rest_args;
+};
+
+struct cpp_reader;
+
+enum cpp_token
+{
+  CPP_EOF, CPP_POP, CPP_COMMA, CPP_RPAREN
+};
+
+extern enum cpp_token macarg (struct cpp_reader *, int);
+
+void
+macroexpand (struct cpp_reader *pfile, struct definition *defn)
+{
+  int nargs = defn->nargs;
+
+  if (nargs >= 0)
+    {
+      enum cpp_token token;  /* { dg-bogus "token" "uninitialized variable warning" } */
+      int i, rest_args;
+      i = 0;
+      rest_args = 0;
+      do
+	{
+	  if (rest_args)
+	    continue;
+	  if (i < nargs || (nargs == 0 && i == 0))
+	    {
+	      /* if we are working on last arg which absorbs rest of args... */
+	      if (i == nargs - 1 && defn->rest_args)
+		rest_args = 1;
+	      token = macarg (pfile, rest_args);
+	    }
+	  else
+	    token = macarg (pfile, 0);
+	  if (token == CPP_EOF || token == CPP_POP)
+	    return;
+
+	  i++;
+	}
+      while (token == CPP_COMMA);
+    }
+}
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-20.c b/gcc/testsuite/gcc.dg/auto-init-uninit-20.c
new file mode 100644
index 000000000000..f533ce9c70e7
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-20.c
@@ -0,0 +1,18 @@
+/* Spurious uninitialized variable warnings, from gdb */
+/* { dg-do compile } */
+/* { dg-options "-O2 -Wuninitialized -ftrivial-auto-var-init=zero" } */
+struct os { struct o *o; };
+struct o { struct o *next; struct os *se; };
+void f(struct o *o){
+  struct os *s;
+  if(o) s = o->se;
+  while(o && s == o->se){
+    s++; // here `o' is non-zero and thus s is initialized
+    s == o->se  // `?' is essential, `if' does not trigger the warning
+      ? (o = o->next, o ? s = o->se : 0)
+      : 0;
+  }
+}
+
+
+
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-21.c b/gcc/testsuite/gcc.dg/auto-init-uninit-21.c
new file mode 100644
index 000000000000..6044eab27870
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-21.c
@@ -0,0 +1,33 @@
+/* PR69537, spurious warning because of a missed optimization. */
+/* { dg-do compile } */
+/* { dg-options "-O2 -fno-short-enums -Wuninitialized -ftrivial-auto-var-init=zero" } */
+
+enum clnt_stat {
+ RPC_SUCCESS=0,
+ RPC_CANTENCODEARGS=1,
+};
+ 
+int do_ypcall_tr ();
+ 
+static int
+yp_master (char **outname)
+{
+  // Replacing enum clnt_stat with int avoids the warning.
+  enum clnt_stat result;
+  result = do_ypcall_tr ();
+  if (result != 0)
+    return result;
+  *outname = __builtin_strdup ("foo");
+  return 0;
+}
+ 
+int
+yp_update (void)
+{
+  char *master;
+  int r;
+  if ((r = yp_master (&master)) != 0)
+    return r;
+  __builtin_free (master); /* { dg-bogus "uninitialized" } */
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-22.c b/gcc/testsuite/gcc.dg/auto-init-uninit-22.c
new file mode 100644
index 000000000000..0200d734a2c3
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-22.c
@@ -0,0 +1,69 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -Wuninitialized --param vect-max-version-for-alias-checks=20 -ftrivial-auto-var-init=zero" } */
+
+#include <stdint.h>
+
+#define A1  2896 /* (1/sqrt(2))<<12 */
+#define A2  2217
+#define A3  3784
+#define A4 -5352
+
+#define IDCT_TRANSFORM(dest,s0,s1,s2,s3,s4,s5,s6,s7,d0,d1,d2,d3,d4,d5,d6,d7,munge,src) {\
+    const int a0 = (src)[s0] + (src)[s4]; \
+    const int a1 = (src)[s0] - (src)[s4]; \
+    const int a2 = (src)[s2] + (src)[s6]; \
+    const int a3 = (A1*((src)[s2] - (src)[s6])) >> 11; \
+    const int a4 = (src)[s5] + (src)[s3]; \
+    const int a5 = (src)[s5] - (src)[s3]; \
+    const int a6 = (src)[s1] + (src)[s7]; \
+    const int a7 = (src)[s1] - (src)[s7]; \
+    const int b0 = a4 + a6; \
+    const int b1 = (A3*(a5 + a7)) >> 11; \
+    const int b2 = ((A4*a5) >> 11) - b0 + b1; \
+    const int b3 = (A1*(a6 - a4) >> 11) - b2; \
+    const int b4 = ((A2*a7) >> 11) + b3 - b1; \
+    (dest)[d0] = munge(a0+a2   +b0); \
+    (dest)[d1] = munge(a1+a3-a2+b2); \
+    (dest)[d2] = munge(a1-a3+a2+b3); \
+    (dest)[d3] = munge(a0-a2   -b4); \
+    (dest)[d4] = munge(a0-a2   +b4); \
+    (dest)[d5] = munge(a1-a3+a2-b3); \
+    (dest)[d6] = munge(a1+a3-a2-b2); \
+    (dest)[d7] = munge(a0+a2   -b0); \
+}
+
+#define MUNGE_NONE(x) (x)
+#define IDCT_COL(dest,src) IDCT_TRANSFORM(dest,0,8,16,24,32,40,48,56,0,8,16,24,32,40,48,56,MUNGE_NONE,src)
+
+#define MUNGE_ROW(x) (((x) + 0x7F)>>8)
+#define IDCT_ROW(dest,src) IDCT_TRANSFORM(dest,0,1,2,3,4,5,6,7,0,1,2,3,4,5,6,7,MUNGE_ROW,src)
+
+static inline void bink_idct_col(int *dest, const int32_t *src)
+{
+    if ((src[8]|src[16]|src[24]|src[32]|src[40]|src[48]|src[56])==0) {
+        dest[0]  =
+        dest[8]  =
+        dest[16] =
+        dest[24] =
+        dest[32] =
+        dest[40] =
+        dest[48] =
+        dest[56] = src[0];
+    } else {
+        IDCT_COL(dest, src);
+    }
+}
+
+int bink_idct_put_c(uint8_t *dest, int linesize, int32_t *block)
+{
+    int i;
+    int temp[64];
+    for (i = 0; i < 8; i++)
+        bink_idct_col(&temp[i], &block[i]);
+    for (i = 0; i < 8; i++) {
+        IDCT_ROW( (&dest[i*linesize]), (&temp[8*i]) );
+    }
+
+    return 0;
+}
+
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-23.c b/gcc/testsuite/gcc.dg/auto-init-uninit-23.c
new file mode 100644
index 000000000000..7dce8d052e16
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-23.c
@@ -0,0 +1,27 @@
+/* PR tree-optimization/78455 */
+/* { dg-do compile } */
+/* { dg-options "-O2 -Wuninitialized -ftrivial-auto-var-init=zero" } */
+
+int ij;
+
+void
+ql (void)
+{
+  int m5 = 0;
+
+  for (;;)
+  {
+    if (0)
+      for (;;)
+      {
+        int *go;
+        int *t4 = go; /* { dg-warning "is used uninitialized" } */
+
+ l1:
+        *t4 = (*t4 != 0) ? 0 : 2;
+      }
+
+    if (ij != 0)
+      goto l1;
+  }
+}
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-24.c b/gcc/testsuite/gcc.dg/auto-init-uninit-24.c
new file mode 100644
index 000000000000..1f6740c123ad
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-24.c
@@ -0,0 +1,10 @@
+/* { dg-do compile } */
+/* { dg-options "-O -Wmaybe-uninitialized -ftrivial-auto-var-init=zero" } */
+
+int foo (int x)
+{
+  int y;
+  if (x)
+    return *(&y + 1); /* { dg-bogus "may be used uninitialized" } */
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-25.c b/gcc/testsuite/gcc.dg/auto-init-uninit-25.c
new file mode 100644
index 000000000000..f36d95f9d279
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-25.c
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-options "-O -Wmaybe-uninitialized -ftrivial-auto-var-init=zero" } */
+
+extern unsigned bar (void);
+extern void quux (void);
+
+unsigned foo (unsigned v)
+{
+  unsigned u;
+  if (v != 1)
+    u = bar ();
+
+  // Prevent the "dom" pass from changing the CFG layout based on the inference
+  // 'if (v != 1) is false then (v != 2) is true'.  (Now it would have to
+  // duplicate the loop in order to do so, which is deemed expensive.)
+  for (int i = 0; i < 10; i++)
+    quux ();
+
+  if (v != 2)
+    return u;       /* { dg-warning "may be used uninitialized" } */
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-26.c b/gcc/testsuite/gcc.dg/auto-init-uninit-26.c
new file mode 100644
index 000000000000..ae97ecfa71e1
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-26.c
@@ -0,0 +1,23 @@
+/* { dg-do compile } */
+/* { dg-options "-O -Wmaybe-uninitialized -ftrivial-auto-var-init=zero" } */
+
+extern unsigned bar (void);
+extern void quux (void);
+
+unsigned foo (unsigned v)
+{
+  unsigned u;
+  if (v != 100)
+    u = bar ();
+
+  // Prevent the "dom" pass from changing the CFG layout based on the inference
+  // 'if (v != 100) is false then (v < 105) is true'.  (Now it would have to
+  // duplicate the loop in order to do so, which is deemed expensive.)
+  for (int i = 0; i < 10; i++)
+    quux ();
+
+  if (v < 105) /* v == 100 falls into this range.  */
+    return u;       /* { dg-warning "may be used uninitialized" }  */
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-3.c b/gcc/testsuite/gcc.dg/auto-init-uninit-3.c
new file mode 100644
index 000000000000..7ff228501f8d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-3.c
@@ -0,0 +1,33 @@
+/* Spurious uninit variable warnings, case 3.
+   Inspired by cppexp.c (parse_charconst) */
+/* { dg-do compile } */
+/* { dg-options "-O -Wuninitialized -ftrivial-auto-var-init=zero" } */
+
+extern void error (char *);
+
+int
+parse_charconst (const char *start, const char *end)
+{
+  int c; /* { dg-bogus "c" "uninitialized variable warning" } */
+  int nchars, retval;
+
+  nchars = 0;
+  retval = 0;
+  while (start < end)
+    {
+      c = *start++;
+      if (c == '\'')
+	break;
+      nchars++;
+      retval += c;
+      retval <<= 8;
+    }
+
+  if (nchars == 0)
+    return 0;
+
+  if (c != '\'')
+    error ("malformed character constant");
+
+  return retval;
+}
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-34.c b/gcc/testsuite/gcc.dg/auto-init-uninit-34.c
new file mode 100644
index 000000000000..98fc366c871f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-34.c
@@ -0,0 +1,58 @@
+/* PR middle-end/10138 - warn for uninitialized arrays passed as const*
+   arguments
+   Verify that passing pointers to uninitialized objects to arguments
+   to functions declared with attribute access is diagnosed where expected.
+   { dg-do compile }
+   { dg-options "-O -Wall -ftrivial-auto-var-init=zero" } */
+
+#define RW(...) __attribute__ ((access (read_write, __VA_ARGS__)))
+
+RW (1) RW (3) void
+f4pi (int*, int*, int*, int*);    // { dg-message "in a call to 'f4pi' declared with attribute 'access \\\(read_write, \[13\]\\\)'" }
+
+
+void nowarn_scalar (void)
+{
+  int i1 = 0, i2, i3 = 1, i4;
+  f4pi (&i1, &i2, &i3, &i4);
+}
+
+void warn_scalar_1 (void)
+{
+  int i1;                         // { dg-message "declared here" }
+  int i2, i3 = 1, i4;
+
+  f4pi (&i1, &i2, &i3, &i4);      // { dg-warning "'i1' may be used uninitialized" }
+}
+
+void warn_scalar_2 (void)
+{
+  int j1 = 0, j2, j4;
+  int j3;
+
+  f4pi (&j1, &j2, &j3, &j4);      // { dg-warning "'j3' may be used uninitialized" }
+}
+
+
+void nowarn_array_init (void)
+{
+  int a1[4] = { 0 }, a2[5], a3[6] = { 0 }, a4[7];
+
+  f4pi (a1, a2, a3, a4);
+}
+
+void warn_array_1 (void)
+{
+  int a1[4];                  // { dg-message "'a1' declared here" }
+  int a2[5], a3[6] = { 0 }, a4[7];
+
+  f4pi (a1, a2, a3, a4);      // { dg-warning "'a1' may be used uninitialized" }
+}
+
+void warn_array_2 (void)
+{
+  int a1[4] = { 0 }, a2[5], a4[7];
+  int a3[6];                  // { dg-message "'a3' declared here" }
+
+  f4pi (a1, a2, a3, a4);      // { dg-warning "'a3' may be used uninitialized" }
+}
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-36.c b/gcc/testsuite/gcc.dg/auto-init-uninit-36.c
new file mode 100644
index 000000000000..64377d380ee9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-36.c
@@ -0,0 +1,238 @@
+/* PR middle-end/10138 - warn for uninitialized arrays passed as const*
+   arguments
+   Verify that passing pointers to uninitialized objects to const
+   arguments to built-ins is diagnosed where expected.
+   { dg-do compile }
+   { dg-options "-O -Wall -ftrivial-auto-var-init=zero" }
+   { dg-require-effective-target alloca } */
+
+typedef __SIZE_TYPE__ size_t;
+
+void* alloca (size_t);
+void* malloc (size_t);
+void* realloc (void*, size_t);
+
+void* memcpy (void*, const void*, size_t);
+char* strcpy (char*, const char*);
+size_t strlen (const char*);
+
+void sink (void*);
+
+void nowarn_array_memcpy (void *d, unsigned n)
+{
+  int a[2];
+  /* Diagnose this?  */
+  memcpy (d, a, n /* Non-constant to avoid folding into MEM_REF.  */);
+}
+
+void nowarn_array_plus_cst_memcpy (void *d, unsigned n)
+{
+  int a[3];
+  /* Diagnose this?  */
+  memcpy (d, a + 1, n);
+}
+
+void nowarn_array_plus_var_memcpy (void *d, unsigned n, int i)
+{
+  int a[4];
+  /* Diagnose this?  */
+  memcpy (d, a + i, n);
+}
+
+void nowarn_array_assign_memcpy (char *d, unsigned n)
+{
+  int a[3];
+  a[1] = 3;
+  memcpy (d, a, n);
+}
+
+void nowarn_array_init_memcpy (char *d, unsigned n)
+{
+  int a[4] = { 0 };
+  memcpy (d, a, n);
+}
+
+void nowarn_array_compound_memcpy (void *d, unsigned n)
+{
+  memcpy (d, (int[2]){ 0 }, n);
+}
+
+void nowarn_struct_assign_memcpy (void *d, unsigned n)
+{
+  struct S { int a, b, c, d; } s;
+  s.b = 1;
+  s.d = 2;
+  memcpy (d, &s, n);
+}
+
+
+void nowarn_array_init_strcpy (char *d[], unsigned n)
+{
+  char a[8] = "012";
+
+  strcpy (d[0], a);
+  strcpy (d[1], a + 1);
+  strcpy (d[1], a + 2);
+  strcpy (d[1], a + 3);
+  strcpy (d[1], a + 4);
+  strcpy (d[1], a + 5);
+  strcpy (d[1], a + 6);
+  strcpy (d[1], a + 7);
+}
+
+
+void nowarn_array_assign_strcpy (char *d[], unsigned n)
+{
+  char a[8];
+  a[0] = '0';
+  a[1] = '1';
+  a[2] = '2';
+  a[3] = '\0';
+
+  strcpy (d[0], a);
+  strcpy (d[1], a + 1);
+  strcpy (d[1], a + 2);
+  strcpy (d[1], a + 3);
+}
+
+void warn_array_plus_cst_strcpy (char *d, unsigned n)
+{
+  char a[8];
+  a[0] = '1';
+  a[1] = '2';
+  a[2] = '3';
+  a[3] = '\0';
+
+  strcpy (d, a + 4);          // { dg-warning "\\\[-Wuninitialized" }
+  strcpy (d, a + 5);          // { dg-warning "\\\[-Wuninitialized" }
+  strcpy (d, a + 6);          // { dg-warning "\\\[-Wuninitialized" }
+  strcpy (d, a + 7);          // { dg-warning "\\\[-Wuninitialized" }
+}
+
+void nowarn_array_plus_var_strcpy (char *d, int i)
+{
+  char a[8];
+  a[0] = '1';
+  a[1] = '2';
+  a[2] = '3';
+  a[3] = '\0';
+
+  strcpy (d, a + i);
+}
+
+
+size_t nowarn_array_assign_strlen (const char *s)
+{
+  char a[8];
+  a[0] = s[0];
+  a[1] = s[1];
+  a[2] = s[2];
+  a[3] = s[3];
+
+  size_t n = 0;
+
+  n += strlen (a);
+  n += strlen (a + 1);
+  n += strlen (a + 2);
+  n += strlen (a + 3);
+  return n;
+}
+
+size_t warn_array_plus_cst_strlen (const char *s)
+{
+  char a[8];
+  a[0] = s[0];
+  a[1] = s[1];
+  a[2] = s[2];
+  a[3] = s[3];
+
+  return strlen (a + 4);      // { dg-warning "\\\[-Wuninitialized" }
+}
+
+size_t nowarn_array_plus_var_strlen (const char *s, int i)
+{
+  char a[8];
+  a[0] = s[0];
+  a[1] = s[1];
+  a[2] = s[2];
+  a[3] = s[3];
+
+  return strlen (a + i);
+}
+
+
+size_t nowarn_alloca_assign_strlen (int i)
+{
+  char *p = (char*)alloca (8);
+  p[i] = '\0';
+  return strlen (p);
+}
+
+size_t nowarn_alloca_escape_strlen (int i)
+{
+  char *p = (char*)alloca (8);
+  sink (p);
+  return strlen (p);
+}
+
+size_t warn_alloca_strlen (void)
+{
+  char *p = (char*)alloca (8);
+  return strlen (p);          // { dg-warning "\\\[-Wuninitialized" }
+}
+
+
+size_t nowarn_malloc_assign_strlen (int i)
+{
+  char *p = (char*)malloc (8);
+  p[i] = '\0';
+  return strlen (p);
+}
+
+size_t nowarn_malloc_escape_strlen (int i)
+{
+  char *p = (char*)malloc (8);
+  sink (p);
+  return strlen (p);
+}
+
+size_t warn_malloc_strlen (void)
+{
+  char *p = (char*)malloc (8);
+  return strlen (p);          // { dg-warning "\\\[-Wuninitialized" }
+}
+
+
+size_t nowarn_realloc_strlen (void *p)
+{
+  char *q = (char*)realloc (p, 8);
+  return strlen (q);
+}
+
+
+size_t nowarn_vla_assign_strlen (int n, int i)
+{
+  char vla[n];
+  vla[i] = '\0';
+  return strlen (vla);
+}
+
+size_t nowarn_vla_strcpy_strlen (int n, const char *s, int i)
+{
+  char vla[n];
+  strcpy (vla, s);
+  return strlen (vla + i);
+}
+
+size_t nowarn_vla_escape_strlen (int n, int i)
+{
+  char vla[n];
+  sink (vla);
+  return strlen (vla);
+}
+
+size_t warn_vla_strlen (unsigned n)
+{
+  char vla[n];
+  return strlen (vla);        // { dg-warning "\\\[-Wuninitialized" }
+}
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-37.c b/gcc/testsuite/gcc.dg/auto-init-uninit-37.c
new file mode 100644
index 000000000000..da3c9db1840a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-37.c
@@ -0,0 +1,154 @@
+/* PR middle-end/10138 - warn for uninitialized arrays passed as const arguments
+   Verify that -Wuninitialized and -Wmaybe-uninitialized trigger (or don't)
+   when passing uninitialized variables by reference to functions declared
+   with or without attribute access and with (or without) const qualified
+   arguments of array, VLA, or pointer types.
+   { dg-do compile }
+   { dg-options "-O2 -Wall -ftrack-macro-expansion=0 -ftrivial-auto-var-init=zero" } */
+
+#define NONE    /* none */
+#define RO(...) __attribute__ ((access (read_only, __VA_ARGS__)))
+#define RW(...) __attribute__ ((access (read_write, __VA_ARGS__)))
+#define WO(...) __attribute__ ((access (write_only, __VA_ARGS__)))
+#define X(...)  __attribute__ ((access (none, __VA_ARGS__)))
+
+#define CONCAT(x, y) x ## y
+#define CAT(x, y)    CONCAT (x, y)
+#define UNIQ(pfx)    CAT (pfx, __LINE__)
+
+extern void sink (void*);
+
+
+#define T1(attr, name, type)			\
+  void UNIQ (CAT (test_, name))(void) {		\
+    extern attr void UNIQ (name)(type);		\
+    int x;					\
+    UNIQ (name)(&x);				\
+    sink (&x);					\
+  }
+
+#define T2(attr, name, types)			\
+  void UNIQ (CAT (test_, name))(void) {		\
+    extern attr void UNIQ (name)(types);	\
+    int x;					\
+    UNIQ (name)(1, &x);				\
+    sink (&x);					\
+  }
+
+
+typedef int IA_[];
+typedef const int CIA_[];
+
+T1 (NONE,   fia_,   IA_);
+T1 (NONE,   fcia_,  CIA_);    // { dg-warning "\\\[-Wmaybe-uninitialized" }
+T1 (RO (1), froia_, IA_);     // { dg-warning "\\\[-Wuninitialized" }
+T1 (RW (1), frwia_, IA_);     // { dg-warning "\\\[-Wmaybe-uninitialized" }
+T1 (WO (1), fwoia_, IA_);
+T1 (X (1),  fxia_,  IA_);
+
+
+typedef int IA1[1];
+typedef const int CIA1[1];
+
+T1 (NONE,   fia1,   IA1);
+T1 (NONE,   fcia1,  CIA1);    // { dg-warning "\\\[-Wmaybe-uninitialized" }
+T1 (RO (1), froia1, IA1);     // { dg-warning "\\\[-Wuninitialized" }
+T1 (RW (1), frwia1, IA1);     // { dg-warning "\\\[-Wmaybe-uninitialized" }
+T1 (WO (1), fwoia1, IA1);
+T1 (X (1),  fxia1,  IA1);
+
+
+#define IARS1  int[restrict static 1]
+#define CIARS1 const int[restrict static 1]
+
+T1 (NONE,   fiars1,   IARS1);
+T1 (NONE,   fciars1,  CIARS1);// { dg-warning "\\\[-Wmaybe-uninitialized" }
+T1 (RO (1), froiars1, IARS1); // { dg-warning "\\\[-Wuninitialized" }
+T1 (RW (1), frwiars1, IARS1); // { dg-warning "\\\[-Wmaybe-uninitialized" }
+T1 (WO (1), fwoiars1, IARS1);
+T1 (X (1),  fxiars1,  IARS1);
+
+
+#define IAS1  int[static 1]
+#define CIAS1 const int[static 1]
+
+T1 (NONE,   fias1,   IAS1);
+T1 (NONE,   fcias1,  CIAS1);   // { dg-warning "\\\[-Wmaybe-uninitialized" }
+T1 (RO (1), froias1, IAS1);    // { dg-warning "\\\[-Wuninitialized" }
+T1 (RW (1), frwias1, IAS1);    // { dg-warning "\\\[-Wmaybe-uninitialized" }
+T1 (WO (1), fwoias1, IAS1);
+T1 (X (1),  fxias1,  IAS1);
+
+
+#define IAX  int[*]
+#define CIAX const int[*]
+
+T1 (NONE,   fiax,   IAX);
+T1 (NONE,   fciax,  CIAX);    // { dg-warning "\\\[-Wmaybe-uninitialized" }
+T1 (RO (1), froiax, IAX);     // { dg-warning "\\\[-Wuninitialized" }
+T1 (RW (1), frwiax, IAX);     // { dg-warning "\\\[-Wmaybe-uninitialized" }
+T1 (WO (1), fwoiax, IAX);
+T1 (X (1),  fxiax,  IAX);
+
+
+#define IAN  int n, int[n]
+#define CIAN int n, const int[n]
+
+T2 (NONE,      fian,   IAN);
+T2 (NONE,      fcian,  CIAN); // { dg-warning "\\\[-Wmaybe-uninitialized" }
+T2 (RO (2, 1), froian, IAN);  // { dg-warning "\\\[-Wuninitialized" }
+T2 (RW (2, 1), frwian, IAN);  // { dg-warning "\\\[-Wmaybe-uninitialized" }
+T2 (WO (2, 1), fwoian, IAN);
+T2 (X (2, 1),  fxian,  IAN);
+
+
+typedef int* IP;
+typedef const int* CIP;
+
+T1 (NONE,   fip,   IP);
+T1 (NONE,   fcip,  CIP);     // { dg-warning "\\\[-Wmaybe-uninitialized" }
+T1 (RO (1), froip, IP);      // { dg-warning "\\\[-Wuninitialized" }
+T1 (RW (1), frwip, IP);      // { dg-warning "\\\[-Wmaybe-uninitialized" }
+T1 (WO (1), fwoip, IP);
+T1 (X (1),  fxip,  IP);
+
+
+/* Verify that the notes printed after the warning mention attribute
+   access only when the attribute is explicitly used in the declaration
+   and not otherwise.  */
+
+void test_note_cst_restrict (void)
+{
+  extern void
+    fccar (const char[restrict]);   // { dg-message "by argument 1 of type 'const char\\\[restrict]' to 'fccar'" "note" }
+
+  char a[1];                  // { dg-message "'a' declared here" "note" }
+  fccar (a);                  // { dg-warning "'a' may be used uninitialized" }
+}
+
+void test_note_vla (int n)
+{
+  extern void
+    fccvla (const char[n]);   // { dg-message "by argument 1 of type 'const char\\\[n]' to 'fccvla'" "note" }
+
+  char a[2];                  // { dg-message "'a' declared here" "note" }
+  fccvla (a);                 // { dg-warning "'a' may be used uninitialized" }
+}
+
+void test_note_ro (void)
+{
+  extern RO (1) void
+    frocar (char[restrict]);  // { dg-message "in a call to 'frocar' declared with attribute 'access \\\(read_only, 1\\\)'" "note" }
+
+  char a[3];                  // { dg-message "'a' declared here" "note" }
+  frocar (a);                 // { dg-warning "'a' is used uninitialized" }
+}
+
+void test_note_rw (void)
+{
+  extern RW (1) void
+    frwcar (char[restrict]);  // { dg-message "in a call to 'frwcar' declared with attribute 'access \\\(read_write, 1\\\)'" "note" }
+
+  char a[4];                  // { dg-message "'a' declared here" "note" }
+  frwcar (a);                 // { dg-warning "'a' may be used uninitialized" }
+}
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-4.c b/gcc/testsuite/gcc.dg/auto-init-uninit-4.c
new file mode 100644
index 000000000000..482c837cacb2
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-4.c
@@ -0,0 +1,52 @@
+/* Spurious uninit variable warnings, case 4.
+   Simplified version of cppexp.c (cpp_parse_expr).
+
+   This one is really fragile, it gets it right if you take out case
+   1, or if the structure is replaced by an int, or if the structure
+   has fewer members (!) */
+
+/* { dg-do compile } */
+/* { dg-options "-O -Wuninitialized -ftrivial-auto-var-init=zero" } */
+
+extern void abort (void);
+
+struct operation {
+    short op;
+    char rprio;
+    char flags;
+    char unsignedp;
+    long value;
+};
+
+extern struct operation cpp_lex (void);
+
+void
+cpp_parse_expr (void)
+{
+  int rprio; /* { dg-bogus "rprio" "uninitialized variable warning PR19833" } */
+  struct operation op;
+
+  for (;;)
+    {
+      op = cpp_lex ();
+
+      switch (op.op)
+	{
+	case 0:
+	  break;
+	case 1:
+	  return;
+	case 2:
+	  rprio = 1;
+	  break;
+	default:
+	  return;
+	}
+
+      if (op.op == 0)
+	return;
+
+      if (rprio != 1)
+	abort();
+    }
+}
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-5.c b/gcc/testsuite/gcc.dg/auto-init-uninit-5.c
new file mode 100644
index 000000000000..ada81c912bdd
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-5.c
@@ -0,0 +1,39 @@
+/* Spurious uninitialized-variable warnings.  */
+/* Disable jump threading, etc to test compiler analysis.  */
+/* { dg-do compile } */
+/* { dg-options "-O -Wuninitialized -fno-tree-dce -fno-tree-vrp -fno-tree-dominator-opts -ftrivial-auto-var-init=zero" } */
+
+extern void use(int);
+extern void foo(void);
+
+void
+func1(int cond)
+{
+    int x;  /* { dg-bogus "x" "uninitialized variable warning" } */
+
+    if(cond)
+	x = 1;
+
+    foo();
+
+    if(cond)
+	use(x);
+}
+
+void
+func2 (int cond)
+{
+    int x;  /* { dg-bogus "x" "uninitialized variable warning" } */
+    int flag = 0;
+
+    if(cond)
+    {
+	x = 1;
+	flag = 1;
+    }
+
+    foo();
+
+    if(flag)
+	use(x);
+}
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-6.c b/gcc/testsuite/gcc.dg/auto-init-uninit-6.c
new file mode 100644
index 000000000000..e6cba4ef22c0
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-6.c
@@ -0,0 +1,47 @@
+/* Spurious uninitialized variable warnings.
+   This one inspired by java/class.c:build_utf8_ref.  */
+
+/* { dg-do compile } */
+/* { dg-options "-O -Wuninitialized -ftrivial-auto-var-init=zero" } */
+
+#include <stddef.h>
+
+struct tree
+{
+    struct tree *car;
+    struct tree *cdr;
+    int type, data;
+};
+
+extern void *malloc(size_t);
+
+#define INTEGER_T 1
+#define PTR_T	  2
+
+#define APPEND(TREE, LAST, TYPE, VALUE)				\
+do {								\
+     struct tree *tmp = malloc (sizeof (struct tree));		\
+     tmp->car = 0; tmp->cdr = 0; tmp->type = TYPE;		\
+     tmp->data = VALUE;						\
+     if (TREE->car)						\
+	 LAST->cdr = tmp;					\
+     else							\
+	 TREE->car = tmp;					\
+     LAST = tmp;						\
+} while(0)
+ 
+struct tree *
+make_something(int a, int b, int c)
+{
+    struct tree *rv;
+    struct tree *field;
+
+    rv = malloc (sizeof (struct tree));
+    rv->car = 0;
+
+    APPEND(rv, field, INTEGER_T, a);  /* { dg-bogus "field" "uninitialized variable warning" } */
+    APPEND(rv, field, PTR_T, b);
+    APPEND(rv, field, INTEGER_T, c);
+
+    return rv;
+}
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-8.c b/gcc/testsuite/gcc.dg/auto-init-uninit-8.c
new file mode 100644
index 000000000000..6c298870c679
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-8.c
@@ -0,0 +1,32 @@
+/* Uninitialized variable warning tests...
+   Inspired by part of optabs.c:expand_binop.
+   May be the same as uninit-1.c.  */
+
+/* { dg-do compile } */
+/* { dg-options "-O -Wuninitialized -ftrivial-auto-var-init=zero" } */
+
+#include <limits.h>
+
+void
+add_bignums (int *out, int *x, int *y)
+{
+    int p, sum;
+    int carry; /* { dg-bogus "carry" "uninitialized variable warning" } */
+
+    p = 0;
+    for (; *x; x++, y++, out++, p++)
+    {
+	if (p)
+	    sum = *x + *y + carry;
+	else
+	    sum = *x + *y;
+
+	if (sum < 0)
+	{
+	    carry = 1;
+	    sum -= INT_MAX;
+	}
+	else
+	    carry = 0;
+    }
+}
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-9.c b/gcc/testsuite/gcc.dg/auto-init-uninit-9.c
new file mode 100644
index 000000000000..9d65493bde2a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-9.c
@@ -0,0 +1,42 @@
+/* Spurious uninitialized variable warnings.  Slight variant on the
+   documented case, inspired by reg-stack.c:record_asm_reg_life.  */
+
+/* { dg-do compile } */
+/* { dg-options "-O -Wuninitialized -ftrivial-auto-var-init=zero" } */
+/* { dg-require-effective-target alloca } */
+
+struct foo
+{
+    int type;
+    struct foo *car;
+    struct foo *cdr;
+    char *data;
+    int data2;
+};
+
+extern void use(struct foo *);
+
+#define CLOBBER 6
+#define PARALLEL 3
+
+void
+func(struct foo *list, int count)
+{
+    int n_clobbers = 0;
+    int i;
+    struct foo **clob_list;   /* { dg-bogus "clob_list" "uninitialized variable warning" } */
+
+    if(list[0].type == PARALLEL)
+    {
+	clob_list = __builtin_alloca(count * sizeof(struct foo *));
+	
+	for(i = 1; i < count; i++)
+	{
+	    if(list[i].type == CLOBBER)
+		clob_list[n_clobbers++] = &list[i];
+	}
+    }
+
+    for(i = 0; i < n_clobbers; i++)
+	use(clob_list[i]);
+}
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-A.c b/gcc/testsuite/gcc.dg/auto-init-uninit-A.c
new file mode 100644
index 000000000000..01fcf59f4504
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-A.c
@@ -0,0 +1,117 @@
+/* Inspired by part of java/parse.y.
+   May be a real bug in CSE. */
+
+/* { dg-do compile } */
+/* { dg-options "-O2 -Wall -ftrivial-auto-var-init=zero" } */
+
+struct tree
+{
+    struct tree *car, *cdr, *wfl;
+    int code;
+    struct { unsigned int renp:1;
+      unsigned int rtnp:1;
+      unsigned int rpnp:1; } flags;
+};
+typedef struct tree *tree;
+#define NULL_TREE ((tree)0)
+
+/* Codes */
+enum
+{
+    CALL_EXPR, NEW_ARRAY_EXPR, NEW_CLASS_EXPR, CONVERT_EXPR,
+    ARRAY_REF, CONDITIONAL_EXPR, STRING_CST, EXPR_WITH_FILE_LOCATION
+};
+
+/* Flags */
+#define RESOLVE_EXPRESSION_NAME_P(t) ((t)->flags.renp)
+#define RESOLVE_TYPE_NAME_P(t) ((t)->flags.rtnp)
+#define RESOLVE_PACKAGE_NAME_P(t) ((t)->flags.rpnp)
+
+/* Macros */
+#define EXPR_WFL_QUALIFICATION(t) ((t)->wfl)
+#define QUAL_WFL(t) ((t)->wfl)
+#define EXPR_WFL_NODE(t) ((t)->wfl)
+#define TREE_CODE(t) ((t)->code)
+#define TREE_OPERAND(t,x) ((t)->car)
+#define CLASSTYPE_SUPER(t) ((t)->car)
+#define IDENTIFIER_LOCAL_VALUE(t) ((t)->car)
+#define TREE_CHAIN(t) ((t)->cdr)
+#define QUAL_RESOLUTION(t) ((t)->cdr)
+
+extern tree current_class, this_identifier_node;
+extern tree super_identifier_node, length_identifier_node;
+
+tree resolve_and_layout (tree, tree);
+tree lookup_field_wrapper (tree, tree);
+
+void
+qualify_ambiguous_name (id)
+     tree id;
+{
+  tree qual, qual_wfl, decl;
+  tree name;	 /* { dg-bogus "name" "uninitialized variable warning" } */
+  tree ptr_type; /* { dg-bogus "ptr_type" "uninitialized variable warning" } */
+  int again, new_array_found = 0;
+  int super_found = 0, this_found = 0;
+
+  qual = EXPR_WFL_QUALIFICATION (id);
+  do {
+    qual_wfl = QUAL_WFL (qual);
+    switch (TREE_CODE (qual_wfl))
+      {
+      case CALL_EXPR:
+	qual_wfl = TREE_OPERAND (qual_wfl, 0);
+	if (TREE_CODE (qual_wfl) != EXPR_WITH_FILE_LOCATION)
+	  {
+	    qual = EXPR_WFL_QUALIFICATION (qual_wfl);
+	    qual_wfl = QUAL_WFL (qual);
+	  }
+	break;
+      case NEW_ARRAY_EXPR:
+	qual = TREE_CHAIN (qual);
+	new_array_found = again = 1;
+	continue;
+      case NEW_CLASS_EXPR:
+      case CONVERT_EXPR:
+	qual_wfl = TREE_OPERAND (qual_wfl, 0);
+	break;
+      case ARRAY_REF:
+	while (TREE_CODE (qual_wfl) == ARRAY_REF)
+	  qual_wfl = TREE_OPERAND (qual_wfl, 0);
+	break;
+      default:
+	break;
+      }
+
+    name = EXPR_WFL_NODE (qual_wfl);
+    ptr_type = current_class;
+    again = 0;
+
+  } while (again);
+
+  /* If you put straightforward uses of name and ptr_type here
+     instead of the if-else sequence below, the warnings go away.
+     Therefore I suspect a real bug. */
+  
+  if (!this_found && !super_found && (decl = IDENTIFIER_LOCAL_VALUE (name)))
+    {
+      RESOLVE_EXPRESSION_NAME_P (qual_wfl) = 1;
+      QUAL_RESOLUTION (qual) = decl;
+    }
+  else if ((decl = lookup_field_wrapper (ptr_type, name))
+	   || (new_array_found && name == length_identifier_node))
+    {
+      RESOLVE_EXPRESSION_NAME_P (qual_wfl) = 1;
+      QUAL_RESOLUTION (qual) = (new_array_found ? NULL_TREE : decl);
+    }
+  else if ((decl = resolve_and_layout (name, NULL_TREE)))
+    {
+      RESOLVE_TYPE_NAME_P (qual_wfl) = 1;
+      QUAL_RESOLUTION (qual) = decl;
+    }
+  else if (TREE_CODE (QUAL_WFL (qual)) == CALL_EXPR
+	   || TREE_CODE (QUAL_WFL (qual)) == ARRAY_REF)
+    RESOLVE_EXPRESSION_NAME_P (qual_wfl) = 1;
+  else 
+    RESOLVE_PACKAGE_NAME_P (qual_wfl) = 1;
+}
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-B.c b/gcc/testsuite/gcc.dg/auto-init-uninit-B.c
new file mode 100644
index 000000000000..0b2837127209
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-B.c
@@ -0,0 +1,15 @@
+/* Origin: PR c/179 from Gray Watson <gray@256.com>, adapted as a testcase
+   by Joseph Myers <jsm28@cam.ac.uk>.  */
+/* { dg-do compile } */
+/* { dg-options "-O2 -Wuninitialized -ftrivial-auto-var-init=zero" } */
+extern void foo (int *);
+extern void bar (int);
+
+void
+baz (void)
+{
+  int i;
+  if (i) /* { dg-warning "is used uninitialized" "uninit i warning" } */
+    bar (i);
+  foo (&i);
+}
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-C.c b/gcc/testsuite/gcc.dg/auto-init-uninit-C.c
new file mode 100644
index 000000000000..a4aa629bf930
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-C.c
@@ -0,0 +1,21 @@
+/* Spurious uninitialized variable warning, inspired by libgcc2.c.  */
+/* { dg-do compile } */
+/* { dg-options "-O -Wuninitialized -ftrivial-auto-var-init=zero" } */
+
+/* Not all platforms support TImode integers.  */
+#if defined(__LP64__) && !defined(__hppa__)
+typedef int TItype __attribute__ ((mode (TI)));
+#else
+typedef long TItype;
+#endif
+
+
+TItype
+__subvdi3 (TItype a, TItype b)
+{
+  TItype w;
+  
+  w = a - b;
+  
+  return w;
+}
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-H.c b/gcc/testsuite/gcc.dg/auto-init-uninit-H.c
new file mode 100644
index 000000000000..71e2e2d68d7f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-H.c
@@ -0,0 +1,33 @@
+/* PR 14204 */
+/* { dg-do compile } */
+/* { dg-options "-O -Wall -Werror -ftrivial-auto-var-init=zero" } */
+
+#if defined __alpha__
+# define ASM __asm__("$30")
+#elif defined __i386__
+# define ASM __asm__("esp")
+#elif defined (__powerpc__) || defined (__PPC__) || defined (__ppc__) || defined (_POWER)
+# define ASM __asm__("r1")
+#elif defined __s390__
+# define ASM __asm__("r15")
+#elif defined __mips
+# define ASM __asm__("$sp")
+#elif defined __sparc__
+# define ASM __asm__("sp")
+#elif defined __ia64__
+# define ASM __asm__("r12")
+#elif defined __hppa__
+# define ASM __asm__("%r30")
+#elif defined __xtensa__
+# define ASM __asm__("sp")
+#else
+/* The register name should be target-dependent so for other targets,
+   we just silence the test.  */
+# define ASM = 0
+#endif
+
+void *load_PCB (void)
+{
+  register void *sp ASM;
+  return sp;			/* { dg-bogus "uninitialized" } */
+}
diff --git a/gcc/testsuite/gcc.dg/auto-init-uninit-I.c b/gcc/testsuite/gcc.dg/auto-init-uninit-I.c
new file mode 100644
index 000000000000..09680fe9790d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/auto-init-uninit-I.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -Wuninitialized -ftrivial-auto-var-init=zero" } */
+
+int sys_msgctl (void)
+{
+  struct { int mode; } setbuf;
+  return setbuf.mode;  /* { dg-warning "'setbuf\.mode' is used" } */
+}
diff --git a/gcc/testsuite/gcc.target/aarch64/auto-init-1.c b/gcc/testsuite/gcc.target/aarch64/auto-init-1.c
new file mode 100644
index 000000000000..0fa470880bf5
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/auto-init-1.c
@@ -0,0 +1,32 @@
+/* Verify zero initialization for integer and pointer type automatic variables.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=zero -fdump-rtl-expand" } */
+
+#ifndef __cplusplus
+# define bool _Bool
+#endif
+
+enum E {
+  N1 = 0,
+  N2,
+  N3
+};
+
+extern void bar (char, short, int, enum E, long, long long, int *, bool);
+
+void foo()
+{
+  char temp1;
+  short temp2;
+  int temp3;
+  enum E temp4;
+  long temp5;
+  long long temp6;
+  int *temp7;
+  bool temp8;
+
+  bar (temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8);
+  return;
+}
+
+/* { dg-final { scan-rtl-dump-times "const_int 0" 11 "expand" } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/auto-init-10.c b/gcc/testsuite/gcc.target/aarch64/auto-init-10.c
new file mode 100644
index 000000000000..aceceb87fbe1
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/auto-init-10.c
@@ -0,0 +1,18 @@
+/* Verify pattern initialization for structure type automatic variables with
+   padding.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern" } */
+
+struct test_aligned {
+        int internal1;
+        long long internal2;
+} __attribute__ ((aligned(64)));
+
+int foo ()
+{
+  struct test_aligned var;
+  return var.internal1;
+}
+
+/* { dg-final { scan-assembler-times "stp\tq0, q0," 2 } } */
+
diff --git a/gcc/testsuite/gcc.target/aarch64/auto-init-11.c b/gcc/testsuite/gcc.target/aarch64/auto-init-11.c
new file mode 100644
index 000000000000..085c38629210
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/auto-init-11.c
@@ -0,0 +1,27 @@
+/* Verify zero initialization for nested structure type automatic variables with
+   padding.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=zero" } */
+
+struct test_aligned {
+        unsigned internal1;
+        unsigned long long internal2;
+} __attribute__ ((aligned(64)));
+
+struct test_big_hole {
+        char one;
+        char two;
+        char three;
+        /* 61 byte padding hole here. */
+        struct test_aligned four;
+} __attribute__ ((aligned(64)));
+
+
+int foo ()
+{
+  struct test_big_hole var;
+  return var.four.internal1;
+}
+
+/* { dg-final { scan-assembler-times "stp\tq0, q0," 4 } } */
+
diff --git a/gcc/testsuite/gcc.target/aarch64/auto-init-12.c b/gcc/testsuite/gcc.target/aarch64/auto-init-12.c
new file mode 100644
index 000000000000..5d1383b0b5c8
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/auto-init-12.c
@@ -0,0 +1,27 @@
+/* Verify pattern initialization for nested structure type automatic variables with
+   padding.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern" } */
+
+struct test_aligned {
+        unsigned internal1;
+        unsigned long long internal2;
+} __attribute__ ((aligned(64)));
+
+struct test_big_hole {
+        char one;
+        char two;
+        char three;
+        /* 61 byte padding hole here. */
+        struct test_aligned four;
+} __attribute__ ((aligned(64)));
+
+
+int foo ()
+{
+  struct test_big_hole var;
+  return var.four.internal1;
+}
+
+/* { dg-final { scan-assembler-times "stp\tq0, q0," 4 } } */
+
diff --git a/gcc/testsuite/gcc.target/aarch64/auto-init-13.c b/gcc/testsuite/gcc.target/aarch64/auto-init-13.c
new file mode 100644
index 000000000000..3c45a6c6288d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/auto-init-13.c
@@ -0,0 +1,22 @@
+/* Verify zero initialization for structure type automatic variables with
+   tail padding.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=zero" } */
+
+struct test_trailing_hole {
+        char *one;
+        char *two;
+        char *three;
+        char four;
+        /* "sizeof(unsigned long) - 1" byte padding hole here. */
+};
+
+int foo ()
+{
+  struct test_trailing_hole var;
+  return var.four;
+}
+
+/* { dg-final { scan-assembler-times "stp\txzr, xzr," 2 } } */
+
+
diff --git a/gcc/testsuite/gcc.target/aarch64/auto-init-14.c b/gcc/testsuite/gcc.target/aarch64/auto-init-14.c
new file mode 100644
index 000000000000..500020e7815b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/auto-init-14.c
@@ -0,0 +1,20 @@
+/* Verify pattern initialization for structure type automatic variables with
+   tail padding.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern" } */
+
+struct test_trailing_hole {
+        char *one;
+        char *two;
+        char *three;
+        char four;
+        /* "sizeof(unsigned long) - 1" byte padding hole here. */
+};
+
+int foo ()
+{
+  struct test_trailing_hole var;
+  return var.four;
+}
+
+/* { dg-final { scan-assembler-times "stp\txzr, xzr," 2 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/auto-init-15.c b/gcc/testsuite/gcc.target/aarch64/auto-init-15.c
new file mode 100644
index 000000000000..cb96c3a1e4b2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/auto-init-15.c
@@ -0,0 +1,20 @@
+/* Verify zero initialization for structure type automatic variables with
+   padding and has explicit initialization.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=zero" } */
+
+struct test_trailing_hole {
+        int one;
+        int two;
+        int three;
+        char four;
+        /* "sizeof(unsigned long) - 1" byte padding hole here. */
+};
+
+int foo ()
+{
+  struct test_trailing_hole var = {.one = 1,.two = 2, .four = 'c'};
+  return var.four;
+}
+
+/* { dg-final { scan-assembler "stp\txzr, xzr," } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/auto-init-16.c b/gcc/testsuite/gcc.target/aarch64/auto-init-16.c
new file mode 100644
index 000000000000..ce7c7cd31c1f
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/auto-init-16.c
@@ -0,0 +1,22 @@
+/* Verify pattern initialization for structure type automatic variables with
+   padding and has explicit initialization.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern" } */
+
+struct test_trailing_hole {
+        int one;
+        int two;
+        int three;
+        char four;
+        /* "sizeof(unsigned long) - 1" byte padding hole here. */
+};
+
+int foo ()
+{
+  struct test_trailing_hole var = {.one = 1,.two = 2, .four = 'c'};
+  return var.four;
+}
+
+/* { dg-final { scan-assembler "stp\txzr, xzr," } } */
+
+
diff --git a/gcc/testsuite/gcc.target/aarch64/auto-init-17.c b/gcc/testsuite/gcc.target/aarch64/auto-init-17.c
new file mode 100644
index 000000000000..c81e5ff28b0b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/auto-init-17.c
@@ -0,0 +1,21 @@
+/* Verify zero initialization for array type with structure element with
+   padding.  */ 
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=zero" } */
+
+struct test_trailing_hole {
+        int one;
+        int two;
+        int three;
+        char four;
+        /* "sizeof(unsigned long) - 1" byte padding hole here. */
+};
+
+
+int foo ()
+{
+  struct test_trailing_hole var[10]; 
+  return var[2].four;
+}
+
+/* { dg-final { scan-assembler-times "stp\tq0, q0," 5 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/auto-init-18.c b/gcc/testsuite/gcc.target/aarch64/auto-init-18.c
new file mode 100644
index 000000000000..0ec0ac4cc11c
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/auto-init-18.c
@@ -0,0 +1,21 @@
+/* Verify pattern initialization for array type with structure element with
+   padding.  */ 
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern" } */
+
+struct test_trailing_hole {
+        int one;
+        int two;
+        int three;
+        char four;
+        /* "sizeof(unsigned long) - 1" byte padding hole here. */
+};
+
+
+int foo ()
+{
+  struct test_trailing_hole var[10]; 
+  return var[2].four;
+}
+
+/* { dg-final { scan-assembler-times "str\tw0, " 30 } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/auto-init-19.c b/gcc/testsuite/gcc.target/aarch64/auto-init-19.c
new file mode 100644
index 000000000000..02f7edc51008
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/auto-init-19.c
@@ -0,0 +1,27 @@
+/* Verify zero initialization for union type with structure field with
+   padding.  */ 
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=zero" } */
+
+struct test_trailing_hole {
+        int one;
+        int two;
+        int three;
+        char four;
+        /* "sizeof(unsigned long) - 1" byte padding hole here. */
+};
+
+union test_union_padding {
+  struct test_trailing_hole u1;
+  long long u2;
+};
+
+
+int foo ()
+{
+  union test_union_padding var;
+  return var.u1.four;
+}
+
+/* { dg-final { scan-assembler "stp\txzr, xzr," } } */
+
diff --git a/gcc/testsuite/gcc.target/aarch64/auto-init-2.c b/gcc/testsuite/gcc.target/aarch64/auto-init-2.c
new file mode 100644
index 000000000000..2cbe34ec0008
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/auto-init-2.c
@@ -0,0 +1,37 @@
+/* Verify pattern initialization for integer and pointer type automatic variables.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern -fdump-rtl-expand" } */
+
+#ifndef __cplusplus
+# define bool _Bool
+#endif
+
+enum E {
+  N1 = 0,
+  N2,
+  N3
+};
+
+extern void bar (char, short, int, enum E, long, long long, int *, bool);
+
+void foo()
+{
+  char temp1;
+  short temp2;
+  int temp3;
+  enum E temp4;
+  long temp5;
+  long long temp6;
+  int *temp7;
+  bool temp8;
+
+  bar (temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8);
+  return;
+}
+
+/* { dg-final { scan-rtl-dump-times "0xffffffffffffffaa" 1 "expand" } } */
+/* { dg-final { scan-rtl-dump-times "0xffffffffffffaaaa" 1 "expand" } } */
+/* { dg-final { scan-rtl-dump-times "0xffffffffaaaaaaaa" 2 "expand" } } */
+/* { dg-final { scan-rtl-dump-times "0xaaaaaaaaaaaaaaaa" 3 "expand" } } */
+/* { dg-final { scan-rtl-dump-times "const_int 0" 4 "expand" } } */
+
diff --git a/gcc/testsuite/gcc.target/aarch64/auto-init-20.c b/gcc/testsuite/gcc.target/aarch64/auto-init-20.c
new file mode 100644
index 000000000000..0ef9acd681bf
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/auto-init-20.c
@@ -0,0 +1,27 @@
+/* Verify pattern initialization for union type with structure field with
+   padding.  */ 
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern" } */
+
+struct test_trailing_hole {
+        int one;
+        int two;
+        int three;
+        char four;
+        /* "sizeof(unsigned long) - 1" byte padding hole here. */
+};
+
+union test_union_padding {
+  struct test_trailing_hole u1;
+  long long u2;
+};
+
+
+int foo ()
+{
+  union test_union_padding var;
+  return var.u1.four;
+}
+
+/* { dg-final { scan-assembler "stp\txzr, xzr," } } */
+
diff --git a/gcc/testsuite/gcc.target/aarch64/auto-init-3.c b/gcc/testsuite/gcc.target/aarch64/auto-init-3.c
new file mode 100644
index 000000000000..78291a1033b7
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/auto-init-3.c
@@ -0,0 +1,19 @@
+/* Verify zero initialization for floating point type automatic variables.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=zero -fdump-rtl-expand" } */
+
+long double result;
+
+long double foo()
+{
+  float temp1;
+  double temp2;
+  long double temp3;
+  
+  result = temp1 + temp2 + temp3;
+  return result;
+}
+
+/* { dg-final { scan-rtl-dump "const_double:SF 0.0" "expand" } } */
+/* { dg-final { scan-rtl-dump "const_double:DF 0.0" "expand" } } */
+/* { dg-final { scan-rtl-dump "const_double:TF 0.0" "expand" } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/auto-init-4.c b/gcc/testsuite/gcc.target/aarch64/auto-init-4.c
new file mode 100644
index 000000000000..53b820385dfb
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/auto-init-4.c
@@ -0,0 +1,19 @@
+/* Verify pattern initialization for floating point type automatic variables.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern -fdump-rtl-expand" } */
+
+long double result;
+
+long double foo()
+{
+  float temp1;
+  double temp2;
+  long double temp3;
+  
+  result = temp1 + temp2 + temp3;
+  return result;
+}
+
+/* { dg-final { scan-rtl-dump "const_double:SF \\+QNaN" "expand" } } */
+/* { dg-final { scan-rtl-dump "const_double:DF \\+QNaN" "expand" } } */
+/* { dg-final { scan-rtl-dump "const_double:TF \\+QNaN" "expand" } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/auto-init-5.c b/gcc/testsuite/gcc.target/aarch64/auto-init-5.c
new file mode 100644
index 000000000000..092f83e16aed
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/auto-init-5.c
@@ -0,0 +1,19 @@
+/* Verify zero initialization for complex type automatic variables.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=zero" } */
+
+
+_Complex long double result;
+
+_Complex long double foo()
+{
+  _Complex float temp1;
+  _Complex double temp2;
+  _Complex long double temp3;
+
+  result = temp1 + temp2 + temp3;
+  return result;
+}
+
+/* { dg-final { scan-assembler-times ".word\\t0" 14 } } */
+
diff --git a/gcc/testsuite/gcc.target/aarch64/auto-init-6.c b/gcc/testsuite/gcc.target/aarch64/auto-init-6.c
new file mode 100644
index 000000000000..8cea59879803
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/auto-init-6.c
@@ -0,0 +1,21 @@
+/* Verify pattern initialization for complex type automatic variables.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern" } */
+
+
+_Complex long double result;
+
+_Complex long double foo()
+{
+  _Complex float temp1;
+  _Complex double temp2;
+  _Complex long double temp3;
+
+  result = temp1 + temp2 + temp3;
+  return result;
+}
+
+/* { dg-final { scan-assembler-times ".word\\t2143289344" 2 } } */
+/* { dg-final { scan-assembler-times ".word\\t2146959360" 2 } } */
+/* { dg-final { scan-assembler-times ".word\\t2147450880" 2 } } */
+
diff --git a/gcc/testsuite/gcc.target/aarch64/auto-init-7.c b/gcc/testsuite/gcc.target/aarch64/auto-init-7.c
new file mode 100644
index 000000000000..ac27fbe92f4a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/auto-init-7.c
@@ -0,0 +1,32 @@
+/* Verify zero initialization for array, union, and structure type automatic variables.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=zero -fdump-rtl-expand" } */
+
+struct S
+{
+  int f1;
+  float f2;
+  char f3[20];
+};
+
+union U
+{
+  char u1[5];
+  int u2;
+  float u3; 
+};
+
+double result;
+
+double foo()
+{
+  int temp1[3];
+  double temp2[3];
+  struct S temp3;
+  union U temp4;
+  
+  result = temp1[2] + temp2[1] + temp3.f2 + temp4.u3;
+  return result;
+}
+
+/* { dg-final { scan-rtl-dump-times "const_int 0" 8 "expand" } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/auto-init-8.c b/gcc/testsuite/gcc.target/aarch64/auto-init-8.c
new file mode 100644
index 000000000000..2f1de120ea84
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/auto-init-8.c
@@ -0,0 +1,33 @@
+/* Verify pattern initialization for array, union, and structure type automatic variables.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern -fdump-rtl-expand" } */
+
+struct S
+{
+  int f1;
+  float f2;
+  char f3[20];
+};
+
+union U
+{
+  char u1[5];
+  int u2;
+  float u3; 
+};
+
+double result;
+
+double foo()
+{
+  int temp1[3];
+  double temp2[3];
+  struct S temp3;
+  union U temp4;
+  
+  result = temp1[2] + temp2[1] + temp3.f2 + temp4.u3;
+  return result;
+}
+
+/* { dg-final { scan-rtl-dump-times "0xffffffffaaaaaaaa" 4 "expand" } } */
+/* { dg-final { scan-rtl-dump-times "0xffffffffffffffaa" 25 "expand" } } */
diff --git a/gcc/testsuite/gcc.target/aarch64/auto-init-9.c b/gcc/testsuite/gcc.target/aarch64/auto-init-9.c
new file mode 100644
index 000000000000..7294de57cf2a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/aarch64/auto-init-9.c
@@ -0,0 +1,19 @@
+/* Verify zero initialization for structure type automatic variables with
+   padding.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=zero" } */
+
+struct test_aligned {
+        int internal1;
+        long long internal2;
+} __attribute__ ((aligned(64)));
+
+int foo ()
+{
+  struct test_aligned var;
+  return var.internal1;
+}
+
+/* { dg-final { scan-assembler-times "stp\tq0, q0," 2 } } */
+
+
diff --git a/gcc/testsuite/gcc.target/i386/auto-init-1.c b/gcc/testsuite/gcc.target/i386/auto-init-1.c
new file mode 100644
index 000000000000..b7690df24060
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/auto-init-1.c
@@ -0,0 +1,32 @@
+/* Verify zero initialization for integer and pointer type automatic variables.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=zero -fdump-rtl-expand" } */
+
+#ifndef __cplusplus
+# define bool _Bool
+#endif
+
+enum E {
+  N1 = 0,
+  N2,
+  N3
+};
+
+extern void bar (char, short, int, enum E, long, long long, int *, bool);
+
+void foo()
+{
+  char temp1;
+  short temp2;
+  int temp3;
+  enum E temp4;
+  long temp5;
+  long long temp6;
+  int *temp7;
+  bool temp8;
+
+  bar (temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8);
+  return;
+}
+
+/* { dg-final { scan-rtl-dump-times "const_int 0" 10 "expand" } } */
diff --git a/gcc/testsuite/gcc.target/i386/auto-init-10.c b/gcc/testsuite/gcc.target/i386/auto-init-10.c
new file mode 100644
index 000000000000..88f95b7d096b
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/auto-init-10.c
@@ -0,0 +1,19 @@
+/* Verify pattern initialization for structure type automatic variables with
+   padding.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern" } */
+
+struct test_aligned {
+        int internal1;
+        long long internal2;
+} __attribute__ ((aligned(64)));
+
+int foo ()
+{
+  struct test_aligned var;
+  return var.internal1;
+}
+
+/* { dg-final { scan-assembler-times "movq\t\\\$0," 8 } } */
+
+
diff --git a/gcc/testsuite/gcc.target/i386/auto-init-11.c b/gcc/testsuite/gcc.target/i386/auto-init-11.c
new file mode 100644
index 000000000000..8a6d764b9fa4
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/auto-init-11.c
@@ -0,0 +1,30 @@
+/* Verify zero initialization for nested structure type automatic variables with
+   padding.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=zero" } */
+
+struct test_aligned {
+        unsigned internal1;
+        unsigned long long internal2;
+} __attribute__ ((aligned(64)));
+
+struct test_big_hole {
+        char one;
+        char two;
+        char three;
+        /* 61 byte padding hole here. */
+        struct test_aligned four;
+} __attribute__ ((aligned(64)));
+
+
+int foo ()
+{
+  struct test_big_hole var;
+  return var.four.internal1;
+}
+
+/* { dg-final { scan-assembler "movl\t\\\$0," } } */
+/* { dg-final { scan-assembler "movl\t\\\$16," } } */
+/* { dg-final { scan-assembler "rep stosq" } } */
+
+
diff --git a/gcc/testsuite/gcc.target/i386/auto-init-12.c b/gcc/testsuite/gcc.target/i386/auto-init-12.c
new file mode 100644
index 000000000000..b5a7bd440a93
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/auto-init-12.c
@@ -0,0 +1,30 @@
+/* Verify pattern initialization for nested structure type automatic variables with
+   padding.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern" } */
+
+struct test_aligned {
+        unsigned internal1;
+        unsigned long long internal2;
+} __attribute__ ((aligned(64)));
+
+struct test_big_hole {
+        char one;
+        char two;
+        char three;
+        /* 61 byte padding hole here. */
+        struct test_aligned four;
+} __attribute__ ((aligned(64)));
+
+
+int foo ()
+{
+  struct test_big_hole var;
+  return var.four.internal1;
+}
+
+/* { dg-final { scan-assembler "movl\t\\\$0," } } */
+/* { dg-final { scan-assembler "movl\t\\\$16," } } */
+/* { dg-final { scan-assembler "rep stosq" } } */
+
+
diff --git a/gcc/testsuite/gcc.target/i386/auto-init-13.c b/gcc/testsuite/gcc.target/i386/auto-init-13.c
new file mode 100644
index 000000000000..e18bc3073e18
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/auto-init-13.c
@@ -0,0 +1,22 @@
+/* Verify zero initialization for structure type automatic variables with
+   tail padding.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=zero" } */
+
+struct test_trailing_hole {
+        char *one;
+        char *two;
+        char *three;
+        char four;
+        /* "sizeof(unsigned long) - 1" byte padding hole here. */
+};
+
+int foo ()
+{
+  struct test_trailing_hole var;
+  return var.four;
+}
+
+/* { dg-final { scan-assembler-times "movq\t\\\$0," 4 } } */
+
+
diff --git a/gcc/testsuite/gcc.target/i386/auto-init-14.c b/gcc/testsuite/gcc.target/i386/auto-init-14.c
new file mode 100644
index 000000000000..55a4c9da54b2
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/auto-init-14.c
@@ -0,0 +1,22 @@
+/* Verify pattern initialization for structure type automatic variables with
+   tail padding.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern" } */
+
+struct test_trailing_hole {
+        char *one;
+        char *two;
+        char *three;
+        char four;
+        /* "sizeof(unsigned long) - 1" byte padding hole here. */
+};
+
+int foo ()
+{
+  struct test_trailing_hole var;
+  return var.four;
+}
+
+/* { dg-final { scan-assembler-times "movq\t\\\$0," 4 } } */
+
+
diff --git a/gcc/testsuite/gcc.target/i386/auto-init-15.c b/gcc/testsuite/gcc.target/i386/auto-init-15.c
new file mode 100644
index 000000000000..b5abffb0fc66
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/auto-init-15.c
@@ -0,0 +1,22 @@
+/* Verify zero initialization for structure type automatic variables with
+   padding and has explicit initialization.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=zero" } */
+
+struct test_trailing_hole {
+        int one;
+        int two;
+        int three;
+        char four;
+        /* "sizeof(unsigned long) - 1" byte padding hole here. */
+};
+
+int foo ()
+{
+  struct test_trailing_hole var = {.one = 1,.two = 2, .four = 'c'};
+  return var.four;
+}
+
+/* { dg-final { scan-assembler-times "movq\t\\\$0," 2 } } */
+
+
diff --git a/gcc/testsuite/gcc.target/i386/auto-init-16.c b/gcc/testsuite/gcc.target/i386/auto-init-16.c
new file mode 100644
index 000000000000..66591cff4488
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/auto-init-16.c
@@ -0,0 +1,22 @@
+/* Verify pattern initialization for structure type automatic variables with
+   padding and has explicit initialization.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern" } */
+
+struct test_trailing_hole {
+        int one;
+        int two;
+        int three;
+        char four;
+        /* "sizeof(unsigned long) - 1" byte padding hole here. */
+};
+
+int foo ()
+{
+  struct test_trailing_hole var = {.one = 1,.two = 2, .four = 'c'};
+  return var.four;
+}
+
+/* { dg-final { scan-assembler-times "movq\t\\\$0," 2 } } */
+
+
diff --git a/gcc/testsuite/gcc.target/i386/auto-init-17.c b/gcc/testsuite/gcc.target/i386/auto-init-17.c
new file mode 100644
index 000000000000..40fccadf920d
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/auto-init-17.c
@@ -0,0 +1,23 @@
+/* Verify zero initialization for array type with structure element with
+   padding.  */ 
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=zero" } */
+
+struct test_trailing_hole {
+        int one;
+        int two;
+        int three;
+        char four;
+        /* "sizeof(unsigned long) - 1" byte padding hole here. */
+};
+
+
+int foo ()
+{
+  struct test_trailing_hole var[10]; 
+  return var[2].four;
+}
+
+/* { dg-final { scan-assembler "movl\t\\\$0," } } */
+/* { dg-final { scan-assembler "movl\t\\\$20," } } */
+/* { dg-final { scan-assembler "rep stosq" } } */
diff --git a/gcc/testsuite/gcc.target/i386/auto-init-18.c b/gcc/testsuite/gcc.target/i386/auto-init-18.c
new file mode 100644
index 000000000000..a422a8d16b40
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/auto-init-18.c
@@ -0,0 +1,21 @@
+/* Verify pattern initialization for array type with structure element with
+   padding.  */ 
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern" } */
+
+struct test_trailing_hole {
+        int one;
+        int two;
+        int three;
+        char four;
+        /* "sizeof(unsigned long) - 1" byte padding hole here. */
+};
+
+
+int foo ()
+{
+  struct test_trailing_hole var[10]; 
+  return var[2].four;
+}
+
+/* { dg-final { scan-assembler-times "movq\t\\\$0," 20 } } */
diff --git a/gcc/testsuite/gcc.target/i386/auto-init-19.c b/gcc/testsuite/gcc.target/i386/auto-init-19.c
new file mode 100644
index 000000000000..31a3ee1fe971
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/auto-init-19.c
@@ -0,0 +1,26 @@
+/* Verify zero initialization for union type with structure field with
+   padding.  */ 
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=zero" } */
+
+struct test_trailing_hole {
+        int one;
+        int two;
+        int three;
+        char four;
+        /* "sizeof(unsigned long) - 1" byte padding hole here. */
+};
+
+union test_union_padding {
+  struct test_trailing_hole u1;
+  long long u2;
+};
+
+
+int foo ()
+{
+  union test_union_padding var;
+  return var.u1.four;
+}
+
+/* { dg-final { scan-assembler-times "movq\t\\\$0," 2 } } */
diff --git a/gcc/testsuite/gcc.target/i386/auto-init-2.c b/gcc/testsuite/gcc.target/i386/auto-init-2.c
new file mode 100644
index 000000000000..c7e006eb97ff
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/auto-init-2.c
@@ -0,0 +1,37 @@
+/* Verify pattern initialization for integer and pointer type automatic variables.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern -fdump-rtl-expand" } */
+
+#ifndef __cplusplus
+# define bool _Bool
+#endif
+
+enum E {
+  N1 = 0,
+  N2,
+  N3
+};
+
+extern void bar (char, short, int, enum E, long, long long, int *, bool);
+
+void foo()
+{
+  char temp1;
+  short temp2;
+  int temp3;
+  enum E temp4;
+  long temp5;
+  long long temp6;
+  int *temp7;
+  bool temp8;
+
+  bar (temp1, temp2, temp3, temp4, temp5, temp6, temp7, temp8);
+  return;
+}
+
+/* { dg-final { scan-rtl-dump-times "0xffffffffffffffaa" 1 "expand" } } */
+/* { dg-final { scan-rtl-dump-times "0xffffffffffffaaaa" 1 "expand" } } */
+/* { dg-final { scan-rtl-dump-times "0xffffffffaaaaaaaa" 2 "expand" } } */
+/* { dg-final { scan-rtl-dump-times "0xaaaaaaaaaaaaaaaa" 3 "expand" } } */
+/* { dg-final { scan-rtl-dump-times "const_int 0" 3 "expand" } } */
+
diff --git a/gcc/testsuite/gcc.target/i386/auto-init-20.c b/gcc/testsuite/gcc.target/i386/auto-init-20.c
new file mode 100644
index 000000000000..e675e8f2cece
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/auto-init-20.c
@@ -0,0 +1,26 @@
+/* Verify pattern initialization for union type with structure field with
+   padding.  */ 
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern" } */
+
+struct test_trailing_hole {
+        int one;
+        int two;
+        int three;
+        char four;
+        /* "sizeof(unsigned long) - 1" byte padding hole here. */
+};
+
+union test_union_padding {
+  struct test_trailing_hole u1;
+  long long u2;
+};
+
+
+int foo ()
+{
+  union test_union_padding var;
+  return var.u1.four;
+}
+
+/* { dg-final { scan-assembler-times "movq\t\\\$0," 2 } } */
diff --git a/gcc/testsuite/gcc.target/i386/auto-init-3.c b/gcc/testsuite/gcc.target/i386/auto-init-3.c
new file mode 100644
index 000000000000..0771f4f84188
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/auto-init-3.c
@@ -0,0 +1,20 @@
+/* Verify zero initialization for floating point type automatic variables.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=zero" } */
+
+long double result;
+
+long double foo()
+{
+  float temp1;
+  double temp2;
+  long double temp3;
+
+  result = temp1 + temp2 + temp3;
+  return result;
+}
+
+/* { dg-final { scan-assembler "pxor\[ \t\]+%xmm0, %xmm0" } } */
+/* { dg-final { scan-assembler "movss\[ \t\]+%xmm0" } } */
+/* { dg-final { scan-assembler "movsd\[ \t\]+%xmm0" } } */
+
diff --git a/gcc/testsuite/gcc.target/i386/auto-init-4.c b/gcc/testsuite/gcc.target/i386/auto-init-4.c
new file mode 100644
index 000000000000..4001e2c78e08
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/auto-init-4.c
@@ -0,0 +1,23 @@
+/* Verify pattern initialization for floating point type automatic variables.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern" } */
+
+long double result;
+
+long double foo()
+{
+  float temp1;
+  double temp2;
+  long double temp3;
+
+  result = temp1 + temp2 + temp3;
+  return result;
+}
+
+/* { dg-final { scan-assembler "movss\[ \t\]+.LC0\\(%rip\\), %xmm0" } } */
+/* { dg-final { scan-assembler "movss\[ \t\]+%xmm0" } } */
+/* { dg-final { scan-assembler "movsd\[ \t\]+.LC1\\(%rip\\), %xmm0" } } */
+/* { dg-final { scan-assembler "movsd\[ \t\]+%xmm0" } } */
+/* { dg-final { scan-assembler ".long\[ \t\]+2143289344" } } */
+/* { dg-final { scan-assembler ".long\[ \t\]+2146959360" } } */
+
diff --git a/gcc/testsuite/gcc.target/i386/auto-init-5.c b/gcc/testsuite/gcc.target/i386/auto-init-5.c
new file mode 100644
index 000000000000..c24a6faf8836
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/auto-init-5.c
@@ -0,0 +1,19 @@
+/* Verify zero initialization for complex type automatic variables.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=zero -fdump-tree-gimple" } */
+
+
+_Complex long double result;
+
+_Complex long double foo()
+{
+  _Complex float temp1;
+  _Complex double temp2;
+  _Complex long double temp3;
+
+  result = temp1 + temp2 + temp3;
+  return result;
+}
+
+/* { dg-final { scan-assembler-times ".long\\t0" 14 } } */
+
diff --git a/gcc/testsuite/gcc.target/i386/auto-init-6.c b/gcc/testsuite/gcc.target/i386/auto-init-6.c
new file mode 100644
index 000000000000..3f17113e5c57
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/auto-init-6.c
@@ -0,0 +1,22 @@
+/* Verify pattern initialization for complex type automatic variables.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern" } */
+
+
+_Complex long double result;
+
+_Complex long double foo()
+{
+  _Complex float temp1;
+  _Complex double temp2;
+  _Complex long double temp3;
+
+  result = temp1 + temp2 + temp3;
+  return result;
+}
+
+/* { dg-final { scan-assembler-times ".long\\t2143289344" 3 } } */
+/* { dg-final { scan-assembler-times ".long\\t2146959360" 2 } } */
+/* { dg-final { scan-assembler-times ".long\\t-1073741824" 2 } } */
+/* { dg-final { scan-assembler-times ".long\\t32767" 2 } } */
+
diff --git a/gcc/testsuite/gcc.target/i386/auto-init-7.c b/gcc/testsuite/gcc.target/i386/auto-init-7.c
new file mode 100644
index 000000000000..ac27fbe92f4a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/auto-init-7.c
@@ -0,0 +1,32 @@
+/* Verify zero initialization for array, union, and structure type automatic variables.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=zero -fdump-rtl-expand" } */
+
+struct S
+{
+  int f1;
+  float f2;
+  char f3[20];
+};
+
+union U
+{
+  char u1[5];
+  int u2;
+  float u3; 
+};
+
+double result;
+
+double foo()
+{
+  int temp1[3];
+  double temp2[3];
+  struct S temp3;
+  union U temp4;
+  
+  result = temp1[2] + temp2[1] + temp3.f2 + temp4.u3;
+  return result;
+}
+
+/* { dg-final { scan-rtl-dump-times "const_int 0" 8 "expand" } } */
diff --git a/gcc/testsuite/gcc.target/i386/auto-init-8.c b/gcc/testsuite/gcc.target/i386/auto-init-8.c
new file mode 100644
index 000000000000..ef5ab315acfe
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/auto-init-8.c
@@ -0,0 +1,33 @@
+/* Verify pattern initialization for array, union, and structure type automatic variables.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=pattern -fdump-rtl-expand" } */
+
+struct S
+{
+  int f1;
+  float f2;
+  char f3[20];
+};
+
+union U
+{
+  char u1[5];
+  int u2;
+  float u3; 
+};
+
+double result;
+
+double foo()
+{
+  int temp1[3];
+  double temp2[3];
+  struct S temp3;
+  union U temp4;
+  
+  result = temp1[2] + temp2[1] + temp3.f2 + temp4.u3;
+  return result;
+}
+
+/* { dg-final { scan-rtl-dump-times "0xffffffffaaaaaaaa" 4 "expand" } } */
+/* { dg-final { scan-rtl-dump-times "0xffffffffffffffaa" 26 "expand" } } */
diff --git a/gcc/testsuite/gcc.target/i386/auto-init-9.c b/gcc/testsuite/gcc.target/i386/auto-init-9.c
new file mode 100644
index 000000000000..b4069797d939
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/auto-init-9.c
@@ -0,0 +1,19 @@
+/* Verify zero initialization for structure type automatic variables with
+   padding.  */
+/* { dg-do compile } */
+/* { dg-options "-ftrivial-auto-var-init=zero" } */
+
+struct test_aligned {
+        int internal1;
+        long long internal2;
+} __attribute__ ((aligned(64)));
+
+int foo ()
+{
+  struct test_aligned var;
+  return var.internal1;
+}
+
+/* { dg-final { scan-assembler-times "movq\t\\\$0," 8 } } */
+
+
diff --git a/gcc/tree-cfg.c b/gcc/tree-cfg.c
index f59a0c052008..8ffcc6675893 100644
--- a/gcc/tree-cfg.c
+++ b/gcc/tree-cfg.c
@@ -3433,24 +3433,56 @@ verify_gimple_call (gcall *stmt)
 	}
     }
 
+  /* For a call to .DEFERRED_INIT, we should guarantee that the lhs is
+     the same as the first argument of the call.  */
+  if (gimple_call_internal_p (stmt, IFN_DEFERRED_INIT))
+    {
+      tree arg0 = gimple_call_arg (stmt, 0);
+      if (TREE_CODE (lhs) == SSA_NAME)
+	lhs = SSA_NAME_VAR (lhs);
+      if (TREE_CODE (arg0) == SSA_NAME)
+	arg0 = SSA_NAME_VAR (arg0);
+      if (lhs != arg0)
+	{
+	  error ("%<DEFFERED_INIT%> calls should have the same LHS as the "
+		 "first argument");
+	  return true;
+	}
+    }
+
+  /* We will not verify the arguments for the calls to .DEFERRED_INIT.
+     Such call is not a real call, just a placeholder for a later
+     initialization during expand phase.
+     This is mainly to avoid assertion failure for the following
+     case:
+
+     uni_var = .DEFERRED_INIT (uni_var, INIT_TYPE);
+     foo (&uni_var);
+
+     in the above, the uninitialized auto variable "uni_var" is
+     addressable, therefore should not be in registers, resulting
+     the assertion failure in the following argument verification.  */
+  if (gimple_call_internal_p (stmt, IFN_DEFERRED_INIT))
+    return false;
   /* ???  The C frontend passes unpromoted arguments in case it
      didn't see a function declaration before the call.  So for now
      leave the call arguments mostly unverified.  Once we gimplify
      unit-at-a-time we have a chance to fix this.  */
 
-  for (i = 0; i < gimple_call_num_args (stmt); ++i)
-    {
-      tree arg = gimple_call_arg (stmt, i);
-      if ((is_gimple_reg_type (TREE_TYPE (arg))
-	   && !is_gimple_val (arg))
-	  || (!is_gimple_reg_type (TREE_TYPE (arg))
-	      && !is_gimple_lvalue (arg)))
-	{
-	  error ("invalid argument to gimple call");
-	  debug_generic_expr (arg);
-	  return true;
-	}
-    }
+  else
+    for (i = 0; i < gimple_call_num_args (stmt); ++i)
+      {
+	tree arg = gimple_call_arg (stmt, i);
+	if ((is_gimple_reg_type (TREE_TYPE (arg))
+	     && !is_gimple_val (arg))
+	    || (!is_gimple_reg_type (TREE_TYPE (arg))
+		&& !is_gimple_lvalue (arg)))
+	  {
+	    error ("invalid argument to gimple call");
+	    debug_generic_expr (arg);
+	    return true;
+	  }
+      }
 
   return false;
 }
diff --git a/gcc/tree-core.h b/gcc/tree-core.h
index e457b917b98e..2e0e76ea8838 100644
--- a/gcc/tree-core.h
+++ b/gcc/tree-core.h
@@ -1829,7 +1829,7 @@ struct GTY(()) tree_decl_with_vis {
  unsigned final : 1;
  /* Belong to FUNCTION_DECL exclusively.  */
  unsigned regdecl_flag : 1;
- /* 14 unused bits. */
+ /* 14 unused bits.  */
  /* 32 more unused on 64 bit HW. */
 };
 
diff --git a/gcc/tree-sra.c b/gcc/tree-sra.c
index 98a6cacbe2ab..4c74df272141 100644
--- a/gcc/tree-sra.c
+++ b/gcc/tree-sra.c
@@ -384,6 +384,13 @@ static struct
 
   /* Numbber of components created when splitting aggregate parameters.  */
   int param_reductions_created;
+
+  /* Number of deferred_init calls that are modified.  */
+  int deferred_init;
+
+  /* Number of deferred_init calls that are created by
+     generate_subtree_deferred_init.  */
+  int subtree_deferred_init;
 } sra_stats;
 
 static void
@@ -4070,6 +4077,119 @@ get_repl_default_def_ssa_name (struct access *racc, tree reg_type)
   return get_or_create_ssa_default_def (cfun, racc->replacement_decl);
 }
 
+
+/* Generate statements to call .DEFERRED_INIT to initialize scalar replacements
+   of accesses within a subtree ACCESS; all its children, siblings and their
+   children are to be processed.
+   GSI is a statement iterator used to place the new statements.  */
+static void
+generate_subtree_deferred_init (struct access *access,
+				enum auto_init_type init_type,
+				gimple_stmt_iterator *gsi,
+				location_t loc)
+{
+  do
+    {
+      if (access->grp_to_be_replaced)
+	{
+	  tree repl = get_access_replacement (access);
+	  tree init_type_node
+	    = build_int_cst (integer_type_node, (int) init_type);
+	  gimple *call = gimple_build_call_internal (IFN_DEFERRED_INIT, 2,
+						     repl, init_type_node);
+	  gimple_call_set_lhs (call, repl);
+	  gsi_insert_before (gsi, call, GSI_SAME_STMT);
+	  update_stmt (call);
+	  gimple_set_location (call, loc);
+
+	  sra_stats.subtree_deferred_init++;
+	}
+      else if (access->grp_to_be_debug_replaced)
+	{
+	  tree drepl = get_access_replacement (access);
+	  tree init_type_node
+	    = build_int_cst (integer_type_node, (int) init_type);
+	  tree call = build_call_expr_internal_loc
+		     (UNKNOWN_LOCATION, IFN_DEFERRED_INIT,
+		      TREE_TYPE (drepl), 2, drepl, init_type_node);
+	  gdebug *ds = gimple_build_debug_bind (drepl, call,
+						gsi_stmt (*gsi));
+	  gsi_insert_before (gsi, ds, GSI_SAME_STMT);
+	}
+      if (access->first_child)
+	generate_subtree_deferred_init (access->first_child, init_type,
+					gsi, loc);
+
+      access = access ->next_sibling;
+    }
+  while (access);
+}
+
+/* For a call to .DEFERRED_INIT:
+   var = .DEFERRED_INIT (var, init_type);
+   examine the LHS variable VAR and replace it with a scalar replacement if
+   there is one, also replace the RHS call to a call to .DEFERRED_INIT of
+   the corresponding scalar relacement variable.  Examine the subtree and
+   do the scalar replacements in the subtree too.  STMT is the call, GSI is
+   the statment iterator to place newly created statement.  */
+
+static enum assignment_mod_result
+sra_modify_deferred_init (gimple *stmt, gimple_stmt_iterator *gsi)
+{
+  tree lhs = gimple_call_lhs (stmt);
+  tree arg0 = gimple_call_arg (stmt, 0);
+  enum auto_init_type init_type
+    = (enum auto_init_type) TREE_INT_CST_LOW (gimple_call_arg (stmt, 1));
+  struct access *lhs_access = get_access_for_expr (lhs);
+  struct access *arg0_access = get_access_for_expr (arg0);
+  if (!lhs_access && !arg0_access)
+    return SRA_AM_NONE;
+  gcc_assert (lhs_access && arg0_access);
+
+  location_t loc = gimple_location (stmt);
+
+  if (lhs_access->grp_to_be_replaced)
+    {
+      tree lhs_repl = get_access_replacement (lhs_access);
+      tree arg0_repl = get_access_replacement (arg0_access);
+      if (TREE_CODE (lhs_repl) == SSA_NAME)
+	{
+	  gcc_assert (TREE_CODE (arg0_repl) == SSA_NAME);
+	  gcc_assert (SSA_NAME_VAR (lhs_repl) == SSA_NAME_VAR (arg0_repl));
+	}
+      else
+	gcc_assert (lhs_repl == arg0_repl);
+      gimple_call_set_lhs (stmt, lhs_repl);
+      gimple_call_set_arg (stmt, 0, arg0_repl);
+      sra_stats.deferred_init++;
+    }
+  else if (lhs_access->grp_to_be_debug_replaced)
+    {
+      tree lhs_drepl = get_access_replacement (lhs_access);
+      tree init_type_node
+	   = build_int_cst (integer_type_node, (int) init_type);
+      tree call = build_call_expr_internal_loc
+		  (UNKNOWN_LOCATION, IFN_DEFERRED_INIT,
+		  TREE_TYPE (lhs_drepl), 2, lhs_drepl, init_type_node);
+      gdebug *ds = gimple_build_debug_bind (lhs_drepl, call,
+					    gsi_stmt (*gsi));
+      gsi_insert_before (gsi, ds, GSI_SAME_STMT);
+    }
+
+  if (lhs_access->first_child)
+    generate_subtree_deferred_init (lhs_access->first_child,
+				    init_type, gsi, loc);
+  if (lhs_access->grp_covered)
+    {
+      unlink_stmt_vdef (stmt);
+      gsi_remove (gsi, true);
+      release_defs (stmt);
+      return SRA_AM_REMOVED;
+    }
+
+  return SRA_AM_MODIFIED;
+}
+
 /* Examine both sides of the assignment statement pointed to by STMT, replace
    them with a scalare replacement if there is one and generate copying of
    replacements if scalarized aggregates have been used in the assignment.  GSI
@@ -4434,17 +4554,27 @@ sra_modify_function_body (void)
 	      break;
 
 	    case GIMPLE_CALL:
-	      /* Operands must be processed before the lhs.  */
-	      for (i = 0; i < gimple_call_num_args (stmt); i++)
+	      /* Handle calls to .DEFERRED_INIT specially.  */
+	      if (gimple_call_internal_p (stmt, IFN_DEFERRED_INIT))
 		{
-		  t = gimple_call_arg_ptr (stmt, i);
-		  modified |= sra_modify_expr (t, &gsi, false);
+		  assign_result = sra_modify_deferred_init (stmt, &gsi);
+		  modified |= assign_result == SRA_AM_MODIFIED;
+		  deleted = assign_result == SRA_AM_REMOVED;
 		}
-
-	      if (gimple_call_lhs (stmt))
+	      else
 		{
-		  t = gimple_call_lhs_ptr (stmt);
-		  modified |= sra_modify_expr (t, &gsi, true);
+		  /* Operands must be processed before the lhs.  */
+		  for (i = 0; i < gimple_call_num_args (stmt); i++)
+		    {
+		      t = gimple_call_arg_ptr (stmt, i);
+		      modified |= sra_modify_expr (t, &gsi, false);
+		    }
+
+	      	  if (gimple_call_lhs (stmt))
+		    {
+		      t = gimple_call_lhs_ptr (stmt);
+		      modified |= sra_modify_expr (t, &gsi, true);
+		    }
 		}
 	      break;
 
diff --git a/gcc/tree-ssa-structalias.c b/gcc/tree-ssa-structalias.c
index cf653be8b6df..547df1c7b41d 100644
--- a/gcc/tree-ssa-structalias.c
+++ b/gcc/tree-ssa-structalias.c
@@ -4864,6 +4864,9 @@ find_func_aliases_for_call (struct function *fn, gcall *t)
       && find_func_aliases_for_builtin_call (fn, t))
     return;
 
+  if (gimple_call_internal_p (t, IFN_DEFERRED_INIT))
+    return;
+
   fi = get_fi_for_callee (t);
   if (!in_ipa_mode
       || (fi->decl && fndecl && !fi->is_fn_info))
diff --git a/gcc/tree-ssa-uninit.c b/gcc/tree-ssa-uninit.c
index 516a7bd2c992..c86c59cbabd4 100644
--- a/gcc/tree-ssa-uninit.c
+++ b/gcc/tree-ssa-uninit.c
@@ -135,6 +135,42 @@ warn_uninit (enum opt_code wc, tree t, tree expr, tree var,
   if (is_gimple_assign (context)
       && gimple_assign_rhs_code (context) == COMPLEX_EXPR)
     return;
+
+  /* Ignore REALPART_EXPR or IMAGPART_EXPR if its operand is a call to
+     .DEFERRED_INIT.  This is for handling the following case correctly:
+
+  1 typedef _Complex float C;
+  2 C foo(int cond)
+  3 {
+  4   C f;
+  5   __imag__ f = 0;
+  6   if (cond)
+  7     {
+  8       __real__ f = 1;
+  9       return f;
+ 10     }
+ 11   return f;
+ 12 }
+
+    with -ftrivial-auto-var-init, compiler will insert the following
+    artificial initialization at line 4:
+  f = .DEFERRED_INIT (f, 2);
+  _1 = REALPART_EXPR <f>;
+
+    without the following special handling, _1 = REALPART_EXPR <f> will
+    be treated as the uninitialized use point, which is incorrect. (the
+    real uninitialized use point is at line 11).  */
+  if (is_gimple_assign (context)
+      && (gimple_assign_rhs_code (context) == REALPART_EXPR
+	  || gimple_assign_rhs_code (context) == IMAGPART_EXPR))
+    {
+      tree v = gimple_assign_rhs1 (context);
+      if (TREE_CODE (TREE_OPERAND (v, 0)) == SSA_NAME
+	  && gimple_call_internal_p (SSA_NAME_DEF_STMT (TREE_OPERAND (v, 0)),
+				     IFN_DEFERRED_INIT))
+	return;
+    }
+
   if (!has_undefined_value_p (t))
     return;
 
@@ -209,6 +245,19 @@ check_defs (ao_ref *ref, tree vdef, void *data_)
 {
   check_defs_data *data = (check_defs_data *)data_;
   gimple *def_stmt = SSA_NAME_DEF_STMT (vdef);
+
+  /* Ignore the vdef if the definition statement is a call
+     to .DEFERRED_INIT function.  */
+  if (gimple_call_internal_p (def_stmt, IFN_DEFERRED_INIT))
+    return false;
+
+  /* Ignore the vdef if the definition statement is a call
+     to builtin_memset function that is added for uninitialized
+     auto variable initialization.  */
+  if (gimple_call_builtin_p (def_stmt, BUILT_IN_MEMSET)
+      && gimple_call_memset_for_uninit_p (def_stmt))
+    return false;
+
   /* If this is a clobber then if it is not a kill walk past it.  */
   if (gimple_clobber_p (def_stmt))
     {
@@ -611,6 +660,12 @@ warn_uninitialized_vars (bool wmaybe_uninit)
 	  ssa_op_iter op_iter;
 	  tree use;
 
+	  /* The call is an artificial use, will not provide meaningful
+	     error message.  If the result of the call is used somewhere
+	     else, we warn there instead.  */
+	  if (gimple_call_internal_p (stmt, IFN_DEFERRED_INIT))
+	    continue;
+
 	  if (is_gimple_debug (stmt))
 	    continue;
 
diff --git a/gcc/tree-ssa.c b/gcc/tree-ssa.c
index a575979aa139..0c285f7b4f0f 100644
--- a/gcc/tree-ssa.c
+++ b/gcc/tree-ssa.c
@@ -1325,6 +1325,46 @@ ssa_undefined_value_p (tree t, bool partial)
   if (gimple_nop_p (def_stmt))
     return true;
 
+  /* The value is undefined if the definition statement is a call
+     to .DEFERRED_INIT function.  */
+  if (gimple_call_internal_p (def_stmt, IFN_DEFERRED_INIT))
+    return true;
+
+  /* The value is partially undefined if the definition statement is
+     a REALPART_EXPR or IMAGPART_EXPR and its operand is defined by
+     the call to .DEFERRED_INIT function.  This is for handling the
+     following case:
+
+  1 typedef _Complex float C;
+  2 C foo(int cond)
+  3 {
+  4   C f;
+  5   __imag__ f = 0;
+  6   if (cond)
+  7     {
+  8       __real__ f = 1;
+  9       return f;
+ 10     }
+ 11   return f;
+ 12 }
+
+    with -ftrivial-auto-var-init, compiler will insert the following
+    artificial initialization:
+  f = .DEFERRED_INIT (f, 2);
+  _1 = REALPART_EXPR <f>;
+
+    we should treat the definition _1 = REALPART_EXPR <f> as undefined.  */
+  if (partial && is_gimple_assign (def_stmt)
+      && (gimple_assign_rhs_code (def_stmt) == REALPART_EXPR
+	  || gimple_assign_rhs_code (def_stmt) == IMAGPART_EXPR))
+    {
+      tree real_imag_part = TREE_OPERAND (gimple_assign_rhs1 (def_stmt), 0);
+      if (TREE_CODE (real_imag_part) == SSA_NAME
+	 && gimple_call_internal_p (SSA_NAME_DEF_STMT (real_imag_part),
+				    IFN_DEFERRED_INIT))
+	return true;
+    }
+
   /* Check if the complex was not only partially defined.  */
   if (partial && is_gimple_assign (def_stmt)
       && gimple_assign_rhs_code (def_stmt) == COMPLEX_EXPR)
diff --git a/gcc/tree.c b/gcc/tree.c
index 02ce5ddcd491..c320781befec 100644
--- a/gcc/tree.c
+++ b/gcc/tree.c
@@ -2529,6 +2529,161 @@ build_zero_cst (tree type)
     }
 }
 
+/* Build pattern constant of type TYPE.  This is used for initializing
+   auto variables.  */
+
+tree
+build_pattern_cst_for_auto_init (tree type)
+{
+  /* 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;
+
+  switch (TREE_CODE (type))
+    {
+    case BOOLEAN_TYPE:
+      /* We think that initializing the boolean variable to 0 other than 1
+	 is better even for pattern initialization.  */
+      return build_zero_cst (type);
+    case INTEGER_TYPE:
+    case ENUMERAL_TYPE:
+      {
+	unsigned char ptr[16]
+	  = {0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA,
+	     0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA, 0xAA};
+	int total_bytes = GET_MODE_SIZE (SCALAR_INT_TYPE_MODE (type));
+	wide_int result = wi::from_buffer (ptr, total_bytes);
+	return wide_int_to_tree (type, result);
+      }
+    case POINTER_TYPE:
+    case OFFSET_TYPE:
+    case REFERENCE_TYPE:
+    case NULLPTR_TYPE:
+      {
+	poly_uint64 intvalue;
+
+	if (POINTER_SIZE == 64)
+	  intvalue = largevalue;
+	else
+	  intvalue = smallvalue;
+	return build_int_cstu (type, intvalue);
+      }
+    case REAL_TYPE:
+      {
+	REAL_VALUE_TYPE rnan;
+	machine_mode mode = TYPE_MODE (type);
+
+	/* create an quiet NAN for REAL TYPE.
+	   if failed, fallback to MAX_FLOAT instead.  */
+	if (!real_nan (&rnan, "", 1, mode))
+	  {
+	    char buf[128];
+ 
+	    get_max_float (REAL_MODE_FORMAT (mode), buf, sizeof (buf), false);
+	    real_from_string (&rnan, buf);
+	  }
+	return build_real (type, rnan);
+      }
+    case FIXED_POINT_TYPE:
+      {
+	FIXED_VALUE_TYPE fixed;
+	fixed_from_string (&fixed, "0xFFFFFFFFFFFFFFFF",
+			   SCALAR_TYPE_MODE (type));
+	return build_fixed (type, fixed);
+      }
+    case VECTOR_TYPE:
+      {
+	tree scalar = build_pattern_cst_for_auto_init (TREE_TYPE (type));
+	return build_vector_from_val (type, scalar);
+      }
+    case COMPLEX_TYPE:
+      {
+	tree element = build_pattern_cst_for_auto_init (TREE_TYPE (type));
+	return build_complex (type, element, element);
+      }
+    case RECORD_TYPE:
+      {
+	tree field;
+	tree field_value;
+	vec<constructor_elt, va_gc> *v = NULL;
+	for (field= TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
+	  {
+	    if (TREE_CODE (field) != FIELD_DECL)
+	      continue;
+	    /* If the field is a flexible array member, it should be the last
+	       field of the record, and no need to initialize it.  */
+	    if (TREE_CODE (TREE_TYPE (field)) == ARRAY_TYPE
+		&& TYPE_SIZE (TREE_TYPE (field)) == NULL_TREE
+		&& ((TYPE_DOMAIN (TREE_TYPE (field)) != NULL_TREE
+		    && TYPE_MAX_VALUE (TYPE_DOMAIN (TREE_TYPE (field))) 
+				       == NULL_TREE)
+		   || TYPE_DOMAIN (TREE_TYPE (field)) == NULL_TREE))
+	      continue;
+	    field_value = build_pattern_cst_for_auto_init (TREE_TYPE (field));
+	    CONSTRUCTOR_APPEND_ELT (v, field, field_value);
+	  }
+	return build_constructor (type, v);
+      }
+    case UNION_TYPE:
+    case QUAL_UNION_TYPE:
+      {
+	tree field, max_field = NULL;
+	unsigned max_size = 0;
+	tree field_value;
+	vec<constructor_elt, va_gc> *v = NULL;
+	/* Find the field with the largest size.  */
+	for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
+	  {
+	    if (TREE_CODE (field) != FIELD_DECL)
+	      continue;
+	    if (tree_fits_uhwi_p (TYPE_SIZE_UNIT (TREE_TYPE (field))))
+	      if (tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (field))) >= max_size)
+	      {
+		max_size = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (field)));
+		max_field = field;
+	      }
+	  }
+	if (max_field)
+	  {
+	    field_value
+	      = build_pattern_cst_for_auto_init (TREE_TYPE (max_field));
+	    CONSTRUCTOR_APPEND_ELT (v, max_field, field_value);
+	  }
+	return build_constructor (type, v);
+      }
+    case ARRAY_TYPE:
+      {
+	vec<constructor_elt, va_gc> *elts = NULL;
+	tree element = build_pattern_cst_for_auto_init (TREE_TYPE (type));
+	tree nelts = array_type_nelts (type);
+	if (nelts && tree_fits_uhwi_p (nelts))
+	  {
+	    unsigned HOST_WIDE_INT n = tree_to_uhwi (nelts) + 1;
+	    for (unsigned int i = 0; i < n; i++)
+	      CONSTRUCTOR_APPEND_ELT (elts, NULL_TREE, element);
+	    return build_constructor (type, elts);
+	  }
+	/* Variable length array should not be here.  */
+	gcc_unreachable ();
+      }
+    default:
+      if (!AGGREGATE_TYPE_P (type))
+	return
+	  fold_convert (type,
+			build_pattern_cst_for_auto_init (unsigned_type_node));
+      else
+	gcc_unreachable ();
+
+    }
+}
+
 
 /* Build a BINFO with LEN language slots.  */
 
@@ -11944,6 +12099,72 @@ lower_bound_in_type (tree outer, tree inner)
     }
 }
 
+/* Returns true when the given TYPE has padding inside it.
+   return false otherwise.  */
+bool
+type_has_padding (tree type)
+{
+  switch (TREE_CODE (type))
+    {
+    case RECORD_TYPE:
+      {
+	unsigned HOST_WIDE_INT record_size
+	  = tree_to_uhwi (TYPE_SIZE_UNIT (type));
+	unsigned HOST_WIDE_INT size_sofar = 0;
+
+	for (tree field= TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
+	  {
+	    if (TREE_CODE (field) != FIELD_DECL)
+	      continue;
+	    unsigned HOST_WIDE_INT cur_off = int_byte_position (field);
+	    if (size_sofar < cur_off)
+	      return true;
+	    size_sofar = cur_off
+			 + tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (field)));
+    	  }
+	if (size_sofar < record_size)
+	  return true;
+	/* If any of the field has padding, return true.  */
+	for (tree field= TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
+	  {
+	    if ((TREE_CODE (field) != FIELD_DECL))
+	      continue;
+	    if (AGGREGATE_TYPE_P (TREE_TYPE (field))
+		&& type_has_padding (TREE_TYPE (field)))
+	      return true;
+	  }
+  	return false;
+      }
+    case UNION_TYPE:
+    case QUAL_UNION_TYPE:
+      {
+	tree max_field = NULL;
+	unsigned max_size = 0;
+	for (tree field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
+	  {
+	    if (TREE_CODE (field) != FIELD_DECL)
+	      continue;
+	    if (tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (field))) >= max_size)
+	      {
+		max_size = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (field)));
+		max_field = field;
+	      }
+	  }
+	if (AGGREGATE_TYPE_P (TREE_TYPE (max_field)))
+	  return type_has_padding (TREE_TYPE (max_field));
+	return false;
+      }
+    case ARRAY_TYPE:
+      {
+	if (AGGREGATE_TYPE_P (TREE_TYPE (type)))
+	  return type_has_padding (TREE_TYPE (type));
+ 	return false;
+      }
+    default:
+      return false;
+    }
+}
+
 /* Return nonzero if two operands that are suitable for PHI nodes are
    necessarily equal.  Specifically, both ARG0 and ARG1 must be either
    SSA_NAME or invariant.  Note that this is strictly an optimization.
diff --git a/gcc/tree.h b/gcc/tree.h
index 7faa49d42ba3..7b7d5bf76bd1 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -4460,6 +4460,7 @@ extern tree build_one_cst (tree);
 extern tree build_minus_one_cst (tree);
 extern tree build_all_ones_cst (tree);
 extern tree build_zero_cst (tree);
+extern tree build_pattern_cst_for_auto_init (tree);
 extern tree build_string (unsigned, const char * = NULL);
 extern tree build_poly_int_cst (tree, const poly_wide_int_ref &);
 extern tree build_tree_list (tree, tree CXX_MEM_STAT_INFO);
@@ -5125,6 +5126,7 @@ extern bool operation_can_overflow (enum tree_code);
 extern bool operation_no_trapping_overflow (tree, enum tree_code);
 extern tree upper_bound_in_type (tree, tree);
 extern tree lower_bound_in_type (tree, tree);
+extern bool type_has_padding (tree);
 extern int operand_equal_for_phi_arg_p (const_tree, const_tree);
 extern tree create_artificial_label (location_t);
 extern const char *get_name (tree);
-- 
2.27.0


[-- Attachment #5: Type: text/plain, Size: 3 bytes --]





^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH][version 3]add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-05-12 17:16 [PATCH][version 3]add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc Qing Zhao
@ 2021-05-25 19:26 ` Qing Zhao
  2021-05-26 11:18 ` Richard Biener
  1 sibling, 0 replies; 57+ messages in thread
From: Qing Zhao @ 2021-05-25 19:26 UTC (permalink / raw)
  To: richard Sandiford, Richard Biener; +Cc: gcc-patches Qing Zhao via, kees Cook

Ping….

Qing

On May 12, 2021, at 12:16 PM, Qing Zhao via Gcc-patches <gcc-patches@gcc.gnu.org<mailto:gcc-patches@gcc.gnu.org>> wrote:

Hi,

This is the 3rd version of the patch for the new security feature for GCC.

Please take look and let me know your comments and suggestions.

thanks.

Qing

******Compare with the 2nd version, the following are the major changes:

1. use "lookup_attribute ("uninitialized",) directly instead of adding
   one new field "uninitialized" into tree_decl_with_vis.
2. update documentation to mention that the new option will not confuse
   -Wuninitialized, GCC still consider an auto without explicit initializer
   as uninitialized.
3. change the name of "build_pattern_cst" to more specific name as
   "build_pattern_cst_for_auto_init".
4. handling of nested VLA;
   Adding new testing cases (auto-init-15/16.c) for this new handling.
5. Add  new verifications of calls to .DEFERRED_INIT in tree-cfg.c;
6. in tree-sra.c, update the handling of "grp_to_be_debug_replaced",
   bind the lhs variable to a call to .DEFERRED_INIT.
7. In tree-ssa-structalias.c, delete "find_func_aliases_for_deferred_init",
   return directly for a call to .DEFERRED_INIT in "find_func_aliases_for_call".
8. Add more detailed comments in tree-ssa-uninit.c and tree-ssa.c to explain
   the special handling on REALPART_EXPR/IMAGPRT_EXPR.
9. in build_pattern_cst_for_auto_init:
   BOOLEAN_TYPE will be set to zero always;
   INTEGER_TYPE (?and ENUMERAL_TYPE) use wi::from_buffer in order to
                correctly handle 128-bit integers.
   POINTER_TYPE will not assert on SIZE < 32.
   REAL_TYPE add fallback;
10. changed gcc_assert to gcc_unreachable in several places;
11. add more comments;
12. some style issue changes.

******Please see the version 2 at:
https://gcc.gnu.org/pipermail/gcc-patches/2021-March/567262.html


******The following 2 items are the ones I didn’t addressed in this version due to further study and might need more discussion:

1. Using __builtin_clear_padding  to replace type_has_padding.

My study shows: the call to __builtin_clear_padding is expanded during gimplification phase.
And there is no __bultin_clear_padding expanding during rtx expanding phase.
If so,  for -ftrivial-auto-var-init, padding initialization should be done both in gimplification phase and rtx expanding phase.
And since the __builtin_clear_padding might not be good for rtx expanding, reusing __builtin_clear_padding might not work.

2. Pattern init to NULLPTR_TYPE and ENUMERAL_TYPE: need more comments from Richard Biener on this.

******The change of the 3rd version compared to the 2nd version are:



******The complete 3rd version of the patch are:



<change-against-2nd-version.patch><3rd-version-ftrivial-auto-var-init.patch>


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH][version 3]add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-05-12 17:16 [PATCH][version 3]add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc Qing Zhao
  2021-05-25 19:26 ` Qing Zhao
@ 2021-05-26 11:18 ` Richard Biener
  2021-05-27 19:44   ` Qing Zhao
                     ` (4 more replies)
  1 sibling, 5 replies; 57+ messages in thread
From: Richard Biener @ 2021-05-26 11:18 UTC (permalink / raw)
  To: Qing Zhao; +Cc: richard Sandiford, kees Cook, gcc-patches Qing Zhao via

On Wed, 12 May 2021, Qing Zhao wrote:

> Hi, 
> 
> This is the 3rd version of the patch for the new security feature for GCC.
> 
> Please take look and let me know your comments and suggestions.
> 
> thanks.
> 
> Qing
> 
> ******Compare with the 2nd version, the following are the major changes:
> 
> 1. use "lookup_attribute ("uninitialized",) directly instead of adding
>    one new field "uninitialized" into tree_decl_with_vis.
> 2. update documentation to mention that the new option will not confuse
>    -Wuninitialized, GCC still consider an auto without explicit initializer
>    as uninitialized.
> 3. change the name of "build_pattern_cst" to more specific name as
>    "build_pattern_cst_for_auto_init".
> 4. handling of nested VLA;
>    Adding new testing cases (auto-init-15/16.c) for this new handling.
> 5. Add  new verifications of calls to .DEFERRED_INIT in tree-cfg.c;
> 6. in tree-sra.c, update the handling of "grp_to_be_debug_replaced",
>    bind the lhs variable to a call to .DEFERRED_INIT.
> 7. In tree-ssa-structalias.c, delete "find_func_aliases_for_deferred_init",
>    return directly for a call to .DEFERRED_INIT in "find_func_aliases_for_call".
> 8. Add more detailed comments in tree-ssa-uninit.c and tree-ssa.c to explain
>    the special handling on REALPART_EXPR/IMAGPRT_EXPR.
> 9. in build_pattern_cst_for_auto_init:
>    BOOLEAN_TYPE will be set to zero always;
>    INTEGER_TYPE (?and ENUMERAL_TYPE) use wi::from_buffer in order to
>                 correctly handle 128-bit integers.
>    POINTER_TYPE will not assert on SIZE < 32.
>    REAL_TYPE add fallback;
> 10. changed gcc_assert to gcc_unreachable in several places;
> 11. add more comments;
> 12. some style issue changes.
> 
> ******Please see the version 2 at:
> https://gcc.gnu.org/pipermail/gcc-patches/2021-March/567262.html
> 
> 
> ******The following 2 items are the ones I didn’t addressed in this version due to further study and might need more discussion:
> 
> 1. Using __builtin_clear_padding  to replace type_has_padding.
> 
> My study shows: the call to __builtin_clear_padding is expanded during gimplification phase.  
> And there is no __bultin_clear_padding expanding during rtx expanding phase.
> If so,  for -ftrivial-auto-var-init, padding initialization should be done both in gimplification phase and rtx expanding phase. 
> And since the __builtin_clear_padding might not be good for rtx expanding, reusing __builtin_clear_padding might not work.
> 
> 2. Pattern init to NULLPTR_TYPE and ENUMERAL_TYPE: need more comments from Richard Biener on this.
> 
> ******The change of the 3rd version compared to the 2nd version are:


+@item -ftrivial-auto-var-init=@var{choice}
+@opindex ftrivial-auto-var-init
+Initialize automatic variables with either a pattern or with zeroes to 
increase
+the security and predictability of a program by preventing uninitialized 
memory
+disclosure and use.

the docs do not state what "trivial" actually means?  Does it affect
C++ classes with ctors, thus is "trivial" equal to what C++ considers
a POD type?

diff --git a/gcc/expr.c b/gcc/expr.c
index 798285eb52ca..9092349d7017 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -6539,14 +6539,19 @@ store_constructor (tree exp, rtx target, int 
cleared, poly_int64 size,
            cleared = 1;
          }

-        /* If the constructor has fewer fields than the structure or
-          if we are initializing the structure to mostly zeros, clear
-          the whole structure first.  Don't do this if TARGET is a
-          register whose mode size isn't equal to SIZE since
-          clear_storage can't handle this case.  */
+       /* If the constructor has fewer fields than the structure,
+          or if we are initializing the structure to mostly zeros,
+          or if the user requests to initialize automatic variables with
+          paddings inside the type,
+          we should clear the whole structure first.
+          Don't do this if TARGET is a register whose mode size isn't 
equal
+          SIZE since clear_storage can't handle this case.  */
        else if (known_size_p (size)
                 && (((int) CONSTRUCTOR_NELTS (exp) != fields_length 
(type))
-                    || mostly_zeros_p (exp))
+                    || mostly_zeros_p (exp)
+                    || (flag_trivial_auto_var_init > 
AUTO_INIT_UNINITIALIZED
+                        && !TREE_STATIC (exp)
+                        && type_has_padding (type)))

testing flag_trivial_auto_var_init tests the global options, if TUs
are compiled with different setting of flag_trivial_auto_var_init
and you use LTO or flag_trivial_auto_var_init is specified per
function via optimize attributes it's more appropriate to test
opt_for_fn (cfun->decl, flag_trivial_auto_var_init)

You do not actually test whether TARGET is an auto-var in this place,
so I question this change - the documentation of ftrivial-auto-var-init
also doesn't mention initialization of padding and the above doesn't
seem to honor -ftrivial-auto-var-init=pattern for this.

+enum auto_init_approach {
+  AUTO_INIT_A = 0,
+  AUTO_INIT_D = 1
+};

I'm assuming we're going for one implementation in the end - have
you made up your mind yet?

+/* If FOR_UNINIT is true, GIMPLE_CALL S is a call to builtin_memset that
+   is known to be emitted for unintialized VLA objects.  */
+
+static inline void
+gimple_call_set_memset_for_uninit (gcall *s, bool for_uninit)

seeing this, can you explain why using .DEFERRED_INIT does not
work for VLAs?  You can build

  .DEFERRED_INIT (WITH_SIZE_EXPR <decl, size-expression>, type)

to carry the initialization size.  There's maybe_with_size_expr that
you can conveniently use to perform the WITH_SIZE_EXPR wrapping.
I'd strongly prefer not going different routes for VLAs vs. on-VLAs.

@@ -5001,6 +5185,17 @@ gimplify_init_constructor (tree *expr_p, gimple_seq 
*pre_p, gimple_seq *post_p,
          /* If a single access to the target must be ensured and all 
elements
             are zero, then it's optimal to clear whatever their number.  
*/
          cleared = true;
+       else if (flag_trivial_auto_var_init > AUTO_INIT_UNINITIALIZED
+                && !TREE_STATIC (object)
+                && type_has_padding (type))
+         /* If the user requests to initialize automatic variables with
+            paddings inside the type, we should initialize the paddings 
too.
+            C guarantees that brace-init with fewer initializers than 
members
+            aggregate will initialize the rest of the aggregate as-if it 
were
+            static initialization.  In turn static initialization 
guarantees
+            that pad is initialized to zero bits.
+            So, it's better to clear the whole record under such 
situation.  */
+         cleared = true;

so here we have padding as well - I think this warrants to be controlled
by an extra option?  And we can maybe split this out to a separate
patch? (the whole padding stuff)

+/* Expand the IFN_DEFERRED_INIT function according to its second 
argument.  */
+static void
+expand_DEFERRED_INIT (internal_fn, gcall *stmt)
+{
+  tree var = gimple_call_lhs (stmt);
+  tree init = NULL_TREE;
+  enum auto_init_type init_type
+    = (enum auto_init_type) TREE_INT_CST_LOW (gimple_call_arg (stmt, 1));
+
+  switch (init_type)
+    {
+    default:
+      gcc_unreachable ();
+    case AUTO_INIT_PATTERN:
+      init = build_pattern_cst_for_auto_init (TREE_TYPE (var));
+      expand_assignment (var, init, false);
+      break;
+    case AUTO_INIT_ZERO:
+      init = build_zero_cst (TREE_TYPE (var));
+      expand_assignment (var, init, false);
+      break;
+    }

I think actually building build_pattern_cst_for_auto_init can generate
massive garbage and for big auto vars code size is also a concern and
ideally on x86 you'd produce rep movq.  So I don't think going
via expand_assignment is good.  Instead you possibly want to lower
.DEFERRED_INIT to MEMs following expand_builtin_memset and
eventually enhance that to allow storing pieces larger than a byte.

diff --git a/gcc/tree-core.h b/gcc/tree-core.h
index e457b917b98e..2e0e76ea8838 100644
--- a/gcc/tree-core.h
+++ b/gcc/tree-core.h
@@ -1829,7 +1829,7 @@ struct GTY(()) tree_decl_with_vis {
  unsigned final : 1;
  /* Belong to FUNCTION_DECL exclusively.  */
  unsigned regdecl_flag : 1;
- /* 14 unused bits. */
+ /* 14 unused bits.  */
  /* 32 more unused on 64 bit HW. */
 };


spurious change, please drop.

+  /* Ignore REALPART_EXPR or IMAGPART_EXPR if its operand is a call to
+     .DEFERRED_INIT.  This is for handling the following case correctly:
+
+  1 typedef _Complex float C;
+  2 C foo(int cond)
+  3 {
+  4   C f;
+  5   __imag__ f = 0;
+  6   if (cond)
+  7     {
+  8       __real__ f = 1;
+  9       return f;
+ 10     }
+ 11   return f;
+ 12 }
+
+    with -ftrivial-auto-var-init, compiler will insert the following
+    artificial initialization at line 4:
+  f = .DEFERRED_INIT (f, 2);
+  _1 = REALPART_EXPR <f>;
+
+    without the following special handling, _1 = REALPART_EXPR <f> will
+    be treated as the uninitialized use point, which is incorrect. (the
+    real uninitialized use point is at line 11).  */
+  if (is_gimple_assign (context)
+      && (gimple_assign_rhs_code (context) == REALPART_EXPR
+         || gimple_assign_rhs_code (context) == IMAGPART_EXPR))
+    {
+      tree v = gimple_assign_rhs1 (context);
+      if (TREE_CODE (TREE_OPERAND (v, 0)) == SSA_NAME
+         && gimple_call_internal_p (SSA_NAME_DEF_STMT (TREE_OPERAND (v, 
0)),
+                                    IFN_DEFERRED_INIT))
+       return;
+    }

will this not mishandle (not report)

C foo ()
{
  C f;
  return __real f;
}

?  I think ssa_undefined_value_p is supposed to catch this, you
seem to duplicate something there as well.

+/* Returns true when the given TYPE has padding inside it.
+   return false otherwise.  */
+bool                    
+type_has_padding (tree type)
+{      
+  switch (TREE_CODE (type))
+    {
+    case RECORD_TYPE:
+      {

btw, there's __builtin_clear_padding and a whole machinery around
it in gimple-fold.c, I'm sure that parts could be re-used if they
are neccessary in the end.

Otherwise the changes look OK.

Do DCE/DSE remove unused .DEFERRED_INIT?

Thanks,
Richard.

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH][version 3]add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-05-26 11:18 ` Richard Biener
@ 2021-05-27 19:44   ` Qing Zhao
  2021-06-07  7:48     ` Richard Biener
  2021-05-27 21:42   ` Qing Zhao
                     ` (3 subsequent siblings)
  4 siblings, 1 reply; 57+ messages in thread
From: Qing Zhao @ 2021-05-27 19:44 UTC (permalink / raw)
  To: Richard Biener; +Cc: richard Sandiford, kees Cook, gcc-patches Qing Zhao via

Hi, Richard,

Thanks a lot for your comments.


On May 26, 2021, at 6:18 AM, Richard Biener <rguenther@suse.de<mailto:rguenther@suse.de>> wrote:

On Wed, 12 May 2021, Qing Zhao wrote:

Hi,

This is the 3rd version of the patch for the new security feature for GCC.

Please take look and let me know your comments and suggestions.

thanks.

Qing

******Compare with the 2nd version, the following are the major changes:

1. use "lookup_attribute ("uninitialized",) directly instead of adding
  one new field "uninitialized" into tree_decl_with_vis.
2. update documentation to mention that the new option will not confuse
  -Wuninitialized, GCC still consider an auto without explicit initializer
  as uninitialized.
3. change the name of "build_pattern_cst" to more specific name as
  "build_pattern_cst_for_auto_init".
4. handling of nested VLA;
  Adding new testing cases (auto-init-15/16.c) for this new handling.
5. Add  new verifications of calls to .DEFERRED_INIT in tree-cfg.c;
6. in tree-sra.c, update the handling of "grp_to_be_debug_replaced",
  bind the lhs variable to a call to .DEFERRED_INIT.
7. In tree-ssa-structalias.c, delete "find_func_aliases_for_deferred_init",
  return directly for a call to .DEFERRED_INIT in "find_func_aliases_for_call".
8. Add more detailed comments in tree-ssa-uninit.c and tree-ssa.c to explain
  the special handling on REALPART_EXPR/IMAGPRT_EXPR.
9. in build_pattern_cst_for_auto_init:
  BOOLEAN_TYPE will be set to zero always;
  INTEGER_TYPE (?and ENUMERAL_TYPE) use wi::from_buffer in order to
               correctly handle 128-bit integers.
  POINTER_TYPE will not assert on SIZE < 32.
  REAL_TYPE add fallback;
10. changed gcc_assert to gcc_unreachable in several places;
11. add more comments;
12. some style issue changes.

******Please see the version 2 at:
https://gcc.gnu.org/pipermail/gcc-patches/2021-March/567262.html


******The following 2 items are the ones I didn’t addressed in this version due to further study and might need more discussion:

1. Using __builtin_clear_padding  to replace type_has_padding.

My study shows: the call to __builtin_clear_padding is expanded during gimplification phase.
And there is no __bultin_clear_padding expanding during rtx expanding phase.
If so,  for -ftrivial-auto-var-init, padding initialization should be done both in gimplification phase and rtx expanding phase.
And since the __builtin_clear_padding might not be good for rtx expanding, reusing __builtin_clear_padding might not work.

2. Pattern init to NULLPTR_TYPE and ENUMERAL_TYPE: need more comments from Richard Biener on this.

******The change of the 3rd version compared to the 2nd version are:


+@item -ftrivial-auto-var-init=@var{choice}
+@opindex ftrivial-auto-var-init
+Initialize automatic variables with either a pattern or with zeroes to
increase
+the security and predictability of a program by preventing uninitialized
memory
+disclosure and use.

the docs do not state what "trivial" actually means?  Does it affect
C++ classes with ctors, thus is "trivial" equal to what C++ considers
a POD type?

Thank you for this question.

The name -ftrivial-auto-var-init is just for compatible with Clang. I really don’t know why
they added trivial.

As I checked a small example with C++ class with ctors, I see both Clang and my patch add
Initialization to this class:

=====
#include <iostream>

using namespace std;

class Line {
   public:
      void setLength( double len );
      double getLength( void );
      Line();  // This is the constructor
   private:
      double length;
};

// Member functions definitions including constructor
Line::Line(void) {
   cout << "Object is being created" << endl;
}
void Line::setLength( double len ) {
  length = len;
}
double Line::getLength( void ) {
  return length;
}

// Main function for the program
int main() {
  Line line;

  // set line length
  line.setLength(6.0);
  cout << "Length of line : " << line.getLength() <<endl;

  return 0;
}

=====

Both clang and my patch add initialization to the above auto variable “line”.

So, I have the following questions need help:

1. Do we need to exclude C++ class with ctor from auto initialization?

2. I see Clang use call to internal memset to initialize such class, but for my patch, I only initialize the data fields inside this class.
    Which one is better?



diff --git a/gcc/expr.c b/gcc/expr.c
index 798285eb52ca..9092349d7017 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -6539,14 +6539,19 @@ store_constructor (tree exp, rtx target, int
cleared, poly_int64 size,
           cleared = 1;
         }

-        /* If the constructor has fewer fields than the structure or
-          if we are initializing the structure to mostly zeros, clear
-          the whole structure first.  Don't do this if TARGET is a
-          register whose mode size isn't equal to SIZE since
-          clear_storage can't handle this case.  */
+       /* If the constructor has fewer fields than the structure,
+          or if we are initializing the structure to mostly zeros,
+          or if the user requests to initialize automatic variables with
+          paddings inside the type,
+          we should clear the whole structure first.
+          Don't do this if TARGET is a register whose mode size isn't
equal
+          SIZE since clear_storage can't handle this case.  */
       else if (known_size_p (size)
                && (((int) CONSTRUCTOR_NELTS (exp) != fields_length
(type))
-                    || mostly_zeros_p (exp))
+                    || mostly_zeros_p (exp)
+                    || (flag_trivial_auto_var_init >
AUTO_INIT_UNINITIALIZED
+                        && !TREE_STATIC (exp)
+                        && type_has_padding (type)))

testing flag_trivial_auto_var_init tests the global options, if TUs
are compiled with different setting of flag_trivial_auto_var_init
and you use LTO or flag_trivial_auto_var_init is specified per
function via optimize attributes it's more appropriate to test
opt_for_fn (cfun->decl, flag_trivial_auto_var_init)

Okay.  Thanks for the info. I will update this.


You do not actually test whether TARGET is an auto-var in this place,
so I question this change

Will add checking for Auto on this.

- the documentation of ftrivial-auto-var-init
also doesn't mention initialization of padding

Will add initialization of padding on this.

Clang add the padding initialization with this option, I guess that we might need to
be compatible with it?

and the above doesn't
seem to honor -ftrivial-auto-var-init=pattern for this.

Richard Sandiford raised the same question in the previous review.
And this behavior also follows Clang’s behavior.

The following is the answer from Kees Cook on this question:

=====

Originally, Clang
implemented using pattern, but there was discussion around it and the
decision there was to go with zero init, as it seemed to more closely
match the C spec:
https://github.com/llvm/llvm-project/commit/d39fbc7e20d84364e409ce59724ce20625637062

=====


+enum auto_init_approach {
+  AUTO_INIT_A = 0,
+  AUTO_INIT_D = 1
+};

I'm assuming we're going for one implementation in the end - have
you made up your mind yet?

Yes, I already decided to take the approach D. (Adding call to internal function .DEFFERED_INIT).

The reason to temporarily keep both implementations is just for the convenience to run some
Performance comparison during the implementation period. I am afraid that I might need some
Changes for approach D during the review process, in case there might be major change, we
need to run the performance testing again.

So, before the last version, I will just keep both implementations.

If all the change is good, I will complete delete approach A at that time.
Is this okay?



+/* If FOR_UNINIT is true, GIMPLE_CALL S is a call to builtin_memset that
+   is known to be emitted for unintialized VLA objects.  */
+
+static inline void
+gimple_call_set_memset_for_uninit (gcall *s, bool for_uninit)

seeing this, can you explain why using .DEFERRED_INIT does not
work for VLAs?

The major reason for going different routes for VLAs vs. no-VLAs is:

In the original gimplification phase, VLAs and no-VLAs go different routes.
I just followed the different routes for them:

In “gimplify_decl_expr”, VLA goes to “gimplify_vla_decl”, and is expanded to
call to alloca.  Naturally, I add calls to “memset/memcpy” in “gimplify_vla_decl” to
Initialize it.

On the other hand, no-VLAs are handled differently in “gimplify_decl_expr”, so
I added calls to “.DEFFERED_INIT” to initialize them.

What’s the major issue if I add calls to “memset/memcpy” in “gimplify_vla_decl” to
Initialize VLAs?

 You can build

 .DEFERRED_INIT (WITH_SIZE_EXPR <decl, size-expression>, type)

to carry the initialization size.  There's maybe_with_size_expr that
you can conveniently use to perform the WITH_SIZE_EXPR wrapping.
I'd strongly prefer not going different routes for VLAs vs. on-VLAs.

What’s the major benefit to this?


@@ -5001,6 +5185,17 @@ gimplify_init_constructor (tree *expr_p, gimple_seq
*pre_p, gimple_seq *post_p,
         /* If a single access to the target must be ensured and all
elements
            are zero, then it's optimal to clear whatever their number.
*/
         cleared = true;
+       else if (flag_trivial_auto_var_init > AUTO_INIT_UNINITIALIZED
+                && !TREE_STATIC (object)
+                && type_has_padding (type))
+         /* If the user requests to initialize automatic variables with
+            paddings inside the type, we should initialize the paddings
too.
+            C guarantees that brace-init with fewer initializers than
members
+            aggregate will initialize the rest of the aggregate as-if it
were
+            static initialization.  In turn static initialization
guarantees
+            that pad is initialized to zero bits.
+            So, it's better to clear the whole record under such
situation.  */
+         cleared = true;

so here we have padding as well - I think this warrants to be controlled
by an extra option?  And we can maybe split this out to a separate
patch? (the whole padding stuff)

Clang does the padding initialization with this option, shall we be consistent with Clang?


+/* Expand the IFN_DEFERRED_INIT function according to its second
argument.  */
+static void
+expand_DEFERRED_INIT (internal_fn, gcall *stmt)
+{
+  tree var = gimple_call_lhs (stmt);
+  tree init = NULL_TREE;
+  enum auto_init_type init_type
+    = (enum auto_init_type) TREE_INT_CST_LOW (gimple_call_arg (stmt, 1));
+
+  switch (init_type)
+    {
+    default:
+      gcc_unreachable ();
+    case AUTO_INIT_PATTERN:
+      init = build_pattern_cst_for_auto_init (TREE_TYPE (var));
+      expand_assignment (var, init, false);
+      break;
+    case AUTO_INIT_ZERO:
+      init = build_zero_cst (TREE_TYPE (var));
+      expand_assignment (var, init, false);
+      break;
+    }

I think actually building build_pattern_cst_for_auto_init can generate
massive garbage and for big auto vars code size is also a concern and
ideally on x86 you'd produce rep movq.  So I don't think going
via expand_assignment is good.  Instead you possibly want to lower
.DEFERRED_INIT to MEMs following expand_builtin_memset and
eventually enhance that to allow storing pieces larger than a byte.

Will study this approach a little bit more, might need more help from you on this part.


diff --git a/gcc/tree-core.h b/gcc/tree-core.h
index e457b917b98e..2e0e76ea8838 100644
--- a/gcc/tree-core.h
+++ b/gcc/tree-core.h
@@ -1829,7 +1829,7 @@ struct GTY(()) tree_decl_with_vis {
 unsigned final : 1;
 /* Belong to FUNCTION_DECL exclusively.  */
 unsigned regdecl_flag : 1;
- /* 14 unused bits. */
+ /* 14 unused bits.  */
 /* 32 more unused on 64 bit HW. */
};


spurious change, please drop.

Okay.


+  /* Ignore REALPART_EXPR or IMAGPART_EXPR if its operand is a call to
+     .DEFERRED_INIT.  This is for handling the following case correctly:
+
+  1 typedef _Complex float C;
+  2 C foo(int cond)
+  3 {
+  4   C f;
+  5   __imag__ f = 0;
+  6   if (cond)
+  7     {
+  8       __real__ f = 1;
+  9       return f;
+ 10     }
+ 11   return f;
+ 12 }
+
+    with -ftrivial-auto-var-init, compiler will insert the following
+    artificial initialization at line 4:
+  f = .DEFERRED_INIT (f, 2);
+  _1 = REALPART_EXPR <f>;
+
+    without the following special handling, _1 = REALPART_EXPR <f> will
+    be treated as the uninitialized use point, which is incorrect. (the
+    real uninitialized use point is at line 11).  */
+  if (is_gimple_assign (context)
+      && (gimple_assign_rhs_code (context) == REALPART_EXPR
+         || gimple_assign_rhs_code (context) == IMAGPART_EXPR))
+    {
+      tree v = gimple_assign_rhs1 (context);
+      if (TREE_CODE (TREE_OPERAND (v, 0)) == SSA_NAME
+         && gimple_call_internal_p (SSA_NAME_DEF_STMT (TREE_OPERAND (v,
0)),
+                                    IFN_DEFERRED_INIT))
+       return;
+    }

will this not mishandle (not report)

C foo ()
{
 C f;
 return __real f;
}

?  I think ssa_undefined_value_p is supposed to catch this, you
seem to duplicate something there as well.

Will check on this.


+/* Returns true when the given TYPE has padding inside it.
+   return false otherwise.  */
+bool
+type_has_padding (tree type)
+{
+  switch (TREE_CODE (type))
+    {
+    case RECORD_TYPE:
+      {

btw, there's __builtin_clear_padding and a whole machinery around
it in gimple-fold.c, I'm sure that parts could be re-used if they
are neccessary in the end.

Richard Sandiford provided this suggestion previously, my previous study shows that it might not
Be convenient to use it. But I will study this a little bit more and get back to you.


Otherwise the changes look OK.

Do DCE/DSE remove unused .DEFERRED_INIT?

It should, but I will double check on this.

Thanks again.

Qing

Thanks,
Richard.


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH][version 3]add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-05-26 11:18 ` Richard Biener
  2021-05-27 19:44   ` Qing Zhao
@ 2021-05-27 21:42   ` Qing Zhao
  2021-06-03 20:14   ` Qing Zhao
                     ` (2 subsequent siblings)
  4 siblings, 0 replies; 57+ messages in thread
From: Qing Zhao @ 2021-05-27 21:42 UTC (permalink / raw)
  To: Richard Biener; +Cc: richard Sandiford, kees Cook, gcc-patches Qing Zhao via

(Resend, the previous version messed up your questions and my answers, hopefully this time it’s better)

Hi, Richard,

Thanks a lot for your comments.

On May 26, 2021, at 6:18 AM, Richard Biener <rguenther@suse.de<mailto:rguenther@suse.de>> wrote:

On Wed, 12 May 2021, Qing Zhao wrote:

Hi,

This is the 3rd version of the patch for the new security feature for GCC.

Please take look and let me know your comments and suggestions.

thanks.

Qing

******Compare with the 2nd version, the following are the major changes:

1. use "lookup_attribute ("uninitialized",) directly instead of adding
  one new field "uninitialized" into tree_decl_with_vis.
2. update documentation to mention that the new option will not confuse
  -Wuninitialized, GCC still consider an auto without explicit initializer
  as uninitialized.
3. change the name of "build_pattern_cst" to more specific name as
  "build_pattern_cst_for_auto_init".
4. handling of nested VLA;
  Adding new testing cases (auto-init-15/16.c) for this new handling.
5. Add  new verifications of calls to .DEFERRED_INIT in tree-cfg.c;
6. in tree-sra.c, update the handling of "grp_to_be_debug_replaced",
  bind the lhs variable to a call to .DEFERRED_INIT.
7. In tree-ssa-structalias.c, delete "find_func_aliases_for_deferred_init",
  return directly for a call to .DEFERRED_INIT in "find_func_aliases_for_call".
8. Add more detailed comments in tree-ssa-uninit.c and tree-ssa.c to explain
  the special handling on REALPART_EXPR/IMAGPRT_EXPR.
9. in build_pattern_cst_for_auto_init:
  BOOLEAN_TYPE will be set to zero always;
  INTEGER_TYPE (?and ENUMERAL_TYPE) use wi::from_buffer in order to
               correctly handle 128-bit integers.
  POINTER_TYPE will not assert on SIZE < 32.
  REAL_TYPE add fallback;
10. changed gcc_assert to gcc_unreachable in several places;
11. add more comments;
12. some style issue changes.

******Please see the version 2 at:
https://gcc.gnu.org/pipermail/gcc-patches/2021-March/567262.html


******The following 2 items are the ones I didn’t addressed in this version due to further study and might need more discussion:

1. Using __builtin_clear_padding  to replace type_has_padding.

My study shows: the call to __builtin_clear_padding is expanded during gimplification phase.
And there is no __bultin_clear_padding expanding during rtx expanding phase.
If so,  for -ftrivial-auto-var-init, padding initialization should be done both in gimplification phase and rtx expanding phase.
And since the __builtin_clear_padding might not be good for rtx expanding, reusing __builtin_clear_padding might not work.

2. Pattern init to NULLPTR_TYPE and ENUMERAL_TYPE: need more comments from Richard Biener on this.

******The change of the 3rd version compared to the 2nd version are:


+@item -ftrivial-auto-var-init=@var{choice}
+@opindex ftrivial-auto-var-init
+Initialize automatic variables with either a pattern or with zeroes to
increase
+the security and predictability of a program by preventing uninitialized
memory
+disclosure and use.

the docs do not state what "trivial" actually means?  Does it affect
C++ classes with ctors, thus is "trivial" equal to what C++ considers
a POD type?


Thank you for this question.

The name -ftrivial-auto-var-init is just for compatible with Clang. I really don’t know why
they added trivial.

As I checked a small example with C++ class with ctors, I see both Clang and my patch add
Initialization to this class:

=====
#include <iostream>

using namespace std;

class Line {
  public:
     void setLength( double len );
     double getLength( void );
     Line();  // This is the constructor
  private:
     double length;
};

// Member functions definitions including constructor
Line::Line(void) {
  cout << "Object is being created" << endl;
}
void Line::setLength( double len ) {
 length = len;
}
double Line::getLength( void ) {
 return length;
}

// Main function for the program
int main() {
 Line line;

 // set line length
 line.setLength(6.0);
 cout << "Length of line : " << line.getLength() <<endl;

 return 0;
}

=====

Both clang and my patch add initialization to the above auto variable “line”.

So, I have the following questions need help:

1. Do we need to exclude C++ class with ctor from auto initialization?

2. I see Clang use call to internal memset to initialize such class, but for my patch, I only initialize the data fields inside this class.
   Which one is better?


diff --git a/gcc/expr.c b/gcc/expr.c
index 798285eb52ca..9092349d7017 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -6539,14 +6539,19 @@ store_constructor (tree exp, rtx target, int
cleared, poly_int64 size,
           cleared = 1;
         }

-        /* If the constructor has fewer fields than the structure or
-          if we are initializing the structure to mostly zeros, clear
-          the whole structure first.  Don't do this if TARGET is a
-          register whose mode size isn't equal to SIZE since
-          clear_storage can't handle this case.  */
+       /* If the constructor has fewer fields than the structure,
+          or if we are initializing the structure to mostly zeros,
+          or if the user requests to initialize automatic variables with
+          paddings inside the type,
+          we should clear the whole structure first.
+          Don't do this if TARGET is a register whose mode size isn't
equal
+          SIZE since clear_storage can't handle this case.  */
       else if (known_size_p (size)
                && (((int) CONSTRUCTOR_NELTS (exp) != fields_length
(type))
-                    || mostly_zeros_p (exp))
+                    || mostly_zeros_p (exp)
+                    || (flag_trivial_auto_var_init >
AUTO_INIT_UNINITIALIZED
+                        && !TREE_STATIC (exp)
+                        && type_has_padding (type)))

testing flag_trivial_auto_var_init tests the global options, if TUs
are compiled with different setting of flag_trivial_auto_var_init
and you use LTO or flag_trivial_auto_var_init is specified per
function via optimize attributes it's more appropriate to test
opt_for_fn (cfun->decl, flag_trivial_auto_var_init)


Okay.  Thanks for the info. I will update this.


You do not actually test whether TARGET is an auto-var in this place,
so I question this change

Will add checking for Auto on this.

- the documentation of ftrivial-auto-var-init
also doesn't mention initialization of padding

Will add initialization of padding on this.
Clang add the padding initialization with this option, I guess that we might need to
be compatible with it?

and the above doesn't
seem to honor -ftrivial-auto-var-init=pattern for this.


Richard Sandiford raised the same question in the previous review.
And this behavior also follows Clang’s behavior.

The following is the answer from Kees Cook on this question:

=====

Originally, Clang
implemented using pattern, but there was discussion around it and the
decision there was to go with zero init, as it seemed to more closely
match the C spec:
https://github.com/llvm/llvm-project/commit/d39fbc7e20d84364e409ce59724ce20625637062

=====


+enum auto_init_approach {
+  AUTO_INIT_A = 0,
+  AUTO_INIT_D = 1
+};

I'm assuming we're going for one implementation in the end - have
you made up your mind yet?

Yes, I already decided to take the approach D. (Adding call to internal function .DEFFERED_INIT).

The reason to temporarily keep both implementations is just for the convenience to run some
Performance comparison during the implementation period. I am afraid that I might need some
Changes for approach D during the review process, in case there might be major change, we
need to run the performance testing again.

So, before the last version, I will just keep both implementations.

If all the change is good, I will complete delete approach A at that time.
Is this okay?


+/* If FOR_UNINIT is true, GIMPLE_CALL S is a call to builtin_memset that
+   is known to be emitted for unintialized VLA objects.  */
+
+static inline void
+gimple_call_set_memset_for_uninit (gcall *s, bool for_uninit)

seeing this, can you explain why using .DEFERRED_INIT does not
work for VLAs?

The major reason for going different routes for VLAs vs. no-VLAs is:

In the original gimplification phase, VLAs and no-VLAs go different routes.
I just followed the different routes for them:

In “gimplify_decl_expr”, VLA goes to “gimplify_vla_decl”, and is expanded to
call to alloca.  Naturally, I add calls to “memset/memcpy” in “gimplify_vla_decl” to
Initialize it.

On the other hand, no-VLAs are handled differently in “gimplify_decl_expr”, so
I added calls to “.DEFFERED_INIT” to initialize them.

What’s the major issue if I add calls to “memset/memcpy” in “gimplify_vla_decl” to
Initialize VLAs?


 You can build

 .DEFERRED_INIT (WITH_SIZE_EXPR <decl, size-expression>, type)

to carry the initialization size.  There's maybe_with_size_expr that
you can conveniently use to perform the WITH_SIZE_EXPR wrapping.
I'd strongly prefer not going different routes for VLAs vs. on-VLAs.

What’s the major benefit to this?


@@ -5001,6 +5185,17 @@ gimplify_init_constructor (tree *expr_p, gimple_seq
*pre_p, gimple_seq *post_p,
         /* If a single access to the target must be ensured and all
elements
            are zero, then it's optimal to clear whatever their number.
*/
         cleared = true;
+       else if (flag_trivial_auto_var_init > AUTO_INIT_UNINITIALIZED
+                && !TREE_STATIC (object)
+                && type_has_padding (type))
+         /* If the user requests to initialize automatic variables with
+            paddings inside the type, we should initialize the paddings
too.
+            C guarantees that brace-init with fewer initializers than
members
+            aggregate will initialize the rest of the aggregate as-if it
were
+            static initialization.  In turn static initialization
guarantees
+            that pad is initialized to zero bits.
+            So, it's better to clear the whole record under such
situation.  */
+         cleared = true;

so here we have padding as well - I think this warrants to be controlled
by an extra option?  And we can maybe split this out to a separate
patch? (the whole padding stuff)

Clang does the padding initialization with this option, shall we be consistent with Clang?


+/* Expand the IFN_DEFERRED_INIT function according to its second
argument.  */
+static void
+expand_DEFERRED_INIT (internal_fn, gcall *stmt)
+{
+  tree var = gimple_call_lhs (stmt);
+  tree init = NULL_TREE;
+  enum auto_init_type init_type
+    = (enum auto_init_type) TREE_INT_CST_LOW (gimple_call_arg (stmt, 1));
+
+  switch (init_type)
+    {
+    default:
+      gcc_unreachable ();
+    case AUTO_INIT_PATTERN:
+      init = build_pattern_cst_for_auto_init (TREE_TYPE (var));
+      expand_assignment (var, init, false);
+      break;
+    case AUTO_INIT_ZERO:
+      init = build_zero_cst (TREE_TYPE (var));
+      expand_assignment (var, init, false);
+      break;
+    }

I think actually building build_pattern_cst_for_auto_init can generate
massive garbage and for big auto vars code size is also a concern and
ideally on x86 you'd produce rep movq.  So I don't think going
via expand_assignment is good.  Instead you possibly want to lower
.DEFERRED_INIT to MEMs following expand_builtin_memset and
eventually enhance that to allow storing pieces larger than a byte.

Will study this approach a little bit more, might need more help from you on this part.


diff --git a/gcc/tree-core.h b/gcc/tree-core.h
index e457b917b98e..2e0e76ea8838 100644
--- a/gcc/tree-core.h
+++ b/gcc/tree-core.h
@@ -1829,7 +1829,7 @@ struct GTY(()) tree_decl_with_vis {
 unsigned final : 1;
 /* Belong to FUNCTION_DECL exclusively.  */
 unsigned regdecl_flag : 1;
- /* 14 unused bits. */
+ /* 14 unused bits.  */
 /* 32 more unused on 64 bit HW. */
};


spurious change, please drop.

Okay.


+  /* Ignore REALPART_EXPR or IMAGPART_EXPR if its operand is a call to
+     .DEFERRED_INIT.  This is for handling the following case correctly:
+
+  1 typedef _Complex float C;
+  2 C foo(int cond)
+  3 {
+  4   C f;
+  5   __imag__ f = 0;
+  6   if (cond)
+  7     {
+  8       __real__ f = 1;
+  9       return f;
+ 10     }
+ 11   return f;
+ 12 }
+
+    with -ftrivial-auto-var-init, compiler will insert the following
+    artificial initialization at line 4:
+  f = .DEFERRED_INIT (f, 2);
+  _1 = REALPART_EXPR <f>;
+
+    without the following special handling, _1 = REALPART_EXPR <f> will
+    be treated as the uninitialized use point, which is incorrect. (the
+    real uninitialized use point is at line 11).  */
+  if (is_gimple_assign (context)
+      && (gimple_assign_rhs_code (context) == REALPART_EXPR
+         || gimple_assign_rhs_code (context) == IMAGPART_EXPR))
+    {
+      tree v = gimple_assign_rhs1 (context);
+      if (TREE_CODE (TREE_OPERAND (v, 0)) == SSA_NAME
+         && gimple_call_internal_p (SSA_NAME_DEF_STMT (TREE_OPERAND (v,
0)),
+                                    IFN_DEFERRED_INIT))
+       return;
+    }

will this not mishandle (not report)

C foo ()
{
 C f;
 return __real f;
}

?  I think ssa_undefined_value_p is supposed to catch this, you
seem to duplicate something there as well.

Will check on this.


+/* Returns true when the given TYPE has padding inside it.
+   return false otherwise.  */
+bool
+type_has_padding (tree type)
+{
+  switch (TREE_CODE (type))
+    {
+    case RECORD_TYPE:
+      {

btw, there's __builtin_clear_padding and a whole machinery around
it in gimple-fold.c, I'm sure that parts could be re-used if they
are neccessary in the end.

Richard Sandiford provided this suggestion previously, my previous study shows that it might not
Be convenient to use it. But I will study this a little bit more and get back to you.


Otherwise the changes look OK.

Do DCE/DSE remove unused .DEFERRED_INIT?

It should, but I will double check on this.

Thanks again.

Qing



Thanks,
Richard.




^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH][version 3]add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-05-26 11:18 ` Richard Biener
  2021-05-27 19:44   ` Qing Zhao
  2021-05-27 21:42   ` Qing Zhao
@ 2021-06-03 20:14   ` Qing Zhao
  2021-06-07  7:50     ` Richard Biener
  2021-06-03 20:18   ` Qing Zhao
  2021-06-10 21:11   ` Qing Zhao
  4 siblings, 1 reply; 57+ messages in thread
From: Qing Zhao @ 2021-06-03 20:14 UTC (permalink / raw)
  To: Richard Biener; +Cc: richard Sandiford, kees Cook, gcc-patches Qing Zhao via

Hi, Richard,

For the following, I need more clarification:



+/* Expand the IFN_DEFERRED_INIT function according to its second
argument.  */
+static void
+expand_DEFERRED_INIT (internal_fn, gcall *stmt)
+{
+  tree var = gimple_call_lhs (stmt);
+  tree init = NULL_TREE;
+  enum auto_init_type init_type
+    = (enum auto_init_type) TREE_INT_CST_LOW (gimple_call_arg (stmt, 1));
+
+  switch (init_type)
+    {
+    default:
+      gcc_unreachable ();
+    case AUTO_INIT_PATTERN:
+      init = build_pattern_cst_for_auto_init (TREE_TYPE (var));
+      expand_assignment (var, init, false);
+      break;
+    case AUTO_INIT_ZERO:
+      init = build_zero_cst (TREE_TYPE (var));
+      expand_assignment (var, init, false);
+      break;
+    }

I think actually building build_pattern_cst_for_auto_init can generate
massive garbage and for big auto vars code size is also a concern and
ideally on x86 you'd produce rep movq.  So I don't think going
via expand_assignment is good.  Instead you possibly want to lower
.DEFERRED_INIT to MEMs following expand_builtin_memset and
eventually enhance that to allow storing pieces larger than a byte.


I will lower .DEFFERED_INIT to MEMS following expand_builtin_memset for “AUTO_INIT_PATTERN”.
My question is:
Do I need to do the same for “AUTO_INIT_ZERO”?

Thanks.

Qing


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH][version 3]add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-05-26 11:18 ` Richard Biener
                     ` (2 preceding siblings ...)
  2021-06-03 20:14   ` Qing Zhao
@ 2021-06-03 20:18   ` Qing Zhao
  2021-06-07  7:53     ` Richard Biener
  2021-06-10 21:11   ` Qing Zhao
  4 siblings, 1 reply; 57+ messages in thread
From: Qing Zhao @ 2021-06-03 20:18 UTC (permalink / raw)
  To: Richard Biener; +Cc: richard Sandiford, kees Cook, gcc-patches Qing Zhao via

Hi, Richard,


On May 26, 2021, at 6:18 AM, Richard Biener <rguenther@suse.de<mailto:rguenther@suse.de>> wrote:

On Wed, 12 May 2021, Qing Zhao wrote:

Hi,

This is the 3rd version of the patch for the new security feature for GCC.

Please take look and let me know your comments and suggestions.


+/* Returns true when the given TYPE has padding inside it.
+   return false otherwise.  */
+bool
+type_has_padding (tree type)
+{
+  switch (TREE_CODE (type))
+    {
+    case RECORD_TYPE:
+      {

btw, there's __builtin_clear_padding and a whole machinery around
it in gimple-fold.c, I'm sure that parts could be re-used if they
are neccessary in the end.

To address the above suggestion:

My study shows: the call to __builtin_clear_padding is expanded during gimplification phase.
And there is no __bultin_clear_padding expanding during rtx expanding phase.
However, for -ftrivial-auto-var-init, padding initialization should be done both in gimplification phase and rtx expanding phase.
since the __builtin_clear_padding might not be good for rtx expanding, reusing __builtin_clear_padding might not work.

Let me know if you have any more comments on this.

Thanks.

Qing

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH][version 3]add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-05-27 19:44   ` Qing Zhao
@ 2021-06-07  7:48     ` Richard Biener
  2021-06-07 16:13       ` Qing Zhao
  2021-06-07 23:45       ` Kees Cook
  0 siblings, 2 replies; 57+ messages in thread
From: Richard Biener @ 2021-06-07  7:48 UTC (permalink / raw)
  To: Qing Zhao; +Cc: richard Sandiford, kees Cook, gcc-patches Qing Zhao via

On Thu, 27 May 2021, Qing Zhao wrote:

> Hi, Richard,
> 
> Thanks a lot for your comments.
> 
> 
> On May 26, 2021, at 6:18 AM, Richard Biener <rguenther@suse.de<mailto:rguenther@suse.de>> wrote:
> 
> On Wed, 12 May 2021, Qing Zhao wrote:
> 
> Hi,
> 
> This is the 3rd version of the patch for the new security feature for GCC.

Meh - can you try using a mailer that does proper quoting?  It's difficult
to spot your added comments.  Will try anyway (and sorry for the delay)

> Please take look and let me know your comments and suggestions.
> 
> thanks.
> 
> Qing
> 
> ******Compare with the 2nd version, the following are the major changes:
> 
> 1. use "lookup_attribute ("uninitialized",) directly instead of adding
>   one new field "uninitialized" into tree_decl_with_vis.
> 2. update documentation to mention that the new option will not confuse
>   -Wuninitialized, GCC still consider an auto without explicit initializer
>   as uninitialized.
> 3. change the name of "build_pattern_cst" to more specific name as
>   "build_pattern_cst_for_auto_init".
> 4. handling of nested VLA;
>   Adding new testing cases (auto-init-15/16.c) for this new handling.
> 5. Add  new verifications of calls to .DEFERRED_INIT in tree-cfg.c;
> 6. in tree-sra.c, update the handling of "grp_to_be_debug_replaced",
>   bind the lhs variable to a call to .DEFERRED_INIT.
> 7. In tree-ssa-structalias.c, delete "find_func_aliases_for_deferred_init",
>   return directly for a call to .DEFERRED_INIT in "find_func_aliases_for_call".
> 8. Add more detailed comments in tree-ssa-uninit.c and tree-ssa.c to explain
>   the special handling on REALPART_EXPR/IMAGPRT_EXPR.
> 9. in build_pattern_cst_for_auto_init:
>   BOOLEAN_TYPE will be set to zero always;
>   INTEGER_TYPE (?and ENUMERAL_TYPE) use wi::from_buffer in order to
>                correctly handle 128-bit integers.
>   POINTER_TYPE will not assert on SIZE < 32.
>   REAL_TYPE add fallback;
> 10. changed gcc_assert to gcc_unreachable in several places;
> 11. add more comments;
> 12. some style issue changes.
> 
> ******Please see the version 2 at:
> https://gcc.gnu.org/pipermail/gcc-patches/2021-March/567262.html
> 
> 
> ******The following 2 items are the ones I didn’t addressed in this version due to further study and might need more discussion:
> 
> 1. Using __builtin_clear_padding  to replace type_has_padding.
> 
> My study shows: the call to __builtin_clear_padding is expanded during gimplification phase.
> And there is no __bultin_clear_padding expanding during rtx expanding phase.
> If so,  for -ftrivial-auto-var-init, padding initialization should be done both in gimplification phase and rtx expanding phase.
> And since the __builtin_clear_padding might not be good for rtx expanding, reusing __builtin_clear_padding might not work.
> 
> 2. Pattern init to NULLPTR_TYPE and ENUMERAL_TYPE: need more comments from Richard Biener on this.
> 
> ******The change of the 3rd version compared to the 2nd version are:
> 
> 
> +@item -ftrivial-auto-var-init=@var{choice}
> +@opindex ftrivial-auto-var-init
> +Initialize automatic variables with either a pattern or with zeroes to
> increase
> +the security and predictability of a program by preventing uninitialized
> memory
> +disclosure and use.
> 
> the docs do not state what "trivial" actually means?  Does it affect
> C++ classes with ctors, thus is "trivial" equal to what C++ considers
> a POD type?
> 
> Thank you for this question.
> 
> The name -ftrivial-auto-var-init is just for compatible with Clang. I really don’t know why
> they added trivial.
> 
> As I checked a small example with C++ class with ctors, I see both Clang and my patch add
> Initialization to this class:
> 
> =====
> #include <iostream>
> 
> using namespace std;
> 
> class Line {
>    public:
>       void setLength( double len );
>       double getLength( void );
>       Line();  // This is the constructor
>    private:
>       double length;
> };
> 
> // Member functions definitions including constructor
> Line::Line(void) {
>    cout << "Object is being created" << endl;
> }
> void Line::setLength( double len ) {
>   length = len;
> }
> double Line::getLength( void ) {
>   return length;
> }
> 
> // Main function for the program
> int main() {
>   Line line;
> 
>   // set line length
>   line.setLength(6.0);
>   cout << "Length of line : " << line.getLength() <<endl;
> 
>   return 0;
> }
> 
> =====
> 
> Both clang and my patch add initialization to the above auto variable “line”.
> 
> So, I have the following questions need help:
> 
> 1. Do we need to exclude C++ class with ctor from auto initialization?
> 
> 2. I see Clang use call to internal memset to initialize such class, but for my patch, I only initialize the data fields inside this class.
>     Which one is better?

I can't answer either question, but generally using block-initialization
(for example via memset, but we'd generally prefer X = {}) is better for
later optimization.

> 
> 
> diff --git a/gcc/expr.c b/gcc/expr.c
> index 798285eb52ca..9092349d7017 100644
> --- a/gcc/expr.c
> +++ b/gcc/expr.c
> @@ -6539,14 +6539,19 @@ store_constructor (tree exp, rtx target, int
> cleared, poly_int64 size,
>            cleared = 1;
>          }
> 
> -        /* If the constructor has fewer fields than the structure or
> -          if we are initializing the structure to mostly zeros, clear
> -          the whole structure first.  Don't do this if TARGET is a
> -          register whose mode size isn't equal to SIZE since
> -          clear_storage can't handle this case.  */
> +       /* If the constructor has fewer fields than the structure,
> +          or if we are initializing the structure to mostly zeros,
> +          or if the user requests to initialize automatic variables with
> +          paddings inside the type,
> +          we should clear the whole structure first.
> +          Don't do this if TARGET is a register whose mode size isn't
> equal
> +          SIZE since clear_storage can't handle this case.  */
>        else if (known_size_p (size)
>                 && (((int) CONSTRUCTOR_NELTS (exp) != fields_length
> (type))
> -                    || mostly_zeros_p (exp))
> +                    || mostly_zeros_p (exp)
> +                    || (flag_trivial_auto_var_init >
> AUTO_INIT_UNINITIALIZED
> +                        && !TREE_STATIC (exp)
> +                        && type_has_padding (type)))
> 
> testing flag_trivial_auto_var_init tests the global options, if TUs
> are compiled with different setting of flag_trivial_auto_var_init
> and you use LTO or flag_trivial_auto_var_init is specified per
> function via optimize attributes it's more appropriate to test
> opt_for_fn (cfun->decl, flag_trivial_auto_var_init)
> 
> Okay.  Thanks for the info. I will update this.
> 
> 
> You do not actually test whether TARGET is an auto-var in this place,
> so I question this change
> 
> Will add checking for Auto on this.
> 
> - the documentation of ftrivial-auto-var-init
> also doesn't mention initialization of padding
> 
> Will add initialization of padding on this.
> 
> Clang add the padding initialization with this option, I guess that we might need to
> be compatible with it?
> 
> and the above doesn't
> seem to honor -ftrivial-auto-var-init=pattern for this.
> 
> Richard Sandiford raised the same question in the previous review.
> And this behavior also follows Clang’s behavior.
> 
> The following is the answer from Kees Cook on this question:
> 
> =====
> 
> Originally, Clang
> implemented using pattern, but there was discussion around it and the
> decision there was to go with zero init, as it seemed to more closely
> match the C spec:
> https://github.com/llvm/llvm-project/commit/d39fbc7e20d84364e409ce59724ce20625637062
> 
> =====
> 
> 
> +enum auto_init_approach {
> +  AUTO_INIT_A = 0,
> +  AUTO_INIT_D = 1
> +};
> 
> I'm assuming we're going for one implementation in the end - have
> you made up your mind yet?
> 
> Yes, I already decided to take the approach D. (Adding call to internal function .DEFFERED_INIT).
> 
> The reason to temporarily keep both implementations is just for the convenience to run some
> Performance comparison during the implementation period. I am afraid that I might need some
> Changes for approach D during the review process, in case there might be major change, we
> need to run the performance testing again.
> 
> So, before the last version, I will just keep both implementations.
> 
> If all the change is good, I will complete delete approach A at that time.
> Is this okay?

OK.

> 
> 
> +/* If FOR_UNINIT is true, GIMPLE_CALL S is a call to builtin_memset that
> +   is known to be emitted for unintialized VLA objects.  */
> +
> +static inline void
> +gimple_call_set_memset_for_uninit (gcall *s, bool for_uninit)
> 
> seeing this, can you explain why using .DEFERRED_INIT does not
> work for VLAs?
> 
> The major reason for going different routes for VLAs vs. no-VLAs is:
> 
> In the original gimplification phase, VLAs and no-VLAs go different routes.
> I just followed the different routes for them:
> 
> In “gimplify_decl_expr”, VLA goes to “gimplify_vla_decl”, and is expanded to
> call to alloca.  Naturally, I add calls to “memset/memcpy” in “gimplify_vla_decl” to
> Initialize it.
> 
> On the other hand, no-VLAs are handled differently in “gimplify_decl_expr”, so
> I added calls to “.DEFFERED_INIT” to initialize them.
> 
> What’s the major issue if I add calls to “memset/memcpy” in “gimplify_vla_decl” to
> Initialize VLAs?

Just inconsistency and unexpected different behavior with respect to
uninitialized warnings?

>  You can build
> 
>  .DEFERRED_INIT (WITH_SIZE_EXPR <decl, size-expression>, type)
> 
> to carry the initialization size.  There's maybe_with_size_expr that
> you can conveniently use to perform the WITH_SIZE_EXPR wrapping.
> I'd strongly prefer not going different routes for VLAs vs. on-VLAs.
> 
> What’s the major benefit to this?

See above.

> 
> @@ -5001,6 +5185,17 @@ gimplify_init_constructor (tree *expr_p, gimple_seq
> *pre_p, gimple_seq *post_p,
>          /* If a single access to the target must be ensured and all
> elements
>             are zero, then it's optimal to clear whatever their number.
> */
>          cleared = true;
> +       else if (flag_trivial_auto_var_init > AUTO_INIT_UNINITIALIZED
> +                && !TREE_STATIC (object)
> +                && type_has_padding (type))
> +         /* If the user requests to initialize automatic variables with
> +            paddings inside the type, we should initialize the paddings
> too.
> +            C guarantees that brace-init with fewer initializers than
> members
> +            aggregate will initialize the rest of the aggregate as-if it
> were
> +            static initialization.  In turn static initialization
> guarantees
> +            that pad is initialized to zero bits.
> +            So, it's better to clear the whole record under such
> situation.  */
> +         cleared = true;
> 
> so here we have padding as well - I think this warrants to be controlled
> by an extra option?  And we can maybe split this out to a separate
> patch? (the whole padding stuff)
> 
> Clang does the padding initialization with this option, shall we be 
> consistent with Clang?

Just for the sake of consistency?  No.  Is there a technical reason
for this complication?  Say we have

  struct { short s; int i; } a;

what's the technical reason to initialize the padding?  I might
be tempted to use -ftrivial-auto-init but I'd definitely don't
want to spend cycles/instructions initializing the padding in the
above struct.

At this point I also wonder whether doing the actual initialization
by block-initializing the current function frame at allocation
time.  That would be a way smaller patch (but possibly backend
specific).  On x86 it could be a single rep mov; for all but the
VLA cases.  Just a thought.

> +/* Expand the IFN_DEFERRED_INIT function according to its second
> argument.  */
> +static void
> +expand_DEFERRED_INIT (internal_fn, gcall *stmt)
> +{
> +  tree var = gimple_call_lhs (stmt);
> +  tree init = NULL_TREE;
> +  enum auto_init_type init_type
> +    = (enum auto_init_type) TREE_INT_CST_LOW (gimple_call_arg (stmt, 1));
> +
> +  switch (init_type)
> +    {
> +    default:
> +      gcc_unreachable ();
> +    case AUTO_INIT_PATTERN:
> +      init = build_pattern_cst_for_auto_init (TREE_TYPE (var));
> +      expand_assignment (var, init, false);
> +      break;
> +    case AUTO_INIT_ZERO:
> +      init = build_zero_cst (TREE_TYPE (var));
> +      expand_assignment (var, init, false);
> +      break;
> +    }
> 
> I think actually building build_pattern_cst_for_auto_init can generate
> massive garbage and for big auto vars code size is also a concern and
> ideally on x86 you'd produce rep movq.  So I don't think going
> via expand_assignment is good.  Instead you possibly want to lower
> .DEFERRED_INIT to MEMs following expand_builtin_memset and
> eventually enhance that to allow storing pieces larger than a byte.
> 
> Will study this approach a little bit more, might need more help from you on this part.
> 
> 
> diff --git a/gcc/tree-core.h b/gcc/tree-core.h
> index e457b917b98e..2e0e76ea8838 100644
> --- a/gcc/tree-core.h
> +++ b/gcc/tree-core.h
> @@ -1829,7 +1829,7 @@ struct GTY(()) tree_decl_with_vis {
>  unsigned final : 1;
>  /* Belong to FUNCTION_DECL exclusively.  */
>  unsigned regdecl_flag : 1;
> - /* 14 unused bits. */
> + /* 14 unused bits.  */
>  /* 32 more unused on 64 bit HW. */
> };
> 
> 
> spurious change, please drop.
> 
> Okay.
> 
> 
> +  /* Ignore REALPART_EXPR or IMAGPART_EXPR if its operand is a call to
> +     .DEFERRED_INIT.  This is for handling the following case correctly:
> +
> +  1 typedef _Complex float C;
> +  2 C foo(int cond)
> +  3 {
> +  4   C f;
> +  5   __imag__ f = 0;
> +  6   if (cond)
> +  7     {
> +  8       __real__ f = 1;
> +  9       return f;
> + 10     }
> + 11   return f;
> + 12 }
> +
> +    with -ftrivial-auto-var-init, compiler will insert the following
> +    artificial initialization at line 4:
> +  f = .DEFERRED_INIT (f, 2);
> +  _1 = REALPART_EXPR <f>;
> +
> +    without the following special handling, _1 = REALPART_EXPR <f> will
> +    be treated as the uninitialized use point, which is incorrect. (the
> +    real uninitialized use point is at line 11).  */
> +  if (is_gimple_assign (context)
> +      && (gimple_assign_rhs_code (context) == REALPART_EXPR
> +         || gimple_assign_rhs_code (context) == IMAGPART_EXPR))
> +    {
> +      tree v = gimple_assign_rhs1 (context);
> +      if (TREE_CODE (TREE_OPERAND (v, 0)) == SSA_NAME
> +         && gimple_call_internal_p (SSA_NAME_DEF_STMT (TREE_OPERAND (v,
> 0)),
> +                                    IFN_DEFERRED_INIT))
> +       return;
> +    }
> 
> will this not mishandle (not report)
> 
> C foo ()
> {
>  C f;
>  return __real f;
> }
> 
> ?  I think ssa_undefined_value_p is supposed to catch this, you
> seem to duplicate something there as well.
> 
> Will check on this.
> 
> 
> +/* Returns true when the given TYPE has padding inside it.
> +   return false otherwise.  */
> +bool
> +type_has_padding (tree type)
> +{
> +  switch (TREE_CODE (type))
> +    {
> +    case RECORD_TYPE:
> +      {
> 
> btw, there's __builtin_clear_padding and a whole machinery around
> it in gimple-fold.c, I'm sure that parts could be re-used if they
> are neccessary in the end.
> 
> Richard Sandiford provided this suggestion previously, my previous study shows that it might not
> Be convenient to use it. But I will study this a little bit more and get back to you.
> 
> 
> Otherwise the changes look OK.
> 
> Do DCE/DSE remove unused .DEFERRED_INIT?
> 
> It should, but I will double check on this.
> 
> Thanks again.
> 
> Qing
> 
> Thanks,
> Richard.
> 
> 

-- 
Richard Biener <rguenther@suse.de>
SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
Germany; GF: Felix Imendörffer; HRB 36809 (AG Nuernberg)

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH][version 3]add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-06-03 20:14   ` Qing Zhao
@ 2021-06-07  7:50     ` Richard Biener
  0 siblings, 0 replies; 57+ messages in thread
From: Richard Biener @ 2021-06-07  7:50 UTC (permalink / raw)
  To: Qing Zhao; +Cc: richard Sandiford, kees Cook, gcc-patches Qing Zhao via

On Thu, 3 Jun 2021, Qing Zhao wrote:

> Hi, Richard,
> 
> For the following, I need more clarification:
> 
> 
> 
> +/* Expand the IFN_DEFERRED_INIT function according to its second
> argument.  */
> +static void
> +expand_DEFERRED_INIT (internal_fn, gcall *stmt)
> +{
> +  tree var = gimple_call_lhs (stmt);
> +  tree init = NULL_TREE;
> +  enum auto_init_type init_type
> +    = (enum auto_init_type) TREE_INT_CST_LOW (gimple_call_arg (stmt, 1));
> +
> +  switch (init_type)
> +    {
> +    default:
> +      gcc_unreachable ();
> +    case AUTO_INIT_PATTERN:
> +      init = build_pattern_cst_for_auto_init (TREE_TYPE (var));
> +      expand_assignment (var, init, false);
> +      break;
> +    case AUTO_INIT_ZERO:
> +      init = build_zero_cst (TREE_TYPE (var));
> +      expand_assignment (var, init, false);
> +      break;
> +    }
> 
> I think actually building build_pattern_cst_for_auto_init can generate
> massive garbage and for big auto vars code size is also a concern and
> ideally on x86 you'd produce rep movq.  So I don't think going
> via expand_assignment is good.  Instead you possibly want to lower
> .DEFERRED_INIT to MEMs following expand_builtin_memset and
> eventually enhance that to allow storing pieces larger than a byte.
> 
> 
> I will lower .DEFFERED_INIT to MEMS following expand_builtin_memset for “AUTO_INIT_PATTERN”.
> My question is:
> Do I need to do the same for “AUTO_INIT_ZERO”?

No, the representation for a general "zero constant" for aggregates is
just a single CONSTRUCTOR node with zero explicit elements and thus
quite optimal.

Richard.

> Thanks.
> 
> Qing
> 

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH][version 3]add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-06-03 20:18   ` Qing Zhao
@ 2021-06-07  7:53     ` Richard Biener
  2021-06-07 16:18       ` Qing Zhao
  0 siblings, 1 reply; 57+ messages in thread
From: Richard Biener @ 2021-06-07  7:53 UTC (permalink / raw)
  To: Qing Zhao; +Cc: richard Sandiford, kees Cook, gcc-patches Qing Zhao via

On Thu, 3 Jun 2021, Qing Zhao wrote:

> Hi, Richard,
> 
> 
> On May 26, 2021, at 6:18 AM, Richard Biener <rguenther@suse.de<mailto:rguenther@suse.de>> wrote:
> 
> On Wed, 12 May 2021, Qing Zhao wrote:
> 
> Hi,
> 
> This is the 3rd version of the patch for the new security feature for GCC.
> 
> Please take look and let me know your comments and suggestions.
> 
> 
> +/* Returns true when the given TYPE has padding inside it.
> +   return false otherwise.  */
> +bool
> +type_has_padding (tree type)
> +{
> +  switch (TREE_CODE (type))
> +    {
> +    case RECORD_TYPE:
> +      {
> 
> btw, there's __builtin_clear_padding and a whole machinery around
> it in gimple-fold.c, I'm sure that parts could be re-used if they
> are neccessary in the end.
> 
> To address the above suggestion:
> 
> My study shows: the call to __builtin_clear_padding is expanded during gimplification phase.
> And there is no __bultin_clear_padding expanding during rtx expanding phase.
> However, for -ftrivial-auto-var-init, padding initialization should be done both in gimplification phase and rtx expanding phase.
> since the __builtin_clear_padding might not be good for rtx expanding, reusing __builtin_clear_padding might not work.
> 
> Let me know if you have any more comments on this.

Yes, I didn't suggest to literally emit calls to __builtin_clear_padding 
but instead to leverage the lowering code, more specifically share the
code that figures _what_ is to be initialized (where the padding is)
and eventually the actual code generation pieces.  That might need some
refactoring but the code where padding resides should be present only
a single time (since it's quite complex).

Which is also why I suggested to split out the padding initialization
bits to a separate patch (and option).

Richard.

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH][version 3]add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-06-07  7:48     ` Richard Biener
@ 2021-06-07 16:13       ` Qing Zhao
  2021-06-08  7:37         ` Richard Biener
  2021-06-07 23:45       ` Kees Cook
  1 sibling, 1 reply; 57+ messages in thread
From: Qing Zhao @ 2021-06-07 16:13 UTC (permalink / raw)
  To: Richard Biener, Kees Cook
  Cc: richard Sandiford, kees Cook, gcc-patches Qing Zhao via

(Kees, can you answer one of Richard’s question below? On the reason to initialize padding of structures)

Richard,


On Jun 7, 2021, at 2:48 AM, Richard Biener <rguenther@suse.de<mailto:rguenther@suse.de>> wrote:

Meh - can you try using a mailer that does proper quoting?  It's difficult
to spot your added comments.  Will try anyway (and sorry for the delay)

Only the email replied to gcc-patch alias had this issue, all the other emails I sent are fine. Not sure why?


Both clang and my patch add initialization to the above auto variable “line”.

So, I have the following questions need help:

1. Do we need to exclude C++ class with ctor from auto initialization?

2. I see Clang use call to internal memset to initialize such class, but for my patch, I only initialize the data fields inside this class.
   Which one is better?

I can't answer either question, but generally using block-initialization
(for example via memset, but we'd generally prefer X = {}) is better for
later optimization.

Okay. So, Is this he same reason as lowering the call to .DEFFERED_INIT through expand_builtin_memset other than expand_assign?


seeing this, can you explain why using .DEFERRED_INIT does not
work for VLAs?

The major reason for going different routes for VLAs vs. no-VLAs is:

In the original gimplification phase, VLAs and no-VLAs go different routes.
I just followed the different routes for them:

In “gimplify_decl_expr”, VLA goes to “gimplify_vla_decl”, and is expanded to
call to alloca.  Naturally, I add calls to “memset/memcpy” in “gimplify_vla_decl” to
Initialize it.

On the other hand, no-VLAs are handled differently in “gimplify_decl_expr”, so
I added calls to “.DEFFERED_INIT” to initialize them.

What’s the major issue if I add calls to “memset/memcpy” in “gimplify_vla_decl” to
Initialize VLAs?

Just inconsistency and unexpected different behavior with respect to
uninitialized warnings?

Okay.
Will try to initialize VLA through the call to .DEFFERED_INIT too. And see whether there is any issue with it.


@@ -5001,6 +5185,17 @@ gimplify_init_constructor (tree *expr_p, gimple_seq
*pre_p, gimple_seq *post_p,
        /* If a single access to the target must be ensured and all
elements
           are zero, then it's optimal to clear whatever their number.
*/
        cleared = true;
+       else if (flag_trivial_auto_var_init > AUTO_INIT_UNINITIALIZED
+                && !TREE_STATIC (object)
+                && type_has_padding (type))
+         /* If the user requests to initialize automatic variables with
+            paddings inside the type, we should initialize the paddings
too.
+            C guarantees that brace-init with fewer initializers than
members
+            aggregate will initialize the rest of the aggregate as-if it
were
+            static initialization.  In turn static initialization
guarantees
+            that pad is initialized to zero bits.
+            So, it's better to clear the whole record under such
situation.  */
+         cleared = true;

so here we have padding as well - I think this warrants to be controlled
by an extra option?  And we can maybe split this out to a separate
patch? (the whole padding stuff)

Clang does the padding initialization with this option, shall we be
consistent with Clang?

Just for the sake of consistency?  No.  Is there a technical reason
for this complication?  Say we have

 struct { short s; int i; } a;

what's the technical reason to initialize the padding?  I might
be tempted to use -ftrivial-auto-init but I'd definitely don't
want to spend cycles/instructions initializing the padding in the
above struct.

Kees, could you please answer this question? What’s the major reason to initialize padding
of structures from the security point of view?


At this point I also wonder whether doing the actual initialization
by block-initializing the current function frame at allocation
time.

Which phase is for “allocation time”, please point me to the specific phase and source file.


That would be a way smaller patch (but possibly backend
specific).  On x86 it could be a single rep mov; for all but the
VLA cases.  Just a thought.



Thanks.

Qing


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH][version 3]add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-06-07  7:53     ` Richard Biener
@ 2021-06-07 16:18       ` Qing Zhao
  2021-06-07 23:48         ` Kees Cook
  2021-06-08  7:41         ` Richard Biener
  0 siblings, 2 replies; 57+ messages in thread
From: Qing Zhao @ 2021-06-07 16:18 UTC (permalink / raw)
  To: Richard Biener, Kees cook
  Cc: richard Sandiford, kees Cook, gcc-patches Qing Zhao via

Hi, 

> On Jun 7, 2021, at 2:53 AM, Richard Biener <rguenther@suse.de> wrote:
> 
>> 
>> To address the above suggestion:
>> 
>> My study shows: the call to __builtin_clear_padding is expanded during gimplification phase.
>> And there is no __bultin_clear_padding expanding during rtx expanding phase.
>> However, for -ftrivial-auto-var-init, padding initialization should be done both in gimplification phase and rtx expanding phase.
>> since the __builtin_clear_padding might not be good for rtx expanding, reusing __builtin_clear_padding might not work.
>> 
>> Let me know if you have any more comments on this.
> 
> Yes, I didn't suggest to literally emit calls to __builtin_clear_padding 
> but instead to leverage the lowering code, more specifically share the
> code that figures _what_ is to be initialized (where the padding is)
> and eventually the actual code generation pieces.  That might need some
> refactoring but the code where padding resides should be present only
> a single time (since it's quite complex).

Okay, I see your point here.

> 
> Which is also why I suggested to split out the padding initialization
> bits to a separate patch (and option).

Personally, I am okay with splitting padding initialization from this current patch,
Kees, what’s your opinion on this? i.e, the current -ftrivial-auto-var-init will NOT initialize padding, we will add another option to 
Explicitly initialize padding.

Qing


> 
> Richard.


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH][version 3]add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-06-07  7:48     ` Richard Biener
  2021-06-07 16:13       ` Qing Zhao
@ 2021-06-07 23:45       ` Kees Cook
  2021-06-08  8:27         ` Richard Biener
  1 sibling, 1 reply; 57+ messages in thread
From: Kees Cook @ 2021-06-07 23:45 UTC (permalink / raw)
  To: Richard Biener; +Cc: Qing Zhao, richard Sandiford, gcc-patches Qing Zhao via

On Mon, Jun 07, 2021 at 09:48:41AM +0200, Richard Biener wrote:
> On Thu, 27 May 2021, Qing Zhao wrote:
> > @@ -5001,6 +5185,17 @@ gimplify_init_constructor (tree *expr_p, gimple_seq
> > *pre_p, gimple_seq *post_p,
> >          /* If a single access to the target must be ensured and all
> > elements
> >             are zero, then it's optimal to clear whatever their number.
> > */
> >          cleared = true;
> > +       else if (flag_trivial_auto_var_init > AUTO_INIT_UNINITIALIZED
> > +                && !TREE_STATIC (object)
> > +                && type_has_padding (type))
> > +         /* If the user requests to initialize automatic variables with
> > +            paddings inside the type, we should initialize the paddings
> > too.
> > +            C guarantees that brace-init with fewer initializers than
> > members
> > +            aggregate will initialize the rest of the aggregate as-if it
> > were
> > +            static initialization.  In turn static initialization
> > guarantees
> > +            that pad is initialized to zero bits.
> > +            So, it's better to clear the whole record under such
> > situation.  */
> > +         cleared = true;
> > 
> > so here we have padding as well - I think this warrants to be controlled
> > by an extra option?  And we can maybe split this out to a separate
> > patch? (the whole padding stuff)
> > 
> > Clang does the padding initialization with this option, shall we be 
> > consistent with Clang?
> 
> Just for the sake of consistency?  No.  Is there a technical reason
> for this complication?  Say we have
> 
>   struct { short s; int i; } a;
> 
> what's the technical reason to initialize the padding?  I might
> be tempted to use -ftrivial-auto-init but I'd definitely don't
> want to spend cycles/instructions initializing the padding in the
> above struct.

Yes, this is very important. This is one of the more common ways memory
content leaks happen in programs (especially the kernel). e.g.:

struct example {
	short s;
	int i;
};

struct example instance = { .i = foo };

While "s" gets zeroed, the padding may not, and may contain prior memory
contents. Having this be deterministically zero is important for this
feature. If the structure gets byte-copied to a buffer (e.g. syscall,
etc), the padding will go along for the ride.

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH][version 3]add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-06-07 16:18       ` Qing Zhao
@ 2021-06-07 23:48         ` Kees Cook
  2021-06-08  7:41         ` Richard Biener
  1 sibling, 0 replies; 57+ messages in thread
From: Kees Cook @ 2021-06-07 23:48 UTC (permalink / raw)
  To: Qing Zhao; +Cc: Richard Biener, richard Sandiford, gcc-patches Qing Zhao via

On Mon, Jun 07, 2021 at 04:18:46PM +0000, Qing Zhao wrote:
> Hi, 
> 
> > On Jun 7, 2021, at 2:53 AM, Richard Biener <rguenther@suse.de> wrote:
> > 
> >> 
> >> To address the above suggestion:
> >> 
> >> My study shows: the call to __builtin_clear_padding is expanded during gimplification phase.
> >> And there is no __bultin_clear_padding expanding during rtx expanding phase.
> >> However, for -ftrivial-auto-var-init, padding initialization should be done both in gimplification phase and rtx expanding phase.
> >> since the __builtin_clear_padding might not be good for rtx expanding, reusing __builtin_clear_padding might not work.
> >> 
> >> Let me know if you have any more comments on this.
> > 
> > Yes, I didn't suggest to literally emit calls to __builtin_clear_padding 
> > but instead to leverage the lowering code, more specifically share the
> > code that figures _what_ is to be initialized (where the padding is)
> > and eventually the actual code generation pieces.  That might need some
> > refactoring but the code where padding resides should be present only
> > a single time (since it's quite complex).
> 
> Okay, I see your point here.
> 
> > 
> > Which is also why I suggested to split out the padding initialization
> > bits to a separate patch (and option).
> 
> Personally, I am okay with splitting padding initialization from this current patch,
> Kees, what’s your opinion on this? i.e, the current -ftrivial-auto-var-init will NOT initialize padding, we will add another option to 
> Explicitly initialize padding.

If two new options are needed, that's fine. But "-ftrivial-auto-var-init"
needs to do both (it is _not_ getting fully initialized if padding isn't
included). And would be a behavioral mismatch between Clang and GCC. :)

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH][version 3]add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-06-07 16:13       ` Qing Zhao
@ 2021-06-08  7:37         ` Richard Biener
  2021-06-08 16:56           ` Kees Cook
  0 siblings, 1 reply; 57+ messages in thread
From: Richard Biener @ 2021-06-08  7:37 UTC (permalink / raw)
  To: Qing Zhao; +Cc: Kees Cook, richard Sandiford, gcc-patches Qing Zhao via

On Mon, 7 Jun 2021, Qing Zhao wrote:

> (Kees, can you answer one of Richard’s question below? On the reason to initialize padding of structures)
> 
> Richard,
> 
> 
> On Jun 7, 2021, at 2:48 AM, Richard Biener <rguenther@suse.de<mailto:rguenther@suse.de>> wrote:
> 
> Meh - can you try using a mailer that does proper quoting?  It's difficult
> to spot your added comments.  Will try anyway (and sorry for the delay)
> 
> Only the email replied to gcc-patch alias had this issue, all the other emails I sent are fine. Not sure why?

All your mails have this problem for me, it makes it quite difficult to
follow the conversation.

> Both clang and my patch add initialization to the above auto variable “line”.
> 
> So, I have the following questions need help:
> 
> 1. Do we need to exclude C++ class with ctor from auto initialization?
> 
> 2. I see Clang use call to internal memset to initialize such class, but for my patch, I only initialize the data fields inside this class.
>    Which one is better?
> 
> I can't answer either question, but generally using block-initialization
> (for example via memset, but we'd generally prefer X = {}) is better for
> later optimization.
> 
> Okay. So, Is this he same reason as lowering the call to .DEFFERED_INIT through expand_builtin_memset other than expand_assign?

Yes, more efficient code generated and more efficient code generation.

> seeing this, can you explain why using .DEFERRED_INIT does not
> work for VLAs?
> 
> The major reason for going different routes for VLAs vs. no-VLAs is:
> 
> In the original gimplification phase, VLAs and no-VLAs go different routes.
> I just followed the different routes for them:
> 
> In “gimplify_decl_expr”, VLA goes to “gimplify_vla_decl”, and is expanded to
> call to alloca.  Naturally, I add calls to “memset/memcpy” in “gimplify_vla_decl” to
> Initialize it.
> 
> On the other hand, no-VLAs are handled differently in “gimplify_decl_expr”, so
> I added calls to “.DEFFERED_INIT” to initialize them.
> 
> What’s the major issue if I add calls to “memset/memcpy” in “gimplify_vla_decl” to
> Initialize VLAs?
> 
> Just inconsistency and unexpected different behavior with respect to
> uninitialized warnings?
> 
> Okay.
> Will try to initialize VLA through the call to .DEFFERED_INIT too. And see whether there is any issue with it.

Thanks.

> 
> @@ -5001,6 +5185,17 @@ gimplify_init_constructor (tree *expr_p, gimple_seq
> *pre_p, gimple_seq *post_p,
>         /* If a single access to the target must be ensured and all
> elements
>            are zero, then it's optimal to clear whatever their number.
> */
>         cleared = true;
> +       else if (flag_trivial_auto_var_init > AUTO_INIT_UNINITIALIZED
> +                && !TREE_STATIC (object)
> +                && type_has_padding (type))
> +         /* If the user requests to initialize automatic variables with
> +            paddings inside the type, we should initialize the paddings
> too.
> +            C guarantees that brace-init with fewer initializers than
> members
> +            aggregate will initialize the rest of the aggregate as-if it
> were
> +            static initialization.  In turn static initialization
> guarantees
> +            that pad is initialized to zero bits.
> +            So, it's better to clear the whole record under such
> situation.  */
> +         cleared = true;
> 
> so here we have padding as well - I think this warrants to be controlled
> by an extra option?  And we can maybe split this out to a separate
> patch? (the whole padding stuff)
> 
> Clang does the padding initialization with this option, shall we be
> consistent with Clang?
> 
> Just for the sake of consistency?  No.  Is there a technical reason
> for this complication?  Say we have
> 
>  struct { short s; int i; } a;
> 
> what's the technical reason to initialize the padding?  I might
> be tempted to use -ftrivial-auto-init but I'd definitely don't
> want to spend cycles/instructions initializing the padding in the
> above struct.
> 
> Kees, could you please answer this question? What’s the major reason to initialize padding
> of structures from the security point of view?
> 
> 
> At this point I also wonder whether doing the actual initialization
> by block-initializing the current function frame at allocation
> time.
> 
> Which phase is for “allocation time”, please point me to the specific phase and source file.

I actually don't know exactly but it would be the function prologue
stack adjustment (that would also cover spill slots if they are
accumulated), maybe config/i386/i386.c:pro_epilogue_adjust_stack.

Maybe it can be hooked into the -fstack-clash-protection code as well
by changing the probe sequence to a zeroing/patterning sequence.

As said, it was just a thought - zeroing/patterning of auto vars
with not needing to respect object boundaries can be more efficient
for example on x86 it could be just a single rep movq;

Richard.

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH][version 3]add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-06-07 16:18       ` Qing Zhao
  2021-06-07 23:48         ` Kees Cook
@ 2021-06-08  7:41         ` Richard Biener
  2021-06-08 15:27           ` Qing Zhao
  2021-06-08 16:59           ` Kees Cook
  1 sibling, 2 replies; 57+ messages in thread
From: Richard Biener @ 2021-06-08  7:41 UTC (permalink / raw)
  To: Qing Zhao; +Cc: Kees cook, richard Sandiford, gcc-patches Qing Zhao via

On Mon, 7 Jun 2021, Qing Zhao wrote:

> Hi, 
> 
> > On Jun 7, 2021, at 2:53 AM, Richard Biener <rguenther@suse.de> wrote:
> > 
> >> 
> >> To address the above suggestion:
> >> 
> >> My study shows: the call to __builtin_clear_padding is expanded during gimplification phase.
> >> And there is no __bultin_clear_padding expanding during rtx expanding phase.
> >> However, for -ftrivial-auto-var-init, padding initialization should be done both in gimplification phase and rtx expanding phase.
> >> since the __builtin_clear_padding might not be good for rtx expanding, reusing __builtin_clear_padding might not work.
> >> 
> >> Let me know if you have any more comments on this.
> > 
> > Yes, I didn't suggest to literally emit calls to __builtin_clear_padding 
> > but instead to leverage the lowering code, more specifically share the
> > code that figures _what_ is to be initialized (where the padding is)
> > and eventually the actual code generation pieces.  That might need some
> > refactoring but the code where padding resides should be present only
> > a single time (since it's quite complex).
> 
> Okay, I see your point here.
> 
> > 
> > Which is also why I suggested to split out the padding initialization
> > bits to a separate patch (and option).
> 
> Personally, I am okay with splitting padding initialization from this current patch,
> Kees, what’s your opinion on this? i.e, the current -ftrivial-auto-var-init will NOT initialize padding, we will add another option to 
> Explicitly initialize padding.

It would also be possible to have -fauto-var-init, -fauto-var-init-padding
and have -ftrivial-auto-var-init for clang compatibility enabling
both.  Or -fauto-var-init={zero,pattern,padding} and allow
-fauto-var-init=pattern,padding to be specified.  Note there's also
padding between auto variables on the stack - that "trailing"
padding isn't initialized either?  (yes, GCC sorts variables to minimize
that padding)  For example for

void foo()
{
  char a[3];
  bar (a);
}

there's 12 bytes padding after 'a', shouldn't we initialize that?  If not,
why's other padding important to be initialized?

Richard.

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH][version 3]add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-06-07 23:45       ` Kees Cook
@ 2021-06-08  8:27         ` Richard Biener
  0 siblings, 0 replies; 57+ messages in thread
From: Richard Biener @ 2021-06-08  8:27 UTC (permalink / raw)
  To: Kees Cook; +Cc: Qing Zhao, richard Sandiford, gcc-patches Qing Zhao via

On Mon, 7 Jun 2021, Kees Cook wrote:

> On Mon, Jun 07, 2021 at 09:48:41AM +0200, Richard Biener wrote:
> > On Thu, 27 May 2021, Qing Zhao wrote:
> > > @@ -5001,6 +5185,17 @@ gimplify_init_constructor (tree *expr_p, gimple_seq
> > > *pre_p, gimple_seq *post_p,
> > >          /* If a single access to the target must be ensured and all
> > > elements
> > >             are zero, then it's optimal to clear whatever their number.
> > > */
> > >          cleared = true;
> > > +       else if (flag_trivial_auto_var_init > AUTO_INIT_UNINITIALIZED
> > > +                && !TREE_STATIC (object)
> > > +                && type_has_padding (type))
> > > +         /* If the user requests to initialize automatic variables with
> > > +            paddings inside the type, we should initialize the paddings
> > > too.
> > > +            C guarantees that brace-init with fewer initializers than
> > > members
> > > +            aggregate will initialize the rest of the aggregate as-if it
> > > were
> > > +            static initialization.  In turn static initialization
> > > guarantees
> > > +            that pad is initialized to zero bits.
> > > +            So, it's better to clear the whole record under such
> > > situation.  */
> > > +         cleared = true;
> > > 
> > > so here we have padding as well - I think this warrants to be controlled
> > > by an extra option?  And we can maybe split this out to a separate
> > > patch? (the whole padding stuff)
> > > 
> > > Clang does the padding initialization with this option, shall we be 
> > > consistent with Clang?
> > 
> > Just for the sake of consistency?  No.  Is there a technical reason
> > for this complication?  Say we have
> > 
> >   struct { short s; int i; } a;
> > 
> > what's the technical reason to initialize the padding?  I might
> > be tempted to use -ftrivial-auto-init but I'd definitely don't
> > want to spend cycles/instructions initializing the padding in the
> > above struct.
> 
> Yes, this is very important. This is one of the more common ways memory
> content leaks happen in programs (especially the kernel). e.g.:
> 
> struct example {
> 	short s;
> 	int i;
> };
> 
> struct example instance = { .i = foo };
> 
> While "s" gets zeroed, the padding may not, and may contain prior memory
> contents. Having this be deterministically zero is important for this
> feature. If the structure gets byte-copied to a buffer (e.g. syscall,
> etc), the padding will go along for the ride.

OK, so IMHO this is really a separate feature then - note that even
allocated memory suffers from this issue if the allocator does not
zero allocated blocks in full.  It then applies to even fully correctly
initialized objects and would eventually be better suited for a
language extension.

That said, the user documentation should elaborate on use cases.
pre-zeroing of fields makes bugs due to uninitialized accesses
more "reliable", zeroing of everything avoids information leaks.
All only for auto-vars (I suppose securing of allocated storage
should then happen in the allocator itself and thus likely a bit
less optimized).

Btw, see my other suggestion about simply making sure to pre-initialize
the whole frame at its allocation point.

Richard.

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH][version 3]add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-06-08  7:41         ` Richard Biener
@ 2021-06-08 15:27           ` Qing Zhao
  2021-06-08 16:59           ` Kees Cook
  1 sibling, 0 replies; 57+ messages in thread
From: Qing Zhao @ 2021-06-08 15:27 UTC (permalink / raw)
  To: Richard Biener; +Cc: Kees cook, richard Sandiford, gcc-patches Qing Zhao via



On Jun 8, 2021, at 2:41 AM, Richard Biener <rguenther@suse.de<mailto:rguenther@suse.de>> wrote:



Which is also why I suggested to split out the padding initialization
bits to a separate patch (and option).

Personally, I am okay with splitting padding initialization from this current patch,
Kees, what’s your opinion on this? i.e, the current -ftrivial-auto-var-init will NOT initialize padding, we will add another option to
Explicitly initialize padding.

It would also be possible to have -fauto-var-init, -fauto-var-init-padding
and have -ftrivial-auto-var-init for clang compatibility enabling
both.

I really like this idea.

Personally, I do think that separating padding initialization from auto-var initialization will make the design and implemenation more clean.

With an additional -ftrivial-auto-var-init to include both will serve the clang compatibility well.

 Or -fauto-var-init={zero,pattern,padding} and allow
-fauto-var-init=pattern,padding to be specified.  Note there's also
padding between auto variables on the stack - that "trailing"
padding isn't initialized either?  (yes, GCC sorts variables to minimize
that padding)  For example for

void foo()
{
 char a[3];
 bar (a);
}

there's 12 bytes padding after 'a', shouldn't we initialize that?

Yes, in the current patch, tail paddings are also initialized.

But “paddings” between auto variables are not initialized. (They are not belong to variables).

Qing


 If not,
why's other padding important to be initialized?

Richard.


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH][version 3]add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-06-08  7:37         ` Richard Biener
@ 2021-06-08 16:56           ` Kees Cook
  2021-06-08 17:32             ` Qing Zhao
  0 siblings, 1 reply; 57+ messages in thread
From: Kees Cook @ 2021-06-08 16:56 UTC (permalink / raw)
  To: Qing Zhao; +Cc: Richard Biener, richard Sandiford, gcc-patches Qing Zhao via

On Tue, Jun 08, 2021 at 09:37:30AM +0200, Richard Biener wrote:
> On Mon, 7 Jun 2021, Qing Zhao wrote:
> > On Jun 7, 2021, at 2:48 AM, Richard Biener <rguenther@suse.de<mailto:rguenther@suse.de>> wrote:
> > 
> > Meh - can you try using a mailer that does proper quoting?  It's difficult
> > to spot your added comments.  Will try anyway (and sorry for the delay)
> > 
> > Only the email replied to gcc-patch alias had this issue, all the other emails I sent are fine. Not sure why?
> 
> All your mails have this problem for me, it makes it quite difficult to
> follow the conversation.

I think the first step is to make sure the MUA is sending "text only"
emails. Then configure the "quoting style" to do the standard "> "-style.

What email client are you using?

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH][version 3]add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-06-08  7:41         ` Richard Biener
  2021-06-08 15:27           ` Qing Zhao
@ 2021-06-08 16:59           ` Kees Cook
  2021-06-08 18:05             ` Qing Zhao
  2021-06-11 11:04             ` Richard Biener
  1 sibling, 2 replies; 57+ messages in thread
From: Kees Cook @ 2021-06-08 16:59 UTC (permalink / raw)
  To: Richard Biener; +Cc: Qing Zhao, richard Sandiford, gcc-patches Qing Zhao via

On Tue, Jun 08, 2021 at 09:41:38AM +0200, Richard Biener wrote:
> On Mon, 7 Jun 2021, Qing Zhao wrote:
> 
> > Hi, 
> > 
> > > On Jun 7, 2021, at 2:53 AM, Richard Biener <rguenther@suse.de> wrote:
> > > 
> > >> 
> > >> To address the above suggestion:
> > >> 
> > >> My study shows: the call to __builtin_clear_padding is expanded during gimplification phase.
> > >> And there is no __bultin_clear_padding expanding during rtx expanding phase.
> > >> However, for -ftrivial-auto-var-init, padding initialization should be done both in gimplification phase and rtx expanding phase.
> > >> since the __builtin_clear_padding might not be good for rtx expanding, reusing __builtin_clear_padding might not work.
> > >> 
> > >> Let me know if you have any more comments on this.
> > > 
> > > Yes, I didn't suggest to literally emit calls to __builtin_clear_padding 
> > > but instead to leverage the lowering code, more specifically share the
> > > code that figures _what_ is to be initialized (where the padding is)
> > > and eventually the actual code generation pieces.  That might need some
> > > refactoring but the code where padding resides should be present only
> > > a single time (since it's quite complex).
> > 
> > Okay, I see your point here.
> > 
> > > 
> > > Which is also why I suggested to split out the padding initialization
> > > bits to a separate patch (and option).
> > 
> > Personally, I am okay with splitting padding initialization from this current patch,
> > Kees, what’s your opinion on this? i.e, the current -ftrivial-auto-var-init will NOT initialize padding, we will add another option to 
> > Explicitly initialize padding.
> 
> It would also be possible to have -fauto-var-init, -fauto-var-init-padding
> and have -ftrivial-auto-var-init for clang compatibility enabling both.

Sounds good to me!

> Or -fauto-var-init={zero,pattern,padding} and allow
> -fauto-var-init=pattern,padding to be specified.  Note there's also
> padding between auto variables on the stack - that "trailing"
> padding isn't initialized either?  (yes, GCC sorts variables to minimize
> that padding)  For example for
> 
> void foo()
> {
>   char a[3];
>   bar (a);
> }
> 
> there's 12 bytes padding after 'a', shouldn't we initialize that?  If not,
> why's other padding important to be initialized?

This isn't a situation that I'm aware of causing real-world problems.
The issues have all come from padding within an addressable object. I
haven't tested Clang's behavior on this (and I have no kernel tests for
this padding), but I do check for trailing padding, like:

struct test_trailing_hole {
        char *one;
        char *two;
        char *three;
        char four;
        /* "sizeof(unsigned long) - 1" byte padding hole here. */
};

-Kees

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH][version 3]add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-06-08 16:56           ` Kees Cook
@ 2021-06-08 17:32             ` Qing Zhao
  2021-06-08 17:36               ` Kees Cook
  0 siblings, 1 reply; 57+ messages in thread
From: Qing Zhao @ 2021-06-08 17:32 UTC (permalink / raw)
  To: Kees Cook; +Cc: Richard Biener, richard Sandiford, gcc-patches Qing Zhao via

Thanks a lot.

Kees. 

Do you have the same issue with my emails?

I see this problem with my email mostly to part of the emails that were sent to gcc-patches alias. 
Other emails are fine. 

> On Jun 8, 2021, at 11:56 AM, Kees Cook <keescook@chromium.org> wrote:
> 
> On Tue, Jun 08, 2021 at 09:37:30AM +0200, Richard Biener wrote:
>> On Mon, 7 Jun 2021, Qing Zhao wrote:
>>> On Jun 7, 2021, at 2:48 AM, Richard Biener <rguenther@suse.de<mailto:rguenther@suse.de>> wrote:
>>> 
>>> Meh - can you try using a mailer that does proper quoting?  It's difficult
>>> to spot your added comments.  Will try anyway (and sorry for the delay)
>>> 
>>> Only the email replied to gcc-patch alias had this issue, all the other emails I sent are fine. Not sure why?
>> 
>> All your mails have this problem for me, it makes it quite difficult to
>> follow the conversation.
> 
> I think the first step is to make sure the MUA is sending "text only"
> emails. Then configure the "quoting style" to do the standard "> "-style.
> 
> What email client are you using?

I am using Mac’s Apple Mail client on my computer. 

I have been using this mail client for a long time, but only had such issues recently. 

Really not sure what’s going on.

I will try to figure this out.

Qing
> 
> -- 
> Kees Cook


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH][version 3]add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-06-08 17:32             ` Qing Zhao
@ 2021-06-08 17:36               ` Kees Cook
  0 siblings, 0 replies; 57+ messages in thread
From: Kees Cook @ 2021-06-08 17:36 UTC (permalink / raw)
  To: Qing Zhao; +Cc: Richard Biener, richard Sandiford, gcc-patches Qing Zhao via

On Tue, Jun 08, 2021 at 05:32:32PM +0000, Qing Zhao wrote:
> Thanks a lot.
> 
> Kees. 
> 
> Do you have the same issue with my emails?

Some of them, yes. This one was fine.

> I see this problem with my email mostly to part of the emails that were sent to gcc-patches alias. 
> Other emails are fine. 
> 
> > On Jun 8, 2021, at 11:56 AM, Kees Cook <keescook@chromium.org> wrote:
> > 
> > On Tue, Jun 08, 2021 at 09:37:30AM +0200, Richard Biener wrote:
> >> On Mon, 7 Jun 2021, Qing Zhao wrote:
> >>> On Jun 7, 2021, at 2:48 AM, Richard Biener <rguenther@suse.de<mailto:rguenther@suse.de>> wrote:
> >>> 
> >>> Meh - can you try using a mailer that does proper quoting?  It's difficult
> >>> to spot your added comments.  Will try anyway (and sorry for the delay)
> >>> 
> >>> Only the email replied to gcc-patch alias had this issue, all the other emails I sent are fine. Not sure why?
> >> 
> >> All your mails have this problem for me, it makes it quite difficult to
> >> follow the conversation.
> > 
> > I think the first step is to make sure the MUA is sending "text only"
> > emails. Then configure the "quoting style" to do the standard "> "-style.
> > 
> > What email client are you using?
> 
> I am using Mac’s Apple Mail client on my computer. 
> 
> I have been using this mail client for a long time, but only had such issues recently. 

I share your pain! Gmail frequently likes making tiny breaking changes
too. :)

> Really not sure what’s going on.
> 
> I will try to figure this out.

Thanks!

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH][version 3]add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-06-08 16:59           ` Kees Cook
@ 2021-06-08 18:05             ` Qing Zhao
  2021-06-11 11:04             ` Richard Biener
  1 sibling, 0 replies; 57+ messages in thread
From: Qing Zhao @ 2021-06-08 18:05 UTC (permalink / raw)
  To: Kees Cook, Richard Biener; +Cc: richard Sandiford, gcc-patches Qing Zhao via



> On Jun 8, 2021, at 11:59 AM, Kees Cook <keescook@chromium.org> wrote:
> 
> On Tue, Jun 08, 2021 at 09:41:38AM +0200, Richard Biener wrote:
>> On Mon, 7 Jun 2021, Qing Zhao wrote:
>>> 
>>> Personally, I am okay with splitting padding initialization from this current patch,
>>> Kees, what’s your opinion on this? i.e, the current -ftrivial-auto-var-init will NOT initialize padding, we will add another option to 
>>> Explicitly initialize padding.
>> 
>> It would also be possible to have -fauto-var-init, -fauto-var-init-padding
>> and have -ftrivial-auto-var-init for clang compatibility enabling both.
> 
> Sounds good to me!

Agreed!

Then I will take this approach:

1.  Adding two separate new options:
   -fauto-var-init.     initialize auto variables to zero or patterns. For variables that have paddings, only initialize valid fields, no padding initialization;
   -fauto-var-init-padding    initialize paddings inside an auto variables to zeroes. 

2.  Add another new option for Clang compatibility:
   -ftrivial-auto-var-init   will enable -fauto-var-init + -fauto-var-init-padding


Thanks.

Qing
> 
>> Or -fauto-var-init={zero,pattern,padding} and allow
>> -fauto-var-init=pattern,padding to be specified.  Note there's also
>> padding between auto variables on the stack - that "trailing"
>> padding isn't initialized either?  (yes, GCC sorts variables to minimize
>> that padding)  For example for
>> 
>> void foo()
>> {
>>  char a[3];
>>  bar (a);
>> }
>> 
>> there's 12 bytes padding after 'a', shouldn't we initialize that?  If not,
>> why's other padding important to be initialized?
> 
> This isn't a situation that I'm aware of causing real-world problems.
> The issues have all come from padding within an addressable object. I
> haven't tested Clang's behavior on this (and I have no kernel tests for
> this padding), but I do check for trailing padding, like:
> 
> struct test_trailing_hole {
>        char *one;
>        char *two;
>        char *three;
>        char four;
>        /* "sizeof(unsigned long) - 1" byte padding hole here. */
> };
> 
> -Kees
> 
> -- 
> Kees Cook


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH][version 3]add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-05-26 11:18 ` Richard Biener
                     ` (3 preceding siblings ...)
  2021-06-03 20:18   ` Qing Zhao
@ 2021-06-10 21:11   ` Qing Zhao
  2021-06-11 11:12     ` Richard Biener
  4 siblings, 1 reply; 57+ messages in thread
From: Qing Zhao @ 2021-06-10 21:11 UTC (permalink / raw)
  To: Richard Biener; +Cc: richard Sandiford, kees Cook, gcc-patches Qing Zhao via

Hi, Richard,

I need more discussion on the following comments you raised:

> On May 26, 2021, at 6:18 AM, Richard Biener <rguenther@suse.de> wrote:
> 
> +/* Expand the IFN_DEFERRED_INIT function according to its second 
> argument.  */
> +static void
> +expand_DEFERRED_INIT (internal_fn, gcall *stmt)
> +{
> +  tree var = gimple_call_lhs (stmt);
> +  tree init = NULL_TREE;
> +  enum auto_init_type init_type
> +    = (enum auto_init_type) TREE_INT_CST_LOW (gimple_call_arg (stmt, 1));
> +
> +  switch (init_type)
> +    {
> +    default:
> +      gcc_unreachable ();
> +    case AUTO_INIT_PATTERN:
> +      init = build_pattern_cst_for_auto_init (TREE_TYPE (var));
> +      expand_assignment (var, init, false);
> +      break;
> +    case AUTO_INIT_ZERO:
> +      init = build_zero_cst (TREE_TYPE (var));
> +      expand_assignment (var, init, false);
> +      break;
> +    }
> 
> I think actually building build_pattern_cst_for_auto_init can generate
> massive garbage and for big auto vars code size is also a concern and
> ideally on x86 you'd produce rep movq.  So I don't think going
> via expand_assignment is good.  Instead you possibly want to lower
> .DEFERRED_INIT to MEMs following expand_builtin_memset and
> eventually enhance that to allow storing pieces larger than a byte.

When I tried to lower .DEFERRED_INIT to MEMs for  “AUTO_INIT_PATTERN”, I have the following questions:

1. If .DEFERRED_INIT will be lowered to MEMS through “memset”, then we basically initialize the whole memory covering the
auto variable, including paddings. Right?
2. Only when the value that is used to initialization has a repeated byte-pattern, we can lower it through “memset”. Otherwise,
If the value that is used to initialization does Not have a repeated byte-pattern, we can NOT lower it through “memset”, right?

Currently, for the values that are used to initialize for “AUTO_INIT_PATTERN”, we have:

  /* 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;

In additional to the above, for BOOLEAN_TYPE:

    case BOOLEAN_TYPE:
      /* We think that initializing the boolean variable to 0 other than 1
         is better even for pattern initialization.  */

Due to “BOOLEAN_TYPE” and “POINTER_TYPE”,  we cannot always have a repeated byte-pattern for variables that include BOOLEAN_TYPE
Or Pointer types. Therefore, lowering the .DEFERRED_INIT for “PATTERN” initialization through “memset” is not always possible. 

Let me know if I miss anything in the above. Do you have other suggestions?

thanks.

Qing


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH][version 3]add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-06-08 16:59           ` Kees Cook
  2021-06-08 18:05             ` Qing Zhao
@ 2021-06-11 11:04             ` Richard Biener
  2021-06-11 17:14               ` Kees Cook
  1 sibling, 1 reply; 57+ messages in thread
From: Richard Biener @ 2021-06-11 11:04 UTC (permalink / raw)
  To: Kees Cook; +Cc: Qing Zhao, richard Sandiford, gcc-patches Qing Zhao via

On Tue, 8 Jun 2021, Kees Cook wrote:

> On Tue, Jun 08, 2021 at 09:41:38AM +0200, Richard Biener wrote:
> > On Mon, 7 Jun 2021, Qing Zhao wrote:
> > 
> > > Hi, 
> > > 
> > > > On Jun 7, 2021, at 2:53 AM, Richard Biener <rguenther@suse.de> wrote:
> > > > 
> > > >> 
> > > >> To address the above suggestion:
> > > >> 
> > > >> My study shows: the call to __builtin_clear_padding is expanded during gimplification phase.
> > > >> And there is no __bultin_clear_padding expanding during rtx expanding phase.
> > > >> However, for -ftrivial-auto-var-init, padding initialization should be done both in gimplification phase and rtx expanding phase.
> > > >> since the __builtin_clear_padding might not be good for rtx expanding, reusing __builtin_clear_padding might not work.
> > > >> 
> > > >> Let me know if you have any more comments on this.
> > > > 
> > > > Yes, I didn't suggest to literally emit calls to __builtin_clear_padding 
> > > > but instead to leverage the lowering code, more specifically share the
> > > > code that figures _what_ is to be initialized (where the padding is)
> > > > and eventually the actual code generation pieces.  That might need some
> > > > refactoring but the code where padding resides should be present only
> > > > a single time (since it's quite complex).
> > > 
> > > Okay, I see your point here.
> > > 
> > > > 
> > > > Which is also why I suggested to split out the padding initialization
> > > > bits to a separate patch (and option).
> > > 
> > > Personally, I am okay with splitting padding initialization from this current patch,
> > > Kees, what’s your opinion on this? i.e, the current -ftrivial-auto-var-init will NOT initialize padding, we will add another option to 
> > > Explicitly initialize padding.
> > 
> > It would also be possible to have -fauto-var-init, -fauto-var-init-padding
> > and have -ftrivial-auto-var-init for clang compatibility enabling both.
> 
> Sounds good to me!
> 
> > Or -fauto-var-init={zero,pattern,padding} and allow
> > -fauto-var-init=pattern,padding to be specified.  Note there's also
> > padding between auto variables on the stack - that "trailing"
> > padding isn't initialized either?  (yes, GCC sorts variables to minimize
> > that padding)  For example for
> > 
> > void foo()
> > {
> >   char a[3];
> >   bar (a);
> > }
> > 
> > there's 12 bytes padding after 'a', shouldn't we initialize that?  If not,
> > why's other padding important to be initialized?
> 
> This isn't a situation that I'm aware of causing real-world problems.
> The issues have all come from padding within an addressable object. I
> haven't tested Clang's behavior on this (and I have no kernel tests for
> this padding), but I do check for trailing padding, like:
> 
> struct test_trailing_hole {
>         char *one;
>         char *two;
>         char *three;
>         char four;
>         /* "sizeof(unsigned long) - 1" byte padding hole here. */
> };

Any justification why tail padding for

 struct foo { double x; char x[3]; } a;

is important but not for

 char x[3];

?  It does look like an odd inconsistency to me.

Richard.

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH][version 3]add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-06-10 21:11   ` Qing Zhao
@ 2021-06-11 11:12     ` Richard Biener
  2021-06-11 15:49       ` Qing Zhao
  0 siblings, 1 reply; 57+ messages in thread
From: Richard Biener @ 2021-06-11 11:12 UTC (permalink / raw)
  To: Qing Zhao; +Cc: richard Sandiford, kees Cook, gcc-patches Qing Zhao via

On Thu, 10 Jun 2021, Qing Zhao wrote:

> Hi, Richard,
> 
> I need more discussion on the following comments you raised:
> 
> > On May 26, 2021, at 6:18 AM, Richard Biener <rguenther@suse.de> wrote:
> > 
> > +/* Expand the IFN_DEFERRED_INIT function according to its second 
> > argument.  */
> > +static void
> > +expand_DEFERRED_INIT (internal_fn, gcall *stmt)
> > +{
> > +  tree var = gimple_call_lhs (stmt);
> > +  tree init = NULL_TREE;
> > +  enum auto_init_type init_type
> > +    = (enum auto_init_type) TREE_INT_CST_LOW (gimple_call_arg (stmt, 1));
> > +
> > +  switch (init_type)
> > +    {
> > +    default:
> > +      gcc_unreachable ();
> > +    case AUTO_INIT_PATTERN:
> > +      init = build_pattern_cst_for_auto_init (TREE_TYPE (var));
> > +      expand_assignment (var, init, false);
> > +      break;
> > +    case AUTO_INIT_ZERO:
> > +      init = build_zero_cst (TREE_TYPE (var));
> > +      expand_assignment (var, init, false);
> > +      break;
> > +    }
> > 
> > I think actually building build_pattern_cst_for_auto_init can generate
> > massive garbage and for big auto vars code size is also a concern and
> > ideally on x86 you'd produce rep movq.  So I don't think going
> > via expand_assignment is good.  Instead you possibly want to lower
> > .DEFERRED_INIT to MEMs following expand_builtin_memset and
> > eventually enhance that to allow storing pieces larger than a byte.
> 
> When I tried to lower .DEFERRED_INIT to MEMs for  “AUTO_INIT_PATTERN”, I have the following questions:
> 
> 1. If .DEFERRED_INIT will be lowered to MEMS through “memset”, then we basically initialize the whole memory covering the
> auto variable, including paddings. Right?

Yes.

> 2. Only when the value that is used to initialization has a repeated 
>    byte-pattern, we can lower it through “memset”. Otherwise, If the 
>    value that is used to initialization does Not have a repeated 
>    byte-pattern, we can NOT lower it through “memset”, right?

Yes.  This is why I said you should do it _similar_ to how memcpy
is implemented.  OTOH I don't see a good reason to support patterns
that are bigger than a byte ...

> Currently, for the values that are used to initialize for “AUTO_INIT_PATTERN”, we have:
> 
>   /* 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;
> 
> In additional to the above, for BOOLEAN_TYPE:
> 
>     case BOOLEAN_TYPE:
>       /* We think that initializing the boolean variable to 0 other than 1
>          is better even for pattern initialization.  */
> 
> Due to “BOOLEAN_TYPE” and “POINTER_TYPE”, we cannot always have a 
> repeated byte-pattern for variables that include BOOLEAN_TYPE Or Pointer 
> types. Therefore, lowering the .DEFERRED_INIT for “PATTERN” 
> initialization through “memset” is not always possible.
> 
> Let me know if I miss anything in the above. Do you have other suggestions?

The main point is that you need to avoid building the explicit initializer
only to have it consumed by assignment expansion.  If you want to keep
all the singing and dancing (as opposed to maybe initializing with a
0x1 byte pattern) then I think for efficiency you still want to
block-initialize the variable and then only fixup the special fields.

But as said, all this is quite over-designed IMHO and simply
zeroing everything would be much simpler and good enough.

Richard.

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH][version 3]add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-06-11 11:12     ` Richard Biener
@ 2021-06-11 15:49       ` Qing Zhao
  2021-06-11 16:24         ` Kees Cook
                           ` (2 more replies)
  0 siblings, 3 replies; 57+ messages in thread
From: Qing Zhao @ 2021-06-11 15:49 UTC (permalink / raw)
  To: Richard Biener, Kees cook; +Cc: richard Sandiford, gcc-patches Qing Zhao via



> On Jun 11, 2021, at 6:12 AM, Richard Biener <rguenther@suse.de> wrote:
> 
> On Thu, 10 Jun 2021, Qing Zhao wrote:
> 
>> Hi, Richard,
>> 
>> I need more discussion on the following comments you raised:
>> 
>>> On May 26, 2021, at 6:18 AM, Richard Biener <rguenther@suse.de> wrote:
>>> 
>>> +/* Expand the IFN_DEFERRED_INIT function according to its second 
>>> argument.  */
>>> +static void
>>> +expand_DEFERRED_INIT (internal_fn, gcall *stmt)
>>> +{
>>> +  tree var = gimple_call_lhs (stmt);
>>> +  tree init = NULL_TREE;
>>> +  enum auto_init_type init_type
>>> +    = (enum auto_init_type) TREE_INT_CST_LOW (gimple_call_arg (stmt, 1));
>>> +
>>> +  switch (init_type)
>>> +    {
>>> +    default:
>>> +      gcc_unreachable ();
>>> +    case AUTO_INIT_PATTERN:
>>> +      init = build_pattern_cst_for_auto_init (TREE_TYPE (var));
>>> +      expand_assignment (var, init, false);
>>> +      break;
>>> +    case AUTO_INIT_ZERO:
>>> +      init = build_zero_cst (TREE_TYPE (var));
>>> +      expand_assignment (var, init, false);
>>> +      break;
>>> +    }
>>> 
>>> I think actually building build_pattern_cst_for_auto_init can generate
>>> massive garbage and for big auto vars code size is also a concern and
>>> ideally on x86 you'd produce rep movq.  So I don't think going
>>> via expand_assignment is good.  Instead you possibly want to lower
>>> .DEFERRED_INIT to MEMs following expand_builtin_memset and
>>> eventually enhance that to allow storing pieces larger than a byte.
>> 
>> When I tried to lower .DEFERRED_INIT to MEMs for  “AUTO_INIT_PATTERN”, I have the following questions:
>> 
>> 1. If .DEFERRED_INIT will be lowered to MEMS through “memset”, then we basically initialize the whole memory covering the
>> auto variable, including paddings. Right?
> 
> Yes.
> 
>> 2. Only when the value that is used to initialization has a repeated 
>>   byte-pattern, we can lower it through “memset”. Otherwise, If the 
>>   value that is used to initialization does Not have a repeated 
>>   byte-pattern, we can NOT lower it through “memset”, right?
> 
> Yes.  This is why I said you should do it _similar_ to how memcpy
> is implemented.  OTOH I don't see a good reason to support patterns
> that are bigger than a byte ...
> 
>> Currently, for the values that are used to initialize for “AUTO_INIT_PATTERN”, we have:
>> 
>>  /* 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;
>> 
>> In additional to the above, for BOOLEAN_TYPE:
>> 
>>    case BOOLEAN_TYPE:
>>      /* We think that initializing the boolean variable to 0 other than 1
>>         is better even for pattern initialization.  */
>> 
>> Due to “BOOLEAN_TYPE” and “POINTER_TYPE”, we cannot always have a 
>> repeated byte-pattern for variables that include BOOLEAN_TYPE Or Pointer 
>> types. Therefore, lowering the .DEFERRED_INIT for “PATTERN” 
>> initialization through “memset” is not always possible.
>> 
>> Let me know if I miss anything in the above. Do you have other suggestions?
> 
> The main point is that you need to avoid building the explicit initializer
> only to have it consumed by assignment expansion.  If you want to keep
> all the singing and dancing (as opposed to maybe initializing with a
> 0x1 byte pattern) then I think for efficiency you still want to
> block-initialize the variable and then only fixup the special fields.

Yes, this is a good idea. 

We can memset the whole structure with repeated pattern “0xAA” first,
Then mixup BOOLEAN_TYPE and POINTER TYPE for 32-bit platform. 
That might be more efficient. 

> 
> But as said, all this is quite over-designed IMHO and simply
> zeroing everything would be much simpler and good enough.

So, the fundenmental questions are:

1. do we need the functionality of “Pattern Initialization” for debugging purpose?
I see that other compilers support both Zero initialization and Pattern initialization. (Clang and Microsoft compiler)

http://lists.llvm.org/pipermail/cfe-dev/2020-April/065221.html
https://msrc-blog.microsoft.com/2020/05/13/solving-uninitialized-stack-memory-on-windows/
Pattern init is used in development build for debugging purpose, zero init is used in production build for security purpose.

So, I assume that GCC might want to provide similar functionality?  But I am open on this. 

Kees, will Kernel use “Pattern initialization” feature? 

2. Since “Pattern initialization” is just used for debugging purpose, the runtime and code size overhead might not be that 
Important at all, right?

thanks.

Qing
> 
> Richard.


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH][version 3]add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-06-11 15:49       ` Qing Zhao
@ 2021-06-11 16:24         ` Kees Cook
  2021-06-11 17:00         ` Qing Zhao
  2021-06-14 16:10         ` Qing Zhao
  2 siblings, 0 replies; 57+ messages in thread
From: Kees Cook @ 2021-06-11 16:24 UTC (permalink / raw)
  To: Qing Zhao; +Cc: Richard Biener, richard Sandiford, gcc-patches Qing Zhao via

On Fri, Jun 11, 2021 at 03:49:02PM +0000, Qing Zhao wrote:
> 
> On Jun 11, 2021, at 6:12 AM, Richard Biener <rguenther@suse.de> wrote:
> > [...]
> > 
> > The main point is that you need to avoid building the explicit initializer
> > only to have it consumed by assignment expansion.  If you want to keep
> > all the singing and dancing (as opposed to maybe initializing with a
> > 0x1 byte pattern) then I think for efficiency you still want to
> > block-initialize the variable and then only fixup the special fields.
> 
> Yes, this is a good idea. 
> 
> We can memset the whole structure with repeated pattern “0xAA” first,
> Then mixup BOOLEAN_TYPE and POINTER TYPE for 32-bit platform. 
> That might be more efficient. 
> 
> > 
> > But as said, all this is quite over-designed IMHO and simply
> > zeroing everything would be much simpler and good enough.
> 
> So, the fundenmental questions are:
> 
> 1. do we need the functionality of “Pattern Initialization” for debugging purpose?
> I see that other compilers support both Zero initialization and Pattern initialization. (Clang and Microsoft compiler)
> 
> http://lists.llvm.org/pipermail/cfe-dev/2020-April/065221.html
> https://msrc-blog.microsoft.com/2020/05/13/solving-uninitialized-stack-memory-on-windows/
> Pattern init is used in development build for debugging purpose, zero init is used in production build for security purpose.

Correct -- "pattern" is much better about triggering all kinds of
problems, and suitable for debug builds. "zero" is less disruptive and
generally provides a safer failure mode for production builds.

> So, I assume that GCC might want to provide similar functionality?  But I am open on this. 
> 
> Kees, will Kernel use “Pattern initialization” feature? 

It is currently support, yes. Note that if I had to choose between "nothing" and
"only zero", I will happily take "only zero". However, it seems like
pattern init isn't much more of an addition in this series.

> 2. Since “Pattern initialization” is just used for debugging purpose, the runtime and code size overhead might not be that 
> Important at all, right?

That has been my impression, yes.

Thanks!

-Kees

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH][version 3]add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-06-11 15:49       ` Qing Zhao
  2021-06-11 16:24         ` Kees Cook
@ 2021-06-11 17:00         ` Qing Zhao
  2021-06-14 16:10         ` Qing Zhao
  2 siblings, 0 replies; 57+ messages in thread
From: Qing Zhao @ 2021-06-11 17:00 UTC (permalink / raw)
  To: Richard Biener; +Cc: Kees cook, richard Sandiford, gcc-patches Qing Zhao via



On Jun 11, 2021, at 10:49 AM, Qing Zhao via Gcc-patches <gcc-patches@gcc.gnu.org<mailto:gcc-patches@gcc.gnu.org>> wrote:



On Jun 11, 2021, at 6:12 AM, Richard Biener <rguenther@suse.de<mailto:rguenther@suse.de>> wrote:

On Thu, 10 Jun 2021, Qing Zhao wrote:

Hi, Richard,

I need more discussion on the following comments you raised:

On May 26, 2021, at 6:18 AM, Richard Biener <rguenther@suse.de<mailto:rguenther@suse.de>> wrote:

+/* Expand the IFN_DEFERRED_INIT function according to its second
argument.  */
+static void
+expand_DEFERRED_INIT (internal_fn, gcall *stmt)
+{
+  tree var = gimple_call_lhs (stmt);
+  tree init = NULL_TREE;
+  enum auto_init_type init_type
+    = (enum auto_init_type) TREE_INT_CST_LOW (gimple_call_arg (stmt, 1));
+
+  switch (init_type)
+    {
+    default:
+      gcc_unreachable ();
+    case AUTO_INIT_PATTERN:
+      init = build_pattern_cst_for_auto_init (TREE_TYPE (var));
+      expand_assignment (var, init, false);
+      break;
+    case AUTO_INIT_ZERO:
+      init = build_zero_cst (TREE_TYPE (var));
+      expand_assignment (var, init, false);
+      break;
+    }

I think actually building build_pattern_cst_for_auto_init can generate
massive garbage and for big auto vars code size is also a concern and
ideally on x86 you'd produce rep movq.  So I don't think going
via expand_assignment is good.  Instead you possibly want to lower
.DEFERRED_INIT to MEMs following expand_builtin_memset and
eventually enhance that to allow storing pieces larger than a byte.

When I tried to lower .DEFERRED_INIT to MEMs for  “AUTO_INIT_PATTERN”, I have the following questions:

1. If .DEFERRED_INIT will be lowered to MEMS through “memset”, then we basically initialize the whole memory covering the
auto variable, including paddings. Right?

Yes.

2. Only when the value that is used to initialization has a repeated
 byte-pattern, we can lower it through “memset”. Otherwise, If the
 value that is used to initialization does Not have a repeated
 byte-pattern, we can NOT lower it through “memset”, right?

Yes.  This is why I said you should do it _similar_ to how memcpy
is implemented.  OTOH I don't see a good reason to support patterns
that are bigger than a byte ...

Currently, for the values that are used to initialize for “AUTO_INIT_PATTERN”, we have:

/* 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;

In additional to the above, for BOOLEAN_TYPE:

  case BOOLEAN_TYPE:
    /* We think that initializing the boolean variable to 0 other than 1
       is better even for pattern initialization.  */

Due to “BOOLEAN_TYPE” and “POINTER_TYPE”, we cannot always have a
repeated byte-pattern for variables that include BOOLEAN_TYPE Or Pointer
types. Therefore, lowering the .DEFERRED_INIT for “PATTERN”
initialization through “memset” is not always possible.

Let me know if I miss anything in the above. Do you have other suggestions?

The main point is that you need to avoid building the explicit initializer
only to have it consumed by assignment expansion.  If you want to keep
all the singing and dancing (as opposed to maybe initializing with a
0x1 byte pattern) then I think for efficiency you still want to
block-initialize the variable and then only fixup the special fields.

Yes, this is a good idea.

We can memset the whole structure with repeated pattern “0xAA” first,
Then mixup BOOLEAN_TYPE and POINTER TYPE for 32-bit platform.
That might be more efficient.

However, the paddings will be initialized to “0xAA”.
But this should be fine since with -fauto-var-init,  the paddings can be any value.

So, still should be fine.

Qing


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH][version 3]add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-06-11 11:04             ` Richard Biener
@ 2021-06-11 17:14               ` Kees Cook
  0 siblings, 0 replies; 57+ messages in thread
From: Kees Cook @ 2021-06-11 17:14 UTC (permalink / raw)
  To: Richard Biener; +Cc: Qing Zhao, richard Sandiford, gcc-patches Qing Zhao via

On Fri, Jun 11, 2021 at 01:04:09PM +0200, Richard Biener wrote:
> On Tue, 8 Jun 2021, Kees Cook wrote:
> 
> > On Tue, Jun 08, 2021 at 09:41:38AM +0200, Richard Biener wrote:
> > > On Mon, 7 Jun 2021, Qing Zhao wrote:
> > > 
> > > > Hi, 
> > > > 
> > > > > On Jun 7, 2021, at 2:53 AM, Richard Biener <rguenther@suse.de> wrote:
> > > > > 
> > > > >> 
> > > > >> To address the above suggestion:
> > > > >> 
> > > > >> My study shows: the call to __builtin_clear_padding is expanded during gimplification phase.
> > > > >> And there is no __bultin_clear_padding expanding during rtx expanding phase.
> > > > >> However, for -ftrivial-auto-var-init, padding initialization should be done both in gimplification phase and rtx expanding phase.
> > > > >> since the __builtin_clear_padding might not be good for rtx expanding, reusing __builtin_clear_padding might not work.
> > > > >> 
> > > > >> Let me know if you have any more comments on this.
> > > > > 
> > > > > Yes, I didn't suggest to literally emit calls to __builtin_clear_padding 
> > > > > but instead to leverage the lowering code, more specifically share the
> > > > > code that figures _what_ is to be initialized (where the padding is)
> > > > > and eventually the actual code generation pieces.  That might need some
> > > > > refactoring but the code where padding resides should be present only
> > > > > a single time (since it's quite complex).
> > > > 
> > > > Okay, I see your point here.
> > > > 
> > > > > 
> > > > > Which is also why I suggested to split out the padding initialization
> > > > > bits to a separate patch (and option).
> > > > 
> > > > Personally, I am okay with splitting padding initialization from this current patch,
> > > > Kees, what’s your opinion on this? i.e, the current -ftrivial-auto-var-init will NOT initialize padding, we will add another option to 
> > > > Explicitly initialize padding.
> > > 
> > > It would also be possible to have -fauto-var-init, -fauto-var-init-padding
> > > and have -ftrivial-auto-var-init for clang compatibility enabling both.
> > 
> > Sounds good to me!
> > 
> > > Or -fauto-var-init={zero,pattern,padding} and allow
> > > -fauto-var-init=pattern,padding to be specified.  Note there's also
> > > padding between auto variables on the stack - that "trailing"
> > > padding isn't initialized either?  (yes, GCC sorts variables to minimize
> > > that padding)  For example for
> > > 
> > > void foo()
> > > {
> > >   char a[3];
> > >   bar (a);
> > > }
> > > 
> > > there's 12 bytes padding after 'a', shouldn't we initialize that?  If not,
> > > why's other padding important to be initialized?
> > 
> > This isn't a situation that I'm aware of causing real-world problems.
> > The issues have all come from padding within an addressable object. I
> > haven't tested Clang's behavior on this (and I have no kernel tests for
> > this padding), but I do check for trailing padding, like:
> > 
> > struct test_trailing_hole {
> >         char *one;
> >         char *two;
> >         char *three;
> >         char four;
> >         /* "sizeof(unsigned long) - 1" byte padding hole here. */
> > };
> 
> Any justification why tail padding for
> 
>  struct foo { double x; char x[3]; } a;
> 
> is important but not for
> 
>  char x[3];
> 
> ?  It does look like an odd inconsistency to me.

The problem is with sizeof() and the various compounding results related
to it. Namely, things that do whole-struct copies (which is unfortunately
common in the kernel) will include the padding for "a" since it is within
the object, as represented by sizeof(), but not for x:

#include <stdio.h>

int main(void)
{
    struct foo { double y; char x[3]; } a;
    char x[3];

    printf("a: %zu (a.y: %zu, a.x: %zu)\n", sizeof(a), sizeof(a.y), sizeof(a.x));
    printf("x: %zu\n", sizeof(x));

    return 0;
}

a: 16 (a.y: 8, a.x: 3)
x: 3

And it gets worse with structs-within-structs, etc.

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH][version 3]add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-06-11 15:49       ` Qing Zhao
  2021-06-11 16:24         ` Kees Cook
  2021-06-11 17:00         ` Qing Zhao
@ 2021-06-14 16:10         ` Qing Zhao
  2021-06-15 13:21           ` Richard Biener
  2 siblings, 1 reply; 57+ messages in thread
From: Qing Zhao @ 2021-06-14 16:10 UTC (permalink / raw)
  To: Richard Biener; +Cc: Kees cook, richard Sandiford, gcc-patches Qing Zhao via

Hi, Richard:

On Jun 11, 2021, at 10:49 AM, Qing Zhao via Gcc-patches <gcc-patches@gcc.gnu.org<mailto:gcc-patches@gcc.gnu.org>> wrote:


On May 26, 2021, at 6:18 AM, Richard Biener <rguenther@suse.de<mailto:rguenther@suse.de>> wrote:

+/* Expand the IFN_DEFERRED_INIT function according to its second
argument.  */
+static void
+expand_DEFERRED_INIT (internal_fn, gcall *stmt)
+{
+  tree var = gimple_call_lhs (stmt);
+  tree init = NULL_TREE;
+  enum auto_init_type init_type
+    = (enum auto_init_type) TREE_INT_CST_LOW (gimple_call_arg (stmt, 1));
+
+  switch (init_type)
+    {
+    default:
+      gcc_unreachable ();
+    case AUTO_INIT_PATTERN:
+      init = build_pattern_cst_for_auto_init (TREE_TYPE (var));
+      expand_assignment (var, init, false);
+      break;
+    case AUTO_INIT_ZERO:
+      init = build_zero_cst (TREE_TYPE (var));
+      expand_assignment (var, init, false);
+      break;
+    }

I think actually building build_pattern_cst_for_auto_init can generate
massive garbage and for big auto vars code size is also a concern and
ideally on x86 you'd produce rep movq.  So I don't think going
via expand_assignment is good.  Instead you possibly want to lower
.DEFERRED_INIT to MEMs following expand_builtin_memset and
eventually enhance that to allow storing pieces larger than a byte.

Due to “BOOLEAN_TYPE” and “POINTER_TYPE”, we cannot always have a
repeated byte-pattern for variables that include BOOLEAN_TYPE Or Pointer
types. Therefore, lowering the .DEFERRED_INIT for “PATTERN”
initialization through “memset” is not always possible.

Let me know if I miss anything in the above. Do you have other suggestions?

The main point is that you need to avoid building the explicit initializer
only to have it consumed by assignment expansion.  If you want to keep
all the singing and dancing (as opposed to maybe initializing with a
0x1 byte pattern) then I think for efficiency you still want to
block-initialize the variable and then only fixup the special fields.

Yes, this is a good idea.

We can memset the whole structure with repeated pattern “0xAA” first,
Then mixup BOOLEAN_TYPE and POINTER TYPE for 32-bit platform.
That might be more efficient.

However, after more consideration, I feel that this might be a more general optimization for “store_constructor” itself:

I.e,  if the “constructor” includes repeated byte value “0xAA” or any other value over a certain threshold,
i.e, 70% of the total size, then we might need to use a call to memset first, and then emit some additional single
field stores  to fix up the fields that have different initialization values?

Just like the current handling of “zeroes” in the current “store_constructor”, if “zeroes” occupy most of the constructor, then
“Clear the whole structure” first, then emit additional single field stories to fix up other fields that do not hold zeros.

So, I think that it might be better to keep the current “expand_assignment”  for “Pattern initialization” as it is in this patch.

And then, later we can  add a separate patch to add this more general optimization in “store_constructor” to improve the
run time performance and code size in general?

What’s your opinion on this?

Qing


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH][version 3]add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-06-14 16:10         ` Qing Zhao
@ 2021-06-15 13:21           ` Richard Biener
  2021-06-15 21:49             ` Qing Zhao
  0 siblings, 1 reply; 57+ messages in thread
From: Richard Biener @ 2021-06-15 13:21 UTC (permalink / raw)
  To: Qing Zhao; +Cc: Kees cook, richard Sandiford, gcc-patches Qing Zhao via

On Mon, 14 Jun 2021, Qing Zhao wrote:

> Hi, Richard:
> 
> On Jun 11, 2021, at 10:49 AM, Qing Zhao via Gcc-patches <gcc-patches@gcc.gnu.org<mailto:gcc-patches@gcc.gnu.org>> wrote:
> 
> 
> On May 26, 2021, at 6:18 AM, Richard Biener <rguenther@suse.de<mailto:rguenther@suse.de>> wrote:
> 
> +/* Expand the IFN_DEFERRED_INIT function according to its second
> argument.  */
> +static void
> +expand_DEFERRED_INIT (internal_fn, gcall *stmt)
> +{
> +  tree var = gimple_call_lhs (stmt);
> +  tree init = NULL_TREE;
> +  enum auto_init_type init_type
> +    = (enum auto_init_type) TREE_INT_CST_LOW (gimple_call_arg (stmt, 1));
> +
> +  switch (init_type)
> +    {
> +    default:
> +      gcc_unreachable ();
> +    case AUTO_INIT_PATTERN:
> +      init = build_pattern_cst_for_auto_init (TREE_TYPE (var));
> +      expand_assignment (var, init, false);
> +      break;
> +    case AUTO_INIT_ZERO:
> +      init = build_zero_cst (TREE_TYPE (var));
> +      expand_assignment (var, init, false);
> +      break;
> +    }
> 
> I think actually building build_pattern_cst_for_auto_init can generate
> massive garbage and for big auto vars code size is also a concern and
> ideally on x86 you'd produce rep movq.  So I don't think going
> via expand_assignment is good.  Instead you possibly want to lower
> .DEFERRED_INIT to MEMs following expand_builtin_memset and
> eventually enhance that to allow storing pieces larger than a byte.
> 
> Due to “BOOLEAN_TYPE” and “POINTER_TYPE”, we cannot always have a
> repeated byte-pattern for variables that include BOOLEAN_TYPE Or Pointer
> types. Therefore, lowering the .DEFERRED_INIT for “PATTERN”
> initialization through “memset” is not always possible.
> 
> Let me know if I miss anything in the above. Do you have other suggestions?
> 
> The main point is that you need to avoid building the explicit initializer
> only to have it consumed by assignment expansion.  If you want to keep
> all the singing and dancing (as opposed to maybe initializing with a
> 0x1 byte pattern) then I think for efficiency you still want to
> block-initialize the variable and then only fixup the special fields.
> 
> Yes, this is a good idea.
> 
> We can memset the whole structure with repeated pattern “0xAA” first,
> Then mixup BOOLEAN_TYPE and POINTER TYPE for 32-bit platform.
> That might be more efficient.
> 
> However, after more consideration, I feel that this might be a more 
> general optimization for “store_constructor” itself:
> 
> I.e,  if the “constructor” includes repeated byte value “0xAA” or any other value over a certain threshold,
> i.e, 70% of the total size, then we might need to use a call to memset first, and then emit some additional single
> field stores  to fix up the fields that have different initialization values?
> 
> Just like the current handling of “zeroes” in the current “store_constructor”, if “zeroes” occupy most of the constructor, then
> “Clear the whole structure” first, then emit additional single field stories to fix up other fields that do not hold zeros.
> 
> So, I think that it might be better to keep the current 
> “expand_assignment” for “Pattern initialization” as it is in this patch.
> 
> And then, later we can add a separate patch to add this more general 
> optimization in “store_constructor” to improve the run time performance 
> and code size in general?
> 
> What’s your opinion on this?

My point is that _building_ the constructor is what we want to avoid
since that involves a lot of overhead memory-wise, it also requires
yet another complex structure field walk with much room for errors.

Block-initializing the object is so much easier and more efficient.
Implementing block initialization with a block size different from
a single byte should be also reasonably possible.  I mean there's
wmemset (not in GCC), so such block initialization would have other
uses as well.

I'm going to repeatedly point at those large chunks of code that
handle padding and building the CTOR - I don't even want to review
them ;)  They should not exist (thus also my suggestion to split out
padding handling - now we can also split out pattern init handling,
maybe somebody else feels like reviewing and approving this, who knows).

Now, what you _could_ try is do sth like

  tree ar = build_array_type (uint_ptr_type_node, size_type_node, false);
  tree range = build2 (RANGE_EXPR, size_type_node,
                       size_zero_node, build_int_cst (size_type_node, 
size-in-words));
  tree pattern = build_int_cst (uint_ptr_type_node, 0xdeadbeef);
  ctor = build_constructor_single (ar, range, pattern);
  ctor = build1 (VIEW_CONVERT_EXPR, type, ctor);

thus build a range-init CTOR of an array of pointer-sized elements
but do the actual assignment to the target object by viewing that
as the target objects type.  That should block-initialize with
a uint_ptr_type_node sized pattern (but likely less efficient than
special block init would do).

Not sure what problems you will run into this, you'll have to try.

Richard.

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH][version 3]add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-06-15 13:21           ` Richard Biener
@ 2021-06-15 21:49             ` Qing Zhao
  2021-06-16  6:19               ` Richard Biener
  0 siblings, 1 reply; 57+ messages in thread
From: Qing Zhao @ 2021-06-15 21:49 UTC (permalink / raw)
  To: Richard Biener; +Cc: Kees cook, richard Sandiford, gcc-patches Qing Zhao via

Hi, Richard,


> On Jun 15, 2021, at 8:21 AM, Richard Biener <rguenther@suse.de> wrote:
>> 
>> 
>> +/* Expand the IFN_DEFERRED_INIT function according to its second
>> argument.  */
>> +static void
>> +expand_DEFERRED_INIT (internal_fn, gcall *stmt)
>> +{
>> +  tree var = gimple_call_lhs (stmt);
>> +  tree init = NULL_TREE;
>> +  enum auto_init_type init_type
>> +    = (enum auto_init_type) TREE_INT_CST_LOW (gimple_call_arg (stmt, 1));
>> +
>> +  switch (init_type)
>> +    {
>> +    default:
>> +      gcc_unreachable ();
>> +    case AUTO_INIT_PATTERN:
>> +      init = build_pattern_cst_for_auto_init (TREE_TYPE (var));
>> +      expand_assignment (var, init, false);
>> +      break;
>> +    case AUTO_INIT_ZERO:
>> +      init = build_zero_cst (TREE_TYPE (var));
>> +      expand_assignment (var, init, false);
>> +      break;
>> +    }
>> 
>> I think actually building build_pattern_cst_for_auto_init can generate
>> massive garbage and for big auto vars code size is also a concern and
>> ideally on x86 you'd produce rep movq.  So I don't think going
>> via expand_assignment is good.  Instead you possibly want to lower
>> .DEFERRED_INIT to MEMs following expand_builtin_memset and
>> eventually enhance that to allow storing pieces larger than a byte.
>> 
>> Due to “BOOLEAN_TYPE” and “POINTER_TYPE”, we cannot always have a
>> repeated byte-pattern for variables that include BOOLEAN_TYPE Or Pointer
>> types. Therefore, lowering the .DEFERRED_INIT for “PATTERN”
>> initialization through “memset” is not always possible.
>> 
>> Let me know if I miss anything in the above. Do you have other suggestions?
>> 
>> The main point is that you need to avoid building the explicit initializer
>> only to have it consumed by assignment expansion.  If you want to keep
>> all the singing and dancing (as opposed to maybe initializing with a
>> 0x1 byte pattern) then I think for efficiency you still want to
>> block-initialize the variable and then only fixup the special fields.
>> 
>> Yes, this is a good idea.
>> 
>> We can memset the whole structure with repeated pattern “0xAA” first,
>> Then mixup BOOLEAN_TYPE and POINTER TYPE for 32-bit platform.
>> That might be more efficient.
>> 
>> However, after more consideration, I feel that this might be a more 
>> general optimization for “store_constructor” itself:
>> 
>> I.e,  if the “constructor” includes repeated byte value “0xAA” or any other value over a certain threshold,
>> i.e, 70% of the total size, then we might need to use a call to memset first, and then emit some additional single
>> field stores  to fix up the fields that have different initialization values?
>> 
>> Just like the current handling of “zeroes” in the current “store_constructor”, if “zeroes” occupy most of the constructor, then
>> “Clear the whole structure” first, then emit additional single field stories to fix up other fields that do not hold zeros.
>> 
>> So, I think that it might be better to keep the current 
>> “expand_assignment” for “Pattern initialization” as it is in this patch.
>> 
>> And then, later we can add a separate patch to add this more general 
>> optimization in “store_constructor” to improve the run time performance 
>> and code size in general?
>> 
>> What’s your opinion on this?
> 
> My point is that _building_ the constructor is what we want to avoid
> since that involves a lot of overhead memory-wise, it also requires
> yet another complex structure field walk with much room for errors.

So, you mean I should completely get rid of the new added routine 
“build_pattern_cst_for_auto_init”, since it built constructors for RECORD,
UNION, and ARRAY types.  And the current RTL expansion of constructor 
assignment is not efficient enough for pattern initialization purpose? 

> 
> Block-initializing the object is so much easier and more efficient.
> Implementing block initialization with a block size different from
> a single byte should be also reasonably possible.  I mean there's
> wmemset (not in GCC), so such block initialization would have other
> uses as well.

If the pattern of the value that is used to initialize is repeatable, then 
Block-initializing is ideal. However, Since the patterns of the values that
are used to initialize might not be completely repeatable due to BOOLEAN (0),
POINTER_TYPE at 32-bit platform (0x000000AA) and FLOATING TYPE (NaN), 
After block initializing of the whole object, we still need to add additional fix up 
stores of these different patterns to the corresponding fields. 

For some of the objects whose most fields are BOOLEAN, POINTER_TYPE, 
rr FLOATING_TYPE, pattern  initializing likee this might be less efficient. Do you 
agree on this?


> 
> I'm going to repeatedly point at those large chunks of code that
> handle padding and building the CTOR - I don't even want to review
> them ;)  They should not exist

So, just want to confirm -:),  do you mean to completely delete the routine 
“build_pattern_cst_for_auto_init”? And then use the approach you suggested below
to replace this part of work?

> (thus also my suggestion to split out
> padding handling - now we can also split out pattern init handling,
> maybe somebody else feels like reviewing and approving this, who knows).

I am okay with further splitting pattern initialization part to a separate patch. Then we will
have 4 independent patches in total:

1. -fauto-var-init=zero and all the handling in other passes to the new added call to .DEFERRED_INIT.
2. Add -fauto-var-init=pattern 
3. Add -fauto-var-init-padding
4. Add -ftrivial-auto-var-init for CLANG compatibility. 

Are the above the correct understanding?

> 
> Now, what you _could_ try is do sth like
> 
>  tree ar = build_array_type (uint_ptr_type_node, size_type_node, false);
>  tree range = build2 (RANGE_EXPR, size_type_node,
>                       size_zero_node, build_int_cst (size_type_node, 
> size-in-words));
>  tree pattern = build_int_cst (uint_ptr_type_node, 0xdeadbeef);
>  ctor = build_constructor_single (ar, range, pattern);
>  ctor = build1 (VIEW_CONVERT_EXPR, type, ctor);


So, the above will be used to replace the following original code in my patch:

>> +    case AUTO_INIT_PATTERN:
>> +      init = build_pattern_cst_for_auto_init (TREE_TYPE (var));
>> +      expand_assignment (var, init, false);
>> +      break;

?

> 
> thus build a range-init CTOR of an array of pointer-sized elements
> but do the actual assignment to the target object by viewing that
> as the target objects type.  

Okay.

So, for a target object that is smaller than a word, for example, BOOLEAN, 
CHAR or short, is the above still working?

> That should block-initialize with
> a uint_ptr_type_node sized pattern (but likely less efficient than
> special block init would do).
> 
> Not sure what problems you will run into this, you'll have to try.

I will try this.

Thanks a lot for your suggestions.

Qing
> 
> Richard.


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH][version 3]add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-06-15 21:49             ` Qing Zhao
@ 2021-06-16  6:19               ` Richard Biener
  2021-06-16 15:04                 ` Qing Zhao
  0 siblings, 1 reply; 57+ messages in thread
From: Richard Biener @ 2021-06-16  6:19 UTC (permalink / raw)
  To: Qing Zhao; +Cc: Kees cook, richard Sandiford, gcc-patches Qing Zhao via

On Tue, 15 Jun 2021, Qing Zhao wrote:

> Hi, Richard,
> 
> 
> > On Jun 15, 2021, at 8:21 AM, Richard Biener <rguenther@suse.de> wrote:
> >> 
> >> 
> >> +/* Expand the IFN_DEFERRED_INIT function according to its second
> >> argument.  */
> >> +static void
> >> +expand_DEFERRED_INIT (internal_fn, gcall *stmt)
> >> +{
> >> +  tree var = gimple_call_lhs (stmt);
> >> +  tree init = NULL_TREE;
> >> +  enum auto_init_type init_type
> >> +    = (enum auto_init_type) TREE_INT_CST_LOW (gimple_call_arg (stmt, 1));
> >> +
> >> +  switch (init_type)
> >> +    {
> >> +    default:
> >> +      gcc_unreachable ();
> >> +    case AUTO_INIT_PATTERN:
> >> +      init = build_pattern_cst_for_auto_init (TREE_TYPE (var));
> >> +      expand_assignment (var, init, false);
> >> +      break;
> >> +    case AUTO_INIT_ZERO:
> >> +      init = build_zero_cst (TREE_TYPE (var));
> >> +      expand_assignment (var, init, false);
> >> +      break;
> >> +    }
> >> 
> >> I think actually building build_pattern_cst_for_auto_init can generate
> >> massive garbage and for big auto vars code size is also a concern and
> >> ideally on x86 you'd produce rep movq.  So I don't think going
> >> via expand_assignment is good.  Instead you possibly want to lower
> >> .DEFERRED_INIT to MEMs following expand_builtin_memset and
> >> eventually enhance that to allow storing pieces larger than a byte.
> >> 
> >> Due to “BOOLEAN_TYPE” and “POINTER_TYPE”, we cannot always have a
> >> repeated byte-pattern for variables that include BOOLEAN_TYPE Or Pointer
> >> types. Therefore, lowering the .DEFERRED_INIT for “PATTERN”
> >> initialization through “memset” is not always possible.
> >> 
> >> Let me know if I miss anything in the above. Do you have other suggestions?
> >> 
> >> The main point is that you need to avoid building the explicit initializer
> >> only to have it consumed by assignment expansion.  If you want to keep
> >> all the singing and dancing (as opposed to maybe initializing with a
> >> 0x1 byte pattern) then I think for efficiency you still want to
> >> block-initialize the variable and then only fixup the special fields.
> >> 
> >> Yes, this is a good idea.
> >> 
> >> We can memset the whole structure with repeated pattern “0xAA” first,
> >> Then mixup BOOLEAN_TYPE and POINTER TYPE for 32-bit platform.
> >> That might be more efficient.
> >> 
> >> However, after more consideration, I feel that this might be a more 
> >> general optimization for “store_constructor” itself:
> >> 
> >> I.e,  if the “constructor” includes repeated byte value “0xAA” or any other value over a certain threshold,
> >> i.e, 70% of the total size, then we might need to use a call to memset first, and then emit some additional single
> >> field stores  to fix up the fields that have different initialization values?
> >> 
> >> Just like the current handling of “zeroes” in the current “store_constructor”, if “zeroes” occupy most of the constructor, then
> >> “Clear the whole structure” first, then emit additional single field stories to fix up other fields that do not hold zeros.
> >> 
> >> So, I think that it might be better to keep the current 
> >> “expand_assignment” for “Pattern initialization” as it is in this patch.
> >> 
> >> And then, later we can add a separate patch to add this more general 
> >> optimization in “store_constructor” to improve the run time performance 
> >> and code size in general?
> >> 
> >> What’s your opinion on this?
> > 
> > My point is that _building_ the constructor is what we want to avoid
> > since that involves a lot of overhead memory-wise, it also requires
> > yet another complex structure field walk with much room for errors.
> 
> So, you mean I should completely get rid of the new added routine 
> “build_pattern_cst_for_auto_init”, since it built constructors for RECORD,
> UNION, and ARRAY types.

Yes.

> And the current RTL expansion of constructor 
> assignment is not efficient enough for pattern initialization purpose? 

Well, it is the wrong tool to use.  It's efficient for initialization
from a constructor but building a constructor and assigning from it
is not an efficient way to do pattern init.

> > 
> > Block-initializing the object is so much easier and more efficient.
> > Implementing block initialization with a block size different from
> > a single byte should be also reasonably possible.  I mean there's
> > wmemset (not in GCC), so such block initialization would have other
> > uses as well.
> 
> If the pattern of the value that is used to initialize is repeatable, then 
> Block-initializing is ideal. However, Since the patterns of the values that
> are used to initialize might not be completely repeatable due to BOOLEAN (0),
> POINTER_TYPE at 32-bit platform (0x000000AA) and FLOATING TYPE (NaN), 
> After block initializing of the whole object, we still need to add additional fix up 
> stores of these different patterns to the corresponding fields. 

But that's a bug with the pattern used then.  You can never be sure that
an object is used only as its declared type but you are initializing it
as if it were.  Also all uninit uses invoke undefined behavior so I don't
see why you need to pay special attention here.  After all this makes
pattern init so much more fragile than zero-init which makes me question
it even more ...

> For some of the objects whose most fields are BOOLEAN, POINTER_TYPE, 
> rr FLOATING_TYPE, pattern  initializing likee this might be less efficient. Do you 
> agree on this?

Use a pattern that fits them all.  I mean memory allocation hardening
fills allocated storage with a repeated (byte) pattern and people are
happy with that.  It also makes it easy to spot uninitialized storage
from a debugger.  So please, do not over-design this, it really doesn't
make any sense and the common case you are inevitably chasing here
would already be fine with a random repeated pattern.

> > I'm going to repeatedly point at those large chunks of code that
> > handle padding and building the CTOR - I don't even want to review
> > them ;)  They should not exist
> 
> So, just want to confirm -:),  do you mean to completely delete the routine 
> “build_pattern_cst_for_auto_init”? And then use the approach you suggested below
> to replace this part of work?

Yes.

> > (thus also my suggestion to split out
> > padding handling - now we can also split out pattern init handling,
> > maybe somebody else feels like reviewing and approving this, who knows).
> 
> I am okay with further splitting pattern initialization part to a separate patch. Then we will
> have 4 independent patches in total:
> 
> 1. -fauto-var-init=zero and all the handling in other passes to the new added call to .DEFERRED_INIT.
> 2. Add -fauto-var-init=pattern 
> 3. Add -fauto-var-init-padding
> 4. Add -ftrivial-auto-var-init for CLANG compatibility. 
> 
> Are the above the correct understanding?

As said, block-initializing with a repeated pattern is OK and I can see
that being useful.  Trying to produce "nicer" values for floats, bools
and pointers on 32bit platforms is IMHO not going to fix anything and
introduce as many problems as it will "fix".

And if you block-initialize stuff you then automagically cover padding.
I call this a win-win, no?

> > 
> > Now, what you _could_ try is do sth like
> > 
> >  tree ar = build_array_type (uint_ptr_type_node, size_type_node, false);
> >  tree range = build2 (RANGE_EXPR, size_type_node,
> >                       size_zero_node, build_int_cst (size_type_node, 
> > size-in-words));
> >  tree pattern = build_int_cst (uint_ptr_type_node, 0xdeadbeef);
> >  ctor = build_constructor_single (ar, range, pattern);
> >  ctor = build1 (VIEW_CONVERT_EXPR, type, ctor);
> 
> 
> So, the above will be used to replace the following original code in my patch:
> 
> >> +    case AUTO_INIT_PATTERN:
> >> +      init = build_pattern_cst_for_auto_init (TREE_TYPE (var));
> >> +      expand_assignment (var, init, false);
> >> +      break;
> 
> ?

in my example code (untested) you then still need

   expand_assignment (var, ctor, false);

it would be the easiest way to try pattern init with a pattern that's
bigger than a byte (otherwise of course the memset path is optimal).

> > 
> > thus build a range-init CTOR of an array of pointer-sized elements
> > but do the actual assignment to the target object by viewing that
> > as the target objects type.  
> 
> Okay.
> 
> So, for a target object that is smaller than a word, for example, BOOLEAN, 
> CHAR or short, is the above still working?

Well, you obviously have to adjust that - you can't pattern-init
a BOOL with word-size stores of a word-size pattern.

As said, for example glibc allocator hardening with MALLOC_PERTURB_
uses simple byte-init.

> > That should block-initialize with
> > a uint_ptr_type_node sized pattern (but likely less efficient than
> > special block init would do).
> > 
> > Not sure what problems you will run into this, you'll have to try.
> 
> I will try this.
> 
> Thanks a lot for your suggestions.
> 
> Qing
> > 
> > Richard.
> 
> 

-- 
Richard Biener <rguenther@suse.de>
SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
Germany; GF: Felix Imendörffer; HRB 36809 (AG Nuernberg)

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH][version 3]add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-06-16  6:19               ` Richard Biener
@ 2021-06-16 15:04                 ` Qing Zhao
  2021-06-16 19:39                   ` Qing Zhao
  2021-06-21  7:53                   ` Richard Biener
  0 siblings, 2 replies; 57+ messages in thread
From: Qing Zhao @ 2021-06-16 15:04 UTC (permalink / raw)
  To: Richard Biener; +Cc: Kees cook, richard Sandiford, gcc-patches Qing Zhao via

Hi, Richard,

On Jun 16, 2021, at 1:19 AM, Richard Biener <rguenther@suse.de<mailto:rguenther@suse.de>> wrote:

+/* Expand the IFN_DEFERRED_INIT function according to its second
argument.  */
+static void
+expand_DEFERRED_INIT (internal_fn, gcall *stmt)
+{
+  tree var = gimple_call_lhs (stmt);
+  tree init = NULL_TREE;
+  enum auto_init_type init_type
+    = (enum auto_init_type) TREE_INT_CST_LOW (gimple_call_arg (stmt, 1));
+
+  switch (init_type)
+    {
+    default:
+      gcc_unreachable ();
+    case AUTO_INIT_PATTERN:
+      init = build_pattern_cst_for_auto_init (TREE_TYPE (var));
+      expand_assignment (var, init, false);
+      break;
+    case AUTO_INIT_ZERO:
+      init = build_zero_cst (TREE_TYPE (var));
+      expand_assignment (var, init, false);
+      break;
+    }

I think actually building build_pattern_cst_for_auto_init can generate
massive garbage and for big auto vars code size is also a concern and
ideally on x86 you'd produce rep movq.  So I don't think going
via expand_assignment is good.  Instead you possibly want to lower
.DEFERRED_INIT to MEMs following expand_builtin_memset and
eventually enhance that to allow storing pieces larger than a byte.

Due to “BOOLEAN_TYPE” and “POINTER_TYPE”, we cannot always have a
repeated byte-pattern for variables that include BOOLEAN_TYPE Or Pointer
types. Therefore, lowering the .DEFERRED_INIT for “PATTERN”
initialization through “memset” is not always possible.

Let me know if I miss anything in the above. Do you have other suggestions?

The main point is that you need to avoid building the explicit initializer
only to have it consumed by assignment expansion.  If you want to keep
all the singing and dancing (as opposed to maybe initializing with a
0x1 byte pattern) then I think for efficiency you still want to
block-initialize the variable and then only fixup the special fields.

Yes, this is a good idea.

We can memset the whole structure with repeated pattern “0xAA” first,
Then mixup BOOLEAN_TYPE and POINTER TYPE for 32-bit platform.
That might be more efficient.

However, after more consideration, I feel that this might be a more
general optimization for “store_constructor” itself:

I.e,  if the “constructor” includes repeated byte value “0xAA” or any other value over a certain threshold,
i.e, 70% of the total size, then we might need to use a call to memset first, and then emit some additional single
field stores  to fix up the fields that have different initialization values?

Just like the current handling of “zeroes” in the current “store_constructor”, if “zeroes” occupy most of the constructor, then
“Clear the whole structure” first, then emit additional single field stories to fix up other fields that do not hold zeros.

So, I think that it might be better to keep the current
“expand_assignment” for “Pattern initialization” as it is in this patch.

And then, later we can add a separate patch to add this more general
optimization in “store_constructor” to improve the run time performance
and code size in general?

What’s your opinion on this?

My point is that _building_ the constructor is what we want to avoid
since that involves a lot of overhead memory-wise, it also requires
yet another complex structure field walk with much room for errors.

Block-initializing the object is so much easier and more efficient.
Implementing block initialization with a block size different from
a single byte should be also reasonably possible.  I mean there's
wmemset (not in GCC), so such block initialization would have other
uses as well.

If the pattern of the value that is used to initialize is repeatable, then
Block-initializing is ideal. However, Since the patterns of the values that
are used to initialize might not be completely repeatable due to BOOLEAN (0),
POINTER_TYPE at 32-bit platform (0x000000AA) and FLOATING TYPE (NaN),
After block initializing of the whole object, we still need to add additional fix up
stores of these different patterns to the corresponding fields.

But that's a bug with the pattern used then.  You can never be sure that
an object is used only as its declared type but you are initializing it
as if it were.  Also all uninit uses invoke undefined behavior so I don't
see why you need to pay special attention here.  After all this makes
pattern init so much more fragile than zero-init which makes me question
it even more ...

Yes, you are right.  The major reason for the complexity of the code to handle pattern initialization
is because multiple different patterns are assigned to different types.

This is for the compatibility with CLANG. -:). (https://reviews.llvm.org/D54604)

For reference, I copied the part for pattern initialization from CLANG’s patch below:


1. Pattern initialization

  This is the recommended initialization approach. Pattern initialization's
  goal is to initialize automatic variables with values which will likely
  transform logic bugs into crashes down the line, are easily recognizable in
  a crash dump, without being values which programmers can rely on for useful
  program semantics. At the same time, pattern initialization tries to
  generate code which will optimize well. You'll find the following details in
  `patternFor`:

  - Integers are initialized with repeated 0xAA bytes (infinite scream).
  - Vectors of integers are also initialized with infinite scream.
  - Pointers are initialized with infinite scream on 64-bit platforms because
    it's an unmappable pointer value on architectures I'm aware of. Pointers
    are initialize to 0x000000AA (small scream) on 32-bit platforms because
    32-bit platforms don't consistently offer unmappable pages. When they do
    it's usually the zero page. As people try this out, I expect that we'll
    want to allow different platforms to customize this, let's do so later.
  - Vectors of pointers are initialized the same way pointers are.
  - Floating point values and vectors are initialized with a negative quiet NaN
    with repeated 0xFF payload (e.g. 0xffffffff and 0xffffffffffffffff). NaNs are nice
    (here, anways) because they propagate on arithmetic, making it more likely
    that entire computations become NaN when a single uninitialized value
    sneaks in.
  - Arrays are initialized to their homogeneous elements' initialization
    value, repeated. Stack-based Variable-Length Arrays (VLAs) are
    runtime-initialized to the allocated size (no effort is made for negative
    size, but zero-sized VLAs are untouched even if technically undefined).
  - Structs are initialized to their heterogeneous element's initialization
    values. Zero-size structs are initialized as 0xAA since they're allocated
    a single byte.
  - Unions are initialized using the initialization for the largest member of
    the union.

  Expect the values used for pattern initialization to change over time, as we
  refine heuristics (both for performance and security). The goal is truly to
  avoid injecting semantics into undefined behavior, and we should be
  comfortable changing these values when there's a worthwhile point in doing
  so.

  Why so much infinite scream? Repeated byte patterns tend to be easy to
  synthesize on most architectures, and otherwise memset is usually very
  efficient. For values which aren't entirely repeated byte patterns, LLVM
  will often generate code which does memset + a few stores.




For some of the objects whose most fields are BOOLEAN, POINTER_TYPE,
rr FLOATING_TYPE, pattern  initializing likee this might be less efficient. Do you
agree on this?

Use a pattern that fits them all.  I mean memory allocation hardening
fills allocated storage with a repeated (byte) pattern and people are
happy with that.  It also makes it easy to spot uninitialized storage
from a debugger.  So please, do not over-design this, it really doesn't
make any sense and the common case you are inevitably chasing here
would already be fine with a random repeated pattern.

So, My question is:

If we want to pattern initialize with the single repeated pattern for all types, with one is better to use:  “0xAAAAAAAA”
or “0xFFFFFFFF” , or other pattern that our current glibc used? What’s that pattern?

Will  “0xAAAAAAAA” in a floating type auto variable crash the program?
Will “0xFFFFFFFF” in a pointer type auto variable crash the program? (Might crash?)


(thus also my suggestion to split out
padding handling - now we can also split out pattern init handling,
maybe somebody else feels like reviewing and approving this, who knows).

I am okay with further splitting pattern initialization part to a separate patch. Then we will
have 4 independent patches in total:

1. -fauto-var-init=zero and all the handling in other passes to the new added call to .DEFERRED_INIT.
2. Add -fauto-var-init=pattern
3. Add -fauto-var-init-padding
4. Add -ftrivial-auto-var-init for CLANG compatibility.

Are the above the correct understanding?

As said, block-initializing with a repeated pattern is OK and I can see
that being useful.  Trying to produce "nicer" values for floats, bools
and pointers on 32bit platforms is IMHO not going to fix anything and
introduce as many problems as it will "fix".

Yes, I agree, if we can find a good repeated pattern for all types’s pattern initialization, that will
be much easier and simpler to implement, I am happy to do that.  (Honestly, the part of implementation
that took me most of the time is pattern-initialization.. and I am still not very comfortable with this part
Of the code myself.  -:)


And if you block-initialize stuff you then automagically cover padding.
I call this a win-win, no?

Yes, this will also initialize paddings with patterns (Not zeroes as CLANG did).
Shall we compatible with CLANG on this?


Now, what you _could_ try is do sth like

tree ar = build_array_type (uint_ptr_type_node, size_type_node, false);
tree range = build2 (RANGE_EXPR, size_type_node,
                     size_zero_node, build_int_cst (size_type_node,
size-in-words));
tree pattern = build_int_cst (uint_ptr_type_node, 0xdeadbeef);
ctor = build_constructor_single (ar, range, pattern);
ctor = build1 (VIEW_CONVERT_EXPR, type, ctor);


So, the above will be used to replace the following original code in my patch:

+    case AUTO_INIT_PATTERN:
+      init = build_pattern_cst_for_auto_init (TREE_TYPE (var));
+      expand_assignment (var, init, false);
+      break;

?

in my example code (untested) you then still need

  expand_assignment (var, ctor, false);

it would be the easiest way to try pattern init with a pattern that's
bigger than a byte (otherwise of course the memset path is optimal).

If the pattern that is used to initialize all types is byte-repeatable, for example, 0xA or 0xF, then
We can use memset to initialize all types, however, the potential problem is, if later we decide
To change to another pattern that might not be byte-repeatable, then the memset implementation
is not proper at that time.

Is it possible that we might change the pattern later?



thus build a range-init CTOR of an array of pointer-sized elements
but do the actual assignment to the target object by viewing that
as the target objects type.

Okay.

So, for a target object that is smaller than a word, for example, BOOLEAN,
CHAR or short, is the above still working?

Well, you obviously have to adjust that - you can't pattern-init
a BOOL with word-size stores of a word-size pattern.

As said, for example glibc allocator hardening with MALLOC_PERTURB_
uses simple byte-init.

What’s the pattern glibc used?

Thanks a lot.

Qing

That should block-initialize with
a uint_ptr_type_node sized pattern (but likely less efficient than
special block init would do).

Not sure what problems you will run into this, you'll have to try.

I will try this.

Thanks a lot for your suggestions.

Qing

Richard.



--
Richard Biener <rguenther@suse.de<mailto:rguenther@suse.de>>
SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
Germany; GF: Felix Imendörffer; HRB 36809 (AG Nuernberg)


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH][version 3]add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-06-16 15:04                 ` Qing Zhao
@ 2021-06-16 19:39                   ` Qing Zhao
  2021-06-18 23:47                     ` Kees Cook
  2021-06-21  7:53                   ` Richard Biener
  1 sibling, 1 reply; 57+ messages in thread
From: Qing Zhao @ 2021-06-16 19:39 UTC (permalink / raw)
  To: Richard Biener, Kees cook
  Cc: richard Sandiford, gcc-patches Qing Zhao via, Kees cook

So, the major question now is:

Is one single repeatable pattern enough for pattern initialization for all different types of auto variables?

If YES, then the implementation for pattern initialization will be much easier and simpler
      as you pointed out. And will save me a lot of pain to implement this part.
If NO, then we have to keep the current complicate implementation since it provides us
      the flexibility to assign different patterns to different types.

Honestly, I don’t have a good justification on this question myself.

The previous references I have so far are the current behavior of CLANG and Microsoft compiler.

For your reference,
. CLANG uses different patterns for INTEGER  (0xAAAAAAAA) and FLOAT (0xFFFFFFFF) and 32-bit pointer (0x000000AA)
https://reviews.llvm.org/D54604
. Microsoft uses different patterns for INTEGERS ( 0xE2), FLOAT (1.0)
https://msrc-blog.microsoft.com/2020/05/13/solving-uninitialized-stack-memory-on-windows/

My understanding from CLANG’s comment is, the patterns are easier to crash the program for the certain type, therefore easier to
catch any potential bugs.
Don’t know why Microsoft chose the pattern like this.

So, For GCC, what should we do on the pattern initializations, shall we choose one single repeatable pattern for all the types as you suggested,
Or chose different patterns for different types as Clang and Microsoft compiler’s behavior?

Kees, do you have any comment on this?

How did Linux Kernel use -ftrivial-auto-var-init=pattern feature of CLANG?

Thanks.

Qing




^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH][version 3]add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-06-16 19:39                   ` Qing Zhao
@ 2021-06-18 23:47                     ` Kees Cook
  2021-06-21 15:39                       ` Qing Zhao
  0 siblings, 1 reply; 57+ messages in thread
From: Kees Cook @ 2021-06-18 23:47 UTC (permalink / raw)
  To: Qing Zhao; +Cc: Richard Biener, richard Sandiford, gcc-patches Qing Zhao via

On Wed, Jun 16, 2021 at 07:39:02PM +0000, Qing Zhao wrote:
> So, the major question now is:
> 
> Is one single repeatable pattern enough for pattern initialization for all different types of auto variables?
> 
> If YES, then the implementation for pattern initialization will be much easier and simpler
>       as you pointed out. And will save me a lot of pain to implement this part.
> If NO, then we have to keep the current complicate implementation since it provides us
>       the flexibility to assign different patterns to different types.
> 
> Honestly, I don’t have a good justification on this question myself.
> 
> The previous references I have so far are the current behavior of CLANG and Microsoft compiler.
> 
> For your reference,
> . CLANG uses different patterns for INTEGER  (0xAAAAAAAA) and FLOAT (0xFFFFFFFF) and 32-bit pointer (0x000000AA)
> https://reviews.llvm.org/D54604
> . Microsoft uses different patterns for INTEGERS ( 0xE2), FLOAT (1.0)
> https://msrc-blog.microsoft.com/2020/05/13/solving-uninitialized-stack-memory-on-windows/
> 
> My understanding from CLANG’s comment is, the patterns are easier to crash the program for the certain type, therefore easier to
> catch any potential bugs.

Right, this is the justification for the different patterns. I am
fine with a static value for the first version of this functionality,
as long as it's a non-canonical virtual memory address when evaluated
as a pointer (so that the pattern can't be made to aim at a legitimate
fixed allocatable address in memory).

> Don’t know why Microsoft chose the pattern like this.
> 
> So, For GCC, what should we do on the pattern initializations, shall we choose one single repeatable pattern for all the types as you suggested,
> Or chose different patterns for different types as Clang and Microsoft compiler’s behavior?
> 
> Kees, do you have any comment on this?
> 
> How did Linux Kernel use -ftrivial-auto-var-init=pattern feature of CLANG?

It's just used as-is from the compiler, and recommended for "debug
builds".

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH][version 3]add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-06-16 15:04                 ` Qing Zhao
  2021-06-16 19:39                   ` Qing Zhao
@ 2021-06-21  7:53                   ` Richard Biener
  2021-06-21 15:11                     ` Qing Zhao
  1 sibling, 1 reply; 57+ messages in thread
From: Richard Biener @ 2021-06-21  7:53 UTC (permalink / raw)
  To: Qing Zhao; +Cc: Kees cook, richard Sandiford, gcc-patches Qing Zhao via

On Wed, 16 Jun 2021, Qing Zhao wrote:

> Hi, Richard,
> 
> On Jun 16, 2021, at 1:19 AM, Richard Biener <rguenther@suse.de<mailto:rguenther@suse.de>> wrote:
> 
> +/* Expand the IFN_DEFERRED_INIT function according to its second
> argument.  */
> +static void
> +expand_DEFERRED_INIT (internal_fn, gcall *stmt)
> +{
> +  tree var = gimple_call_lhs (stmt);
> +  tree init = NULL_TREE;
> +  enum auto_init_type init_type
> +    = (enum auto_init_type) TREE_INT_CST_LOW (gimple_call_arg (stmt, 1));
> +
> +  switch (init_type)
> +    {
> +    default:
> +      gcc_unreachable ();
> +    case AUTO_INIT_PATTERN:
> +      init = build_pattern_cst_for_auto_init (TREE_TYPE (var));
> +      expand_assignment (var, init, false);
> +      break;
> +    case AUTO_INIT_ZERO:
> +      init = build_zero_cst (TREE_TYPE (var));
> +      expand_assignment (var, init, false);
> +      break;
> +    }
> 
> I think actually building build_pattern_cst_for_auto_init can generate
> massive garbage and for big auto vars code size is also a concern and
> ideally on x86 you'd produce rep movq.  So I don't think going
> via expand_assignment is good.  Instead you possibly want to lower
> .DEFERRED_INIT to MEMs following expand_builtin_memset and
> eventually enhance that to allow storing pieces larger than a byte.
> 
> Due to “BOOLEAN_TYPE” and “POINTER_TYPE”, we cannot always have a
> repeated byte-pattern for variables that include BOOLEAN_TYPE Or Pointer
> types. Therefore, lowering the .DEFERRED_INIT for “PATTERN”
> initialization through “memset” is not always possible.
> 
> Let me know if I miss anything in the above. Do you have other suggestions?
> 
> The main point is that you need to avoid building the explicit initializer
> only to have it consumed by assignment expansion.  If you want to keep
> all the singing and dancing (as opposed to maybe initializing with a
> 0x1 byte pattern) then I think for efficiency you still want to
> block-initialize the variable and then only fixup the special fields.
> 
> Yes, this is a good idea.
> 
> We can memset the whole structure with repeated pattern “0xAA” first,
> Then mixup BOOLEAN_TYPE and POINTER TYPE for 32-bit platform.
> That might be more efficient.
> 
> However, after more consideration, I feel that this might be a more
> general optimization for “store_constructor” itself:
> 
> I.e,  if the “constructor” includes repeated byte value “0xAA” or any other value over a certain threshold,
> i.e, 70% of the total size, then we might need to use a call to memset first, and then emit some additional single
> field stores  to fix up the fields that have different initialization values?
> 
> Just like the current handling of “zeroes” in the current “store_constructor”, if “zeroes” occupy most of the constructor, then
> “Clear the whole structure” first, then emit additional single field stories to fix up other fields that do not hold zeros.
> 
> So, I think that it might be better to keep the current
> “expand_assignment” for “Pattern initialization” as it is in this patch.
> 
> And then, later we can add a separate patch to add this more general
> optimization in “store_constructor” to improve the run time performance
> and code size in general?
> 
> What’s your opinion on this?
> 
> My point is that _building_ the constructor is what we want to avoid
> since that involves a lot of overhead memory-wise, it also requires
> yet another complex structure field walk with much room for errors.
> 
> Block-initializing the object is so much easier and more efficient.
> Implementing block initialization with a block size different from
> a single byte should be also reasonably possible.  I mean there's
> wmemset (not in GCC), so such block initialization would have other
> uses as well.
> 
> If the pattern of the value that is used to initialize is repeatable, then
> Block-initializing is ideal. However, Since the patterns of the values that
> are used to initialize might not be completely repeatable due to BOOLEAN (0),
> POINTER_TYPE at 32-bit platform (0x000000AA) and FLOATING TYPE (NaN),
> After block initializing of the whole object, we still need to add additional fix up
> stores of these different patterns to the corresponding fields.
> 
> But that's a bug with the pattern used then.  You can never be sure that
> an object is used only as its declared type but you are initializing it
> as if it were.  Also all uninit uses invoke undefined behavior so I don't
> see why you need to pay special attention here.  After all this makes
> pattern init so much more fragile than zero-init which makes me question
> it even more ...
> 
> Yes, you are right.  The major reason for the complexity of the code to handle pattern initialization
> is because multiple different patterns are assigned to different types.
> 
> This is for the compatibility with CLANG. -:). (https://reviews.llvm.org/D54604)

I don't care about functional 1:1 "compatibility" with CLANG.

> For reference, I copied the part for pattern initialization from CLANG’s patch below:
> 
> 
> 1. Pattern initialization
> 
>   This is the recommended initialization approach. Pattern initialization's

But elsewhere you said pattern initialization is only for debugging,
not production ...

>   goal is to initialize automatic variables with values which will likely
>   transform logic bugs into crashes down the line, are easily recognizable in
>   a crash dump, without being values which programmers can rely on for useful
>   program semantics. At the same time, pattern initialization tries to
>   generate code which will optimize well. You'll find the following details in
>   `patternFor`:
> 
>   - Integers are initialized with repeated 0xAA bytes (infinite scream).
>   - Vectors of integers are also initialized with infinite scream.
>   - Pointers are initialized with infinite scream on 64-bit platforms because
>     it's an unmappable pointer value on architectures I'm aware of. Pointers
>     are initialize to 0x000000AA (small scream) on 32-bit platforms because
>     32-bit platforms don't consistently offer unmappable pages. When they do
>     it's usually the zero page. As people try this out, I expect that we'll
>     want to allow different platforms to customize this, let's do so later.
>   - Vectors of pointers are initialized the same way pointers are.
>   - Floating point values and vectors are initialized with a negative quiet NaN
>     with repeated 0xFF payload (e.g. 0xffffffff and 0xffffffffffffffff). NaNs are nice
>     (here, anways) because they propagate on arithmetic, making it more likely
>     that entire computations become NaN when a single uninitialized value
>     sneaks in.
>   - Arrays are initialized to their homogeneous elements' initialization
>     value, repeated. Stack-based Variable-Length Arrays (VLAs) are
>     runtime-initialized to the allocated size (no effort is made for negative
>     size, but zero-sized VLAs are untouched even if technically undefined).
>   - Structs are initialized to their heterogeneous element's initialization
>     values. Zero-size structs are initialized as 0xAA since they're allocated
>     a single byte.
>   - Unions are initialized using the initialization for the largest member of
>     the union.
> 
>   Expect the values used for pattern initialization to change over time, as we
>   refine heuristics (both for performance and security). The goal is truly to
>   avoid injecting semantics into undefined behavior, and we should be
>   comfortable changing these values when there's a worthwhile point in doing
>   so.
> 
>   Why so much infinite scream? Repeated byte patterns tend to be easy to
>   synthesize on most architectures, and otherwise memset is usually very
>   efficient. For values which aren't entirely repeated byte patterns, LLVM
>   will often generate code which does memset + a few stores.
> 
> 
> 
> 
> For some of the objects whose most fields are BOOLEAN, POINTER_TYPE,
> rr FLOATING_TYPE, pattern  initializing likee this might be less efficient. Do you
> agree on this?
> 
> Use a pattern that fits them all.  I mean memory allocation hardening
> fills allocated storage with a repeated (byte) pattern and people are
> happy with that.  It also makes it easy to spot uninitialized storage
> from a debugger.  So please, do not over-design this, it really doesn't
> make any sense and the common case you are inevitably chasing here
> would already be fine with a random repeated pattern.
> 
> So, My question is:
> 
> If we want to pattern initialize with the single repeated pattern for all types, with one is better to use:  “0xAAAAAAAA”
> or “0xFFFFFFFF” , or other pattern that our current glibc used? What’s that pattern?

It's set by the user.

> Will  “0xAAAAAAAA” in a floating type auto variable crash the program?
> Will “0xFFFFFFFF” in a pointer type auto variable crash the program? (Might crash?)
> 
> 
> (thus also my suggestion to split out
> padding handling - now we can also split out pattern init handling,
> maybe somebody else feels like reviewing and approving this, who knows).
> 
> I am okay with further splitting pattern initialization part to a separate patch. Then we will
> have 4 independent patches in total:
> 
> 1. -fauto-var-init=zero and all the handling in other passes to the new added call to .DEFERRED_INIT.
> 2. Add -fauto-var-init=pattern
> 3. Add -fauto-var-init-padding
> 4. Add -ftrivial-auto-var-init for CLANG compatibility.
> 
> Are the above the correct understanding?

I think we can drop -fauto-var-init=pattern and just go with block
initializing which will cover padding as well which means we can
stay with the odd -ftrivial-auto-var-init name used by CLANG and
add no additional options.

> As said, block-initializing with a repeated pattern is OK and I can see
> that being useful.  Trying to produce "nicer" values for floats, bools
> and pointers on 32bit platforms is IMHO not going to fix anything and
> introduce as many problems as it will "fix".
> 
> Yes, I agree, if we can find a good repeated pattern for all types’s 
> pattern initialization, that will be much easier and simpler to 
> implement, I am happy to do that.  (Honestly, the part of implementation 
> that took me most of the time is pattern-initialization.. and I am still 
> not very comfortable with this part Of the code myself.  -:)

There's no "safe" pattern besides all-zero for all "undefined" uses
(note that uses do not necessarily use declared types).  Which is why
recommending pattern init is somewhat misguided.  There's maybe 
some useful pattern that more readily produces crashes, those that
produce a FP sNaN for all of the float types.

> And if you block-initialize stuff you then automagically cover padding.
> I call this a win-win, no?
> 
> Yes, this will also initialize paddings with patterns (Not zeroes as CLANG did).
> Shall we compatible with CLANG on this?

No, why?

> Now, what you _could_ try is do sth like
> 
> tree ar = build_array_type (uint_ptr_type_node, size_type_node, false);
> tree range = build2 (RANGE_EXPR, size_type_node,
>                      size_zero_node, build_int_cst (size_type_node,
> size-in-words));
> tree pattern = build_int_cst (uint_ptr_type_node, 0xdeadbeef);
> ctor = build_constructor_single (ar, range, pattern);
> ctor = build1 (VIEW_CONVERT_EXPR, type, ctor);
> 
> 
> So, the above will be used to replace the following original code in my patch:
> 
> +    case AUTO_INIT_PATTERN:
> +      init = build_pattern_cst_for_auto_init (TREE_TYPE (var));
> +      expand_assignment (var, init, false);
> +      break;
> 
> ?
> 
> in my example code (untested) you then still need
> 
>   expand_assignment (var, ctor, false);
> 
> it would be the easiest way to try pattern init with a pattern that's
> bigger than a byte (otherwise of course the memset path is optimal).
> 
> If the pattern that is used to initialize all types is byte-repeatable, for example, 0xA or 0xF, then
> We can use memset to initialize all types, however, the potential problem is, if later we decide
> To change to another pattern that might not be byte-repeatable, then the memset implementation
> is not proper at that time.
> 
> Is it possible that we might change the pattern later?

The pattern should be documented as an implementation detail unless
we want to expose it to the user via, say, -fpattern-init=0xdeadbeef.

> 
> 
> thus build a range-init CTOR of an array of pointer-sized elements
> but do the actual assignment to the target object by viewing that
> as the target objects type.
> 
> Okay.
> 
> So, for a target object that is smaller than a word, for example, BOOLEAN,
> CHAR or short, is the above still working?
> 
> Well, you obviously have to adjust that - you can't pattern-init
> a BOOL with word-size stores of a word-size pattern.
> 
> As said, for example glibc allocator hardening with MALLOC_PERTURB_
> uses simple byte-init.
> 
> What’s the pattern glibc used?

The value of the MALLOC_PERTURB_ environment truncated to a byte.

Richard.

> Thanks a lot.
> 
> Qing
> 
> That should block-initialize with
> a uint_ptr_type_node sized pattern (but likely less efficient than
> special block init would do).
> 
> Not sure what problems you will run into this, you'll have to try.
> 
> I will try this.
> 
> Thanks a lot for your suggestions.
> 
> Qing
> 
> Richard.
> 
> 
> 
> --
> Richard Biener <rguenther@suse.de<mailto:rguenther@suse.de>>
> SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
> Germany; GF: Felix Imendörffer; HRB 36809 (AG Nuernberg)
> 
> 

-- 
Richard Biener <rguenther@suse.de>
SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
Germany; GF: Felix Imendörffer; HRB 36809 (AG Nuernberg)

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH][version 3]add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-06-21  7:53                   ` Richard Biener
@ 2021-06-21 15:11                     ` Qing Zhao
  2021-06-21 15:35                       ` Richard Biener
  0 siblings, 1 reply; 57+ messages in thread
From: Qing Zhao @ 2021-06-21 15:11 UTC (permalink / raw)
  To: Richard Biener; +Cc: Kees cook, richard Sandiford, gcc-patches Qing Zhao via

HI, Richard,

> On Jun 21, 2021, at 2:53 AM, Richard Biener <rguenther@suse.de> wrote:
> 
>> 
>> 
>> This is for the compatibility with CLANG. -:). (https://reviews.llvm.org/D54604)
> 
> I don't care about functional 1:1 "compatibility" with CLANG.

Okay.  -:)

> 
>> 1. Pattern initialization
>> 
>>  This is the recommended initialization approach. Pattern initialization's
> 
> But elsewhere you said pattern initialization is only for debugging,
> not production …

Yes. Pattern initialization is only for debugging purpose during development phase.

> 
>> Use a pattern that fits them all.  I mean memory allocation hardening
>> fills allocated storage with a repeated (byte) pattern and people are
>> happy with that.  It also makes it easy to spot uninitialized storage
>> from a debugger.  So please, do not over-design this, it really doesn't
>> make any sense and the common case you are inevitably chasing here
>> would already be fine with a random repeated pattern.
>> 
>> So, My question is:
>> 
>> If we want to pattern initialize with the single repeated pattern for all types, with one is better to use:  “0xAAAAAAAA”
>> or “0xFFFFFFFF” , or other pattern that our current glibc used? What’s that pattern?
> 
> It's set by the user.

Yes, looks like that glibc uses a byte-repeated pattern that is set by the user through environment variable.

> 
>> Will  “0xAAAAAAAA” in a floating type auto variable crash the program?
>> Will “0xFFFFFFFF” in a pointer type auto variable crash the program? (Might crash?)
>> 
>> 
>> (thus also my suggestion to split out
>> padding handling - now we can also split out pattern init handling,
>> maybe somebody else feels like reviewing and approving this, who knows).
>> 
>> I am okay with further splitting pattern initialization part to a separate patch. Then we will
>> have 4 independent patches in total:
>> 
>> 1. -fauto-var-init=zero and all the handling in other passes to the new added call to .DEFERRED_INIT.
>> 2. Add -fauto-var-init=pattern
>> 3. Add -fauto-var-init-padding
>> 4. Add -ftrivial-auto-var-init for CLANG compatibility.
>> 
>> Are the above the correct understanding?
> 
> I think we can drop -fauto-var-init=pattern and just go with block
> initializing which will cover padding as well which means we can
> stay with the odd -ftrivial-auto-var-init name used by CLANG and
> add no additional options.

Yes, this is a good idea. 

block initializing will cover all paddings automatically. 

Shall we do block initializing for both “zero initialization” and “pattern initialization”?

Currently, for zero initialization, I used the following:

>>> +    case AUTO_INIT_ZERO:
>>> +      init = build_zero_cst (TREE_TYPE (var));
>>> +      expand_assignment (var, init, false);
>>> +      break;

Looks like that the current “expand_assignment” does not initialize paddings with zeroes. 
Shall I also use “memset” for “zero initialization”?

> 
>> As said, block-initializing with a repeated pattern is OK and I can see
>> that being useful.  Trying to produce "nicer" values for floats, bools
>> and pointers on 32bit platforms is IMHO not going to fix anything and
>> introduce as many problems as it will "fix".
>> 
>> Yes, I agree, if we can find a good repeated pattern for all types’s 
>> pattern initialization, that will be much easier and simpler to 
>> implement, I am happy to do that.  (Honestly, the part of implementation 
>> that took me most of the time is pattern-initialization.. and I am still 
>> not very comfortable with this part Of the code myself.  -:)
> 
> There's no "safe" pattern besides all-zero for all "undefined" uses
> (note that uses do not necessarily use declared types).  Which is why
> recommending pattern init is somewhat misguided.  There's maybe 
> some useful pattern that more readily produces crashes, those that
> produce a FP sNaN for all of the float types.

So, pattern value as 0xFF might be better than 0xAA since 0xFFFFFFFF will be a NaN value for floating type?

> 
>> And if you block-initialize stuff you then automagically cover padding.
>> I call this a win-win, no?
>> 
>> Yes, this will also initialize paddings with patterns (Not zeroes as CLANG did).
>> Shall we compatible with CLANG on this?
> 
> No, why?

Okay.

>> in my example code (untested) you then still need
>> 
>>  expand_assignment (var, ctor, false);
>> 
>> it would be the easiest way to try pattern init with a pattern that's
>> bigger than a byte (otherwise of course the memset path is optimal).
>> 
>> If the pattern that is used to initialize all types is byte-repeatable, for example, 0xA or 0xF, then
>> We can use memset to initialize all types, however, the potential problem is, if later we decide
>> To change to another pattern that might not be byte-repeatable, then the memset implementation
>> is not proper at that time.
>> 
>> Is it possible that we might change the pattern later?
> 
> The pattern should be documented as an implementation detail unless
> we want to expose it to the user via, say, -fpattern-init=0xdeadbeef.

Not sure whether it’s necessary to expose this to user.

One question that is important to the implementation is:

Shall we use “byte-repeated” or “word-repeated” pattern?
Is “word-repeated” pattern better than “byte-repeated” pattern?

For implementation, “byte-repeated” pattern will make the whole implementation much simpler since both “zero initialization” 
and “pattern initialization” can be implemented with “memset” with different “value”.  

So, if “word-repeated” pattern will not have too much more benefit, I will prefer “byte-repeated” pattern.

Let me know your comments here.

> 
>> 
>> 
>> As said, for example glibc allocator hardening with MALLOC_PERTURB_
>> uses simple byte-init.
>> 
>> What’s the pattern glibc used?
> 
> The value of the MALLOC_PERTURB_ environment truncated to a byte.

Okay.

thanks.

Qing
> 
> Richard.
> 


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH][version 3]add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-06-21 15:11                     ` Qing Zhao
@ 2021-06-21 15:35                       ` Richard Biener
  2021-06-21 16:13                         ` Qing Zhao
  0 siblings, 1 reply; 57+ messages in thread
From: Richard Biener @ 2021-06-21 15:35 UTC (permalink / raw)
  To: Qing Zhao; +Cc: Kees cook, richard Sandiford, gcc-patches Qing Zhao via

On June 21, 2021 5:11:30 PM GMT+02:00, Qing Zhao <qing.zhao@oracle.com> wrote:
>HI, Richard,
>
>> On Jun 21, 2021, at 2:53 AM, Richard Biener <rguenther@suse.de>
>wrote:
>> 
>>> 
>>> 
>>> This is for the compatibility with CLANG. -:).
>(https://reviews.llvm.org/D54604)
>> 
>> I don't care about functional 1:1 "compatibility" with CLANG.
>
>Okay.  -:)
>
>> 
>>> 1. Pattern initialization
>>> 
>>>  This is the recommended initialization approach. Pattern
>initialization's
>> 
>> But elsewhere you said pattern initialization is only for debugging,
>> not production …
>
>Yes. Pattern initialization is only for debugging purpose during
>development phase.
>
>> 
>>> Use a pattern that fits them all.  I mean memory allocation
>hardening
>>> fills allocated storage with a repeated (byte) pattern and people
>are
>>> happy with that.  It also makes it easy to spot uninitialized
>storage
>>> from a debugger.  So please, do not over-design this, it really
>doesn't
>>> make any sense and the common case you are inevitably chasing here
>>> would already be fine with a random repeated pattern.
>>> 
>>> So, My question is:
>>> 
>>> If we want to pattern initialize with the single repeated pattern
>for all types, with one is better to use:  “0xAAAAAAAA”
>>> or “0xFFFFFFFF” , or other pattern that our current glibc used?
>What’s that pattern?
>> 
>> It's set by the user.
>
>Yes, looks like that glibc uses a byte-repeated pattern that is set by
>the user through environment variable.
>
>> 
>>> Will  “0xAAAAAAAA” in a floating type auto variable crash the
>program?
>>> Will “0xFFFFFFFF” in a pointer type auto variable crash the program?
>(Might crash?)
>>> 
>>> 
>>> (thus also my suggestion to split out
>>> padding handling - now we can also split out pattern init handling,
>>> maybe somebody else feels like reviewing and approving this, who
>knows).
>>> 
>>> I am okay with further splitting pattern initialization part to a
>separate patch. Then we will
>>> have 4 independent patches in total:
>>> 
>>> 1. -fauto-var-init=zero and all the handling in other passes to the
>new added call to .DEFERRED_INIT.
>>> 2. Add -fauto-var-init=pattern
>>> 3. Add -fauto-var-init-padding
>>> 4. Add -ftrivial-auto-var-init for CLANG compatibility.
>>> 
>>> Are the above the correct understanding?
>> 
>> I think we can drop -fauto-var-init=pattern and just go with block
>> initializing which will cover padding as well which means we can
>> stay with the odd -ftrivial-auto-var-init name used by CLANG and
>> add no additional options.
>
>Yes, this is a good idea. 
>
>block initializing will cover all paddings automatically. 
>
>Shall we do block initializing for both “zero initialization” and
>“pattern initialization”?
>
>Currently, for zero initialization, I used the following:
>
>>>> +    case AUTO_INIT_ZERO:
>>>> +      init = build_zero_cst (TREE_TYPE (var));
>>>> +      expand_assignment (var, init, false);
>>>> +      break;
>
>Looks like that the current “expand_assignment” does not initialize
>paddings with zeroes. 
>Shall I also use “memset” for “zero initialization”?

I'd say so, yes. 

>> 
>>> As said, block-initializing with a repeated pattern is OK and I can
>see
>>> that being useful.  Trying to produce "nicer" values for floats,
>bools
>>> and pointers on 32bit platforms is IMHO not going to fix anything
>and
>>> introduce as many problems as it will "fix".
>>> 
>>> Yes, I agree, if we can find a good repeated pattern for all types’s
>
>>> pattern initialization, that will be much easier and simpler to 
>>> implement, I am happy to do that.  (Honestly, the part of
>implementation 
>>> that took me most of the time is pattern-initialization.. and I am
>still 
>>> not very comfortable with this part Of the code myself.  -:)
>> 
>> There's no "safe" pattern besides all-zero for all "undefined" uses
>> (note that uses do not necessarily use declared types).  Which is why
>> recommending pattern init is somewhat misguided.  There's maybe 
>> some useful pattern that more readily produces crashes, those that
>> produce a FP sNaN for all of the float types.
>
>So, pattern value as 0xFF might be better than 0xAA since 0xFFFFFFFF
>will be a NaN value for floating type?

I think for debugging NaNs are quite nice, yes. 

>> 
>>> And if you block-initialize stuff you then automagically cover
>padding.
>>> I call this a win-win, no?
>>> 
>>> Yes, this will also initialize paddings with patterns (Not zeroes as
>CLANG did).
>>> Shall we compatible with CLANG on this?
>> 
>> No, why?
>
>Okay.
>
>>> in my example code (untested) you then still need
>>> 
>>>  expand_assignment (var, ctor, false);
>>> 
>>> it would be the easiest way to try pattern init with a pattern
>that's
>>> bigger than a byte (otherwise of course the memset path is optimal).
>>> 
>>> If the pattern that is used to initialize all types is
>byte-repeatable, for example, 0xA or 0xF, then
>>> We can use memset to initialize all types, however, the potential
>problem is, if later we decide
>>> To change to another pattern that might not be byte-repeatable, then
>the memset implementation
>>> is not proper at that time.
>>> 
>>> Is it possible that we might change the pattern later?
>> 
>> The pattern should be documented as an implementation detail unless
>> we want to expose it to the user via, say, -fpattern-init=0xdeadbeef.
>
>Not sure whether it’s necessary to expose this to user.
>
>One question that is important to the implementation is:
>
>Shall we use “byte-repeated” or “word-repeated” pattern?
>Is “word-repeated” pattern better than “byte-repeated” pattern?
>
>For implementation, “byte-repeated” pattern will make the whole
>implementation much simpler since both “zero initialization” 
>and “pattern initialization” can be implemented with “memset” with
>different “value”.  
>
>So, if “word-repeated” pattern will not have too much more benefit, I
>will prefer “byte-repeated” pattern.
>
>Let me know your comments here.

I have no strong opinion and prefer byte repetition for simplicity. But I would document this as implementation detail that can change. 

Richard. 

>> 
>>> 
>>> 
>>> As said, for example glibc allocator hardening with MALLOC_PERTURB_
>>> uses simple byte-init.
>>> 
>>> What’s the pattern glibc used?
>> 
>> The value of the MALLOC_PERTURB_ environment truncated to a byte.
>
>Okay.
>
>thanks.
>
>Qing
>> 
>> Richard.
>> 


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH][version 3]add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-06-18 23:47                     ` Kees Cook
@ 2021-06-21 15:39                       ` Qing Zhao
  2021-06-21 16:18                         ` Kees Cook
  0 siblings, 1 reply; 57+ messages in thread
From: Qing Zhao @ 2021-06-21 15:39 UTC (permalink / raw)
  To: Kees cook; +Cc: Richard Biener, richard Sandiford, gcc-patches Qing Zhao via

Hi, Kees,

On Jun 18, 2021, at 6:47 PM, Kees cook <keescook@chromium.org<mailto:keescook@chromium.org>> wrote:

On Wed, Jun 16, 2021 at 07:39:02PM +0000, Qing Zhao wrote:
So, the major question now is:

Is one single repeatable pattern enough for pattern initialization for all different types of auto variables?

If YES, then the implementation for pattern initialization will be much easier and simpler
     as you pointed out. And will save me a lot of pain to implement this part.
If NO, then we have to keep the current complicate implementation since it provides us
     the flexibility to assign different patterns to different types.

Honestly, I don’t have a good justification on this question myself.

The previous references I have so far are the current behavior of CLANG and Microsoft compiler.

For your reference,
. CLANG uses different patterns for INTEGER  (0xAAAAAAAA) and FLOAT (0xFFFFFFFF) and 32-bit pointer (0x000000AA)
https://reviews.llvm.org/D54604
. Microsoft uses different patterns for INTEGERS ( 0xE2), FLOAT (1.0)
https://msrc-blog.microsoft.com/2020/05/13/solving-uninitialized-stack-memory-on-windows/

My understanding from CLANG’s comment is, the patterns are easier to crash the program for the certain type, therefore easier to
catch any potential bugs.

Right, this is the justification for the different patterns. I am
fine with a static value for the first version of this functionality,
as long as it's a non-canonical virtual memory address when evaluated
as a pointer (so that the pattern can't be made to aim at a legitimate
fixed allocatable address in memory).

Just searched online, (https://en.wikipedia.org/wiki/X86-64#Virtual_address_space_details)

===
Canonical form addresses run from 0 through 00007FFF'FFFFFFFF, and from FFFF8000'00000000 through FFFFFFFF'FFFFFFFF, for a total of 256 TB of usable virtual address space.
===

So, if “pattern value” is “0xFFFFFFFFFFFFFFFF”, then it’s a valid canonical virtual memory address.  However, for most OS, “0xFFFFFFFFFFFFFFFF” should be not in user space.

My question is, is “0xFFFFFFFFFFFFFFFFF” good for pointer? Or “0xAAAAAAAAAAAAAAAA” better?

Thanks.
Qing


Don’t know why Microsoft chose the pattern like this.

So, For GCC, what should we do on the pattern initializations, shall we choose one single repeatable pattern for all the types as you suggested,
Or chose different patterns for different types as Clang and Microsoft compiler’s behavior?

Kees, do you have any comment on this?

How did Linux Kernel use -ftrivial-auto-var-init=pattern feature of CLANG?

It's just used as-is from the compiler, and recommended for "debug
builds".

--
Kees Cook


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH][version 3]add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-06-21 15:35                       ` Richard Biener
@ 2021-06-21 16:13                         ` Qing Zhao
  2021-06-22  6:24                           ` Richard Biener
  0 siblings, 1 reply; 57+ messages in thread
From: Qing Zhao @ 2021-06-21 16:13 UTC (permalink / raw)
  To: Richard Biener; +Cc: Kees cook, richard Sandiford, gcc-patches Qing Zhao via



> On Jun 21, 2021, at 10:35 AM, Richard Biener <rguenther@suse.de> wrote:
>>> I think we can drop -fauto-var-init=pattern and just go with block
>>> initializing which will cover padding as well which means we can
>>> stay with the odd -ftrivial-auto-var-init name used by CLANG and
>>> add no additional options.
>> 
>> Yes, this is a good idea. 
>> 
>> block initializing will cover all paddings automatically. 
>> 
>> Shall we do block initializing for both “zero initialization” and
>> “pattern initialization”?
>> 
>> Currently, for zero initialization, I used the following:
>> 
>>>>> +    case AUTO_INIT_ZERO:
>>>>> +      init = build_zero_cst (TREE_TYPE (var));
>>>>> +      expand_assignment (var, init, false);
>>>>> +      break;
>> 
>> Looks like that the current “expand_assignment” does not initialize
>> paddings with zeroes. 
>> Shall I also use “memset” for “zero initialization”?
> 
> I'd say so, yes. 

Okay.

One more question for the current “expand_builtin_memset”:

Is the current implementation of “expand_builtin_memset” automatically handle short length memset optimally? 

i.e, do I need to specially handle char type, short type, or other types that can fit to a register?


>>> 
>>> There's no "safe" pattern besides all-zero for all "undefined" uses
>>> (note that uses do not necessarily use declared types).  Which is why
>>> recommending pattern init is somewhat misguided.  There's maybe 
>>> some useful pattern that more readily produces crashes, those that
>>> produce a FP sNaN for all of the float types.
>> 
>> So, pattern value as 0xFF might be better than 0xAA since 0xFFFFFFFF
>> will be a NaN value for floating type?
> 
> I think for debugging NaNs are quite nice, yes. 

For floating point, 0xFFFFFFFF is good. 
But for pointer type, is it good? (See my other email to Kees).

>> 
>> Not sure whether it’s necessary to expose this to user.
>> 
>> One question that is important to the implementation is:
>> 
>> Shall we use “byte-repeated” or “word-repeated” pattern?
>> Is “word-repeated” pattern better than “byte-repeated” pattern?
>> 
>> For implementation, “byte-repeated” pattern will make the whole
>> implementation much simpler since both “zero initialization” 
>> and “pattern initialization” can be implemented with “memset” with
>> different “value”.  
>> 
>> So, if “word-repeated” pattern will not have too much more benefit, I
>> will prefer “byte-repeated” pattern.
>> 
>> Let me know your comments here.
> 
> I have no strong opinion and prefer byte repetition for simplicity. But I would document this as implementation detail that can change. 

Okay, if we finally decide to go with byte repetition, I will document this as implementation details that can be changed later.

Qing
> 
> Richard. 
> 
>>> 
>>>> 
>>>> 
>>>> As said, for example glibc allocator hardening with MALLOC_PERTURB_
>>>> uses simple byte-init.
>>>> 
>>>> What’s the pattern glibc used?
>>> 
>>> The value of the MALLOC_PERTURB_ environment truncated to a byte.
>> 
>> Okay.
>> 
>> thanks.
>> 
>> Qing
>>> 
>>> Richard.
>>> 
> 


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH][version 3]add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-06-21 15:39                       ` Qing Zhao
@ 2021-06-21 16:18                         ` Kees Cook
  2021-06-21 17:11                           ` Qing Zhao
  2021-06-22  8:25                           ` Richard Sandiford
  0 siblings, 2 replies; 57+ messages in thread
From: Kees Cook @ 2021-06-21 16:18 UTC (permalink / raw)
  To: Qing Zhao; +Cc: Richard Biener, richard Sandiford, gcc-patches Qing Zhao via

On Mon, Jun 21, 2021 at 03:39:45PM +0000, Qing Zhao wrote:
> So, if “pattern value” is “0xFFFFFFFFFFFFFFFF”, then it’s a valid canonical virtual memory address.  However, for most OS, “0xFFFFFFFFFFFFFFFF” should be not in user space.
> 
> My question is, is “0xFFFFFFFFFFFFFFFFF” good for pointer? Or “0xAAAAAAAAAAAAAAAA” better?

I think 0xFF repeating is fine for this version. Everything else is a
"nice to have" for the pattern-init, IMO. :)

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH][version 3]add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-06-21 16:18                         ` Kees Cook
@ 2021-06-21 17:11                           ` Qing Zhao
  2021-06-22  8:25                           ` Richard Sandiford
  1 sibling, 0 replies; 57+ messages in thread
From: Qing Zhao @ 2021-06-21 17:11 UTC (permalink / raw)
  To: Kees Cook; +Cc: Richard Biener, richard Sandiford, gcc-patches Qing Zhao via



> On Jun 21, 2021, at 11:18 AM, Kees Cook <keescook@chromium.org> wrote:
> 
> On Mon, Jun 21, 2021 at 03:39:45PM +0000, Qing Zhao wrote:
>> So, if “pattern value” is “0xFFFFFFFFFFFFFFFF”, then it’s a valid canonical virtual memory address.  However, for most OS, “0xFFFFFFFFFFFFFFFF” should be not in user space.
>> 
>> My question is, is “0xFFFFFFFFFFFFFFFFF” good for pointer? Or “0xAAAAAAAAAAAAAAAA” better?
> 
> I think 0xFF repeating is fine for this version. Everything else is a
> "nice to have" for the pattern-init, IMO. :)

Okay, thank you!

Qing
> 
> -- 
> Kees Cook


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH][version 3]add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-06-21 16:13                         ` Qing Zhao
@ 2021-06-22  6:24                           ` Richard Biener
  0 siblings, 0 replies; 57+ messages in thread
From: Richard Biener @ 2021-06-22  6:24 UTC (permalink / raw)
  To: Qing Zhao; +Cc: Kees cook, richard Sandiford, gcc-patches Qing Zhao via

On Mon, 21 Jun 2021, Qing Zhao wrote:

> 
> 
> > On Jun 21, 2021, at 10:35 AM, Richard Biener <rguenther@suse.de> wrote:
> >>> I think we can drop -fauto-var-init=pattern and just go with block
> >>> initializing which will cover padding as well which means we can
> >>> stay with the odd -ftrivial-auto-var-init name used by CLANG and
> >>> add no additional options.
> >> 
> >> Yes, this is a good idea. 
> >> 
> >> block initializing will cover all paddings automatically. 
> >> 
> >> Shall we do block initializing for both “zero initialization” and
> >> “pattern initialization”?
> >> 
> >> Currently, for zero initialization, I used the following:
> >> 
> >>>>> +    case AUTO_INIT_ZERO:
> >>>>> +      init = build_zero_cst (TREE_TYPE (var));
> >>>>> +      expand_assignment (var, init, false);
> >>>>> +      break;
> >> 
> >> Looks like that the current “expand_assignment” does not initialize
> >> paddings with zeroes. 
> >> Shall I also use “memset” for “zero initialization”?
> > 
> > I'd say so, yes. 
> 
> Okay.
> 
> One more question for the current “expand_builtin_memset”:
> 
> Is the current implementation of “expand_builtin_memset” automatically handle short length memset optimally? 
> 
> i.e, do I need to specially handle char type, short type, or other types that can fit to a register?

No, short memsets are handled optimally.

> 
> >>> 
> >>> There's no "safe" pattern besides all-zero for all "undefined" uses
> >>> (note that uses do not necessarily use declared types).  Which is why
> >>> recommending pattern init is somewhat misguided.  There's maybe 
> >>> some useful pattern that more readily produces crashes, those that
> >>> produce a FP sNaN for all of the float types.
> >> 
> >> So, pattern value as 0xFF might be better than 0xAA since 0xFFFFFFFF
> >> will be a NaN value for floating type?
> > 
> > I think for debugging NaNs are quite nice, yes. 
> 
> For floating point, 0xFFFFFFFF is good. 
> But for pointer type, is it good? (See my other email to Kees).

Good enough IMHO.  We could make it GCC target specific so targets
can coordinate with their OS vendors to have the picked page
unmapped on low virtual memory machines.

> >> 
> >> Not sure whether it’s necessary to expose this to user.
> >> 
> >> One question that is important to the implementation is:
> >> 
> >> Shall we use “byte-repeated” or “word-repeated” pattern?
> >> Is “word-repeated” pattern better than “byte-repeated” pattern?
> >> 
> >> For implementation, “byte-repeated” pattern will make the whole
> >> implementation much simpler since both “zero initialization” 
> >> and “pattern initialization” can be implemented with “memset” with
> >> different “value”.  
> >> 
> >> So, if “word-repeated” pattern will not have too much more benefit, I
> >> will prefer “byte-repeated” pattern.
> >> 
> >> Let me know your comments here.
> > 
> > I have no strong opinion and prefer byte repetition for simplicity. But I would document this as implementation detail that can change. 
> 
> Okay, if we finally decide to go with byte repetition, I will document this as implementation details that can be changed later.
> 
> Qing
> > 
> > Richard. 
> > 
> >>> 
> >>>> 
> >>>> 
> >>>> As said, for example glibc allocator hardening with MALLOC_PERTURB_
> >>>> uses simple byte-init.
> >>>> 
> >>>> What’s the pattern glibc used?
> >>> 
> >>> The value of the MALLOC_PERTURB_ environment truncated to a byte.
> >> 
> >> Okay.
> >> 
> >> thanks.
> >> 
> >> Qing
> >>> 
> >>> Richard.
> >>> 
> > 

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH][version 3]add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-06-21 16:18                         ` Kees Cook
  2021-06-21 17:11                           ` Qing Zhao
@ 2021-06-22  8:25                           ` Richard Sandiford
  2021-06-22  8:59                             ` Richard Biener
  2021-06-22 17:55                             ` Kees Cook
  1 sibling, 2 replies; 57+ messages in thread
From: Richard Sandiford @ 2021-06-22  8:25 UTC (permalink / raw)
  To: Kees Cook; +Cc: Qing Zhao, Richard Biener, gcc-patches Qing Zhao via

Kees Cook <keescook@chromium.org> writes:
> On Mon, Jun 21, 2021 at 03:39:45PM +0000, Qing Zhao wrote:
>> So, if “pattern value” is “0xFFFFFFFFFFFFFFFF”, then it’s a valid canonical virtual memory address.  However, for most OS, “0xFFFFFFFFFFFFFFFF” should be not in user space.
>> 
>> My question is, is “0xFFFFFFFFFFFFFFFFF” good for pointer? Or “0xAAAAAAAAAAAAAAAA” better?
>
> I think 0xFF repeating is fine for this version. Everything else is a
> "nice to have" for the pattern-init, IMO. :)

Sorry to be awkward, but 0xFF seems worse than 0xAA to me.

For integer types, all values are valid representations, and we're
relying on the pattern being “obviously” wrong in context.  0xAAAA…
is unlikely to be a correct integer but 0xFFFF… would instead be a
“nice” -1.  It would be difficult to tell in a debugger that a -1
came from pattern init rather than a deliberate choice.

I agree that, all other things being equal, it would be nice to use NaNs
for floats.  But relying on wrong numerical values for floats doesn't
seem worse than doing that for integers.

0xAA… for float is (if I've got this right) -3.0316488252093987e-13,
which admittedly doesn't stand out as wrong.  But I'm not sure we
should sacrifice integer debugging for float debugging here.

Thanks,
Richard

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH][version 3]add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-06-22  8:25                           ` Richard Sandiford
@ 2021-06-22  8:59                             ` Richard Biener
  2021-06-22 13:54                               ` Qing Zhao
  2021-06-22 17:55                             ` Kees Cook
  1 sibling, 1 reply; 57+ messages in thread
From: Richard Biener @ 2021-06-22  8:59 UTC (permalink / raw)
  To: Richard Sandiford; +Cc: Kees Cook, Qing Zhao, gcc-patches Qing Zhao via

On Tue, 22 Jun 2021, Richard Sandiford wrote:

> Kees Cook <keescook@chromium.org> writes:
> > On Mon, Jun 21, 2021 at 03:39:45PM +0000, Qing Zhao wrote:
> >> So, if “pattern value” is “0xFFFFFFFFFFFFFFFF”, then it’s a valid canonical virtual memory address.  However, for most OS, “0xFFFFFFFFFFFFFFFF” should be not in user space.
> >> 
> >> My question is, is “0xFFFFFFFFFFFFFFFFF” good for pointer? Or “0xAAAAAAAAAAAAAAAA” better?
> >
> > I think 0xFF repeating is fine for this version. Everything else is a
> > "nice to have" for the pattern-init, IMO. :)
> 
> Sorry to be awkward, but 0xFF seems worse than 0xAA to me.
> 
> For integer types, all values are valid representations, and we're
> relying on the pattern being “obviously” wrong in context.  0xAAAA…
> is unlikely to be a correct integer but 0xFFFF… would instead be a
> “nice” -1.  It would be difficult to tell in a debugger that a -1
> came from pattern init rather than a deliberate choice.
> 
> I agree that, all other things being equal, it would be nice to use NaNs
> for floats.  But relying on wrong numerical values for floats doesn't
> seem worse than doing that for integers.
> 
> 0xAA… for float is (if I've got this right) -3.0316488252093987e-13,
> which admittedly doesn't stand out as wrong.  But I'm not sure we
> should sacrifice integer debugging for float debugging here.

We can always expose the actual value as --param.  Now, I think
we'd need a two-byte pattern to reliably produce NaNs anyway,
so with floats taken out of the picture the focus should be on
pointers where IMHO val & 1 and val & 15 would be nice to have.
So sth like 0xf7 would work for those.  With a two-byte pattern
we could use 0xffef or 0x7fef.

Anyway, it's probably down to priorities of the project involved
(debugging FP stuff or integer stuff).

Richard.

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH][version 3]add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-06-22  8:59                             ` Richard Biener
@ 2021-06-22 13:54                               ` Qing Zhao
  2021-06-22 14:00                                 ` Richard Biener
  0 siblings, 1 reply; 57+ messages in thread
From: Qing Zhao @ 2021-06-22 13:54 UTC (permalink / raw)
  To: Richard Biener; +Cc: Richard Sandiford, Kees Cook, gcc-patches Qing Zhao via

So, I am wondering why not still keep my current implementation on assign different patterns for different types?

This major issue with this design is the code size and runtime overhead, but for debugging purpose, those are not that important, right? And we can add some optimization later to improve the code size and runtime overhead.

Otherwise, if we only use one pattern for all the types in this initial version, later we still might need change it.

How do you think?

Qing

On Jun 22, 2021, at 3:59 AM, Richard Biener <rguenther@suse.de<mailto:rguenther@suse.de>> wrote:

On Tue, 22 Jun 2021, Richard Sandiford wrote:

Kees Cook <keescook@chromium.org<mailto:keescook@chromium.org>> writes:
On Mon, Jun 21, 2021 at 03:39:45PM +0000, Qing Zhao wrote:
So, if “pattern value” is “0xFFFFFFFFFFFFFFFF”, then it’s a valid canonical virtual memory address.  However, for most OS, “0xFFFFFFFFFFFFFFFF” should be not in user space.

My question is, is “0xFFFFFFFFFFFFFFFFF” good for pointer? Or “0xAAAAAAAAAAAAAAAA” better?

I think 0xFF repeating is fine for this version. Everything else is a
"nice to have" for the pattern-init, IMO. :)

Sorry to be awkward, but 0xFF seems worse than 0xAA to me.

For integer types, all values are valid representations, and we're
relying on the pattern being “obviously” wrong in context.  0xAAAA…
is unlikely to be a correct integer but 0xFFFF… would instead be a
“nice” -1.  It would be difficult to tell in a debugger that a -1
came from pattern init rather than a deliberate choice.

I agree that, all other things being equal, it would be nice to use NaNs
for floats.  But relying on wrong numerical values for floats doesn't
seem worse than doing that for integers.

0xAA… for float is (if I've got this right) -3.0316488252093987e-13,
which admittedly doesn't stand out as wrong.  But I'm not sure we
should sacrifice integer debugging for float debugging here.

We can always expose the actual value as --param.  Now, I think
we'd need a two-byte pattern to reliably produce NaNs anyway,
so with floats taken out of the picture the focus should be on
pointers where IMHO val & 1 and val & 15 would be nice to have.
So sth like 0xf7 would work for those.  With a two-byte pattern
we could use 0xffef or 0x7fef.

Anyway, it's probably down to priorities of the project involved
(debugging FP stuff or integer stuff).

Richard.


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH][version 3]add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-06-22 13:54                               ` Qing Zhao
@ 2021-06-22 14:00                                 ` Richard Biener
  2021-06-22 14:10                                   ` Qing Zhao
  0 siblings, 1 reply; 57+ messages in thread
From: Richard Biener @ 2021-06-22 14:00 UTC (permalink / raw)
  To: Qing Zhao; +Cc: Richard Sandiford, Kees Cook, gcc-patches Qing Zhao via

On Tue, 22 Jun 2021, Qing Zhao wrote:

> So, I am wondering why not still keep my current implementation on 
> assign different patterns for different types?
> 
> This major issue with this design is the code size and runtime overhead, 
> but for debugging purpose, those are not that important, right? And we 
> can add some optimization later to improve the code size and runtime 
> overhead.
> 
> Otherwise, if we only use one pattern for all the types in this initial 
> version, later we still might need change it.
> 
> How do you think?

No, let's not re-open that discussion.  As said we can look to support
multi-byte pattern if that has a chance to improve things but only
as followup.

Thanks,
Richard.

> Qing
> 
> On Jun 22, 2021, at 3:59 AM, Richard Biener <rguenther@suse.de<mailto:rguenther@suse.de>> wrote:
> 
> On Tue, 22 Jun 2021, Richard Sandiford wrote:
> 
> Kees Cook <keescook@chromium.org<mailto:keescook@chromium.org>> writes:
> On Mon, Jun 21, 2021 at 03:39:45PM +0000, Qing Zhao wrote:
> So, if “pattern value” is “0xFFFFFFFFFFFFFFFF”, then it’s a valid canonical virtual memory address.  However, for most OS, “0xFFFFFFFFFFFFFFFF” should be not in user space.
> 
> My question is, is “0xFFFFFFFFFFFFFFFFF” good for pointer? Or “0xAAAAAAAAAAAAAAAA” better?
> 
> I think 0xFF repeating is fine for this version. Everything else is a
> "nice to have" for the pattern-init, IMO. :)
> 
> Sorry to be awkward, but 0xFF seems worse than 0xAA to me.
> 
> For integer types, all values are valid representations, and we're
> relying on the pattern being “obviously” wrong in context.  0xAAAA…
> is unlikely to be a correct integer but 0xFFFF… would instead be a
> “nice” -1.  It would be difficult to tell in a debugger that a -1
> came from pattern init rather than a deliberate choice.
> 
> I agree that, all other things being equal, it would be nice to use NaNs
> for floats.  But relying on wrong numerical values for floats doesn't
> seem worse than doing that for integers.
> 
> 0xAA… for float is (if I've got this right) -3.0316488252093987e-13,
> which admittedly doesn't stand out as wrong.  But I'm not sure we
> should sacrifice integer debugging for float debugging here.
> 
> We can always expose the actual value as --param.  Now, I think
> we'd need a two-byte pattern to reliably produce NaNs anyway,
> so with floats taken out of the picture the focus should be on
> pointers where IMHO val & 1 and val & 15 would be nice to have.
> So sth like 0xf7 would work for those.  With a two-byte pattern
> we could use 0xffef or 0x7fef.
> 
> Anyway, it's probably down to priorities of the project involved
> (debugging FP stuff or integer stuff).
> 
> Richard.
> 
> 

-- 
Richard Biener <rguenther@suse.de>
SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
Germany; GF: Felix Imendörffer; HRB 36809 (AG Nuernberg)

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH][version 3]add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-06-22 14:00                                 ` Richard Biener
@ 2021-06-22 14:10                                   ` Qing Zhao
  2021-06-22 14:15                                     ` Richard Biener
  0 siblings, 1 reply; 57+ messages in thread
From: Qing Zhao @ 2021-06-22 14:10 UTC (permalink / raw)
  To: Richard Biener; +Cc: Richard Sandiford, Kees Cook, gcc-patches Qing Zhao via



> On Jun 22, 2021, at 9:00 AM, Richard Biener <rguenther@suse.de> wrote:
> 
> On Tue, 22 Jun 2021, Qing Zhao wrote:
> 
>> So, I am wondering why not still keep my current implementation on 
>> assign different patterns for different types?
>> 
>> This major issue with this design is the code size and runtime overhead, 
>> but for debugging purpose, those are not that important, right? And we 
>> can add some optimization later to improve the code size and runtime 
>> overhead.
>> 
>> Otherwise, if we only use one pattern for all the types in this initial 
>> version, later we still might need change it.
>> 
>> How do you think?
> 
> No, let's not re-open that discussion.  As said we can look to support
> multi-byte pattern if that has a chance to improve things but only
> as followup.

I am fine with this.

However, we need to decide whether we will use one-byte repeatable pattern, or multiple-byte repeatable pattern now,
Since the implementation will be different. If using one-byte, the implementation will be the simplest, we can use memset for all
VLA, non-vla, zero-init, or pattern-init consistently.

However, if we choose multiple-byte pattern, then the implementation will be different, we cannot use memset for pattern-init, and 
The implemenation for VLA pattern-init also is different.

Qing
> 
> Thanks,
> Richard.
> 
>> Qing
>> 
>> On Jun 22, 2021, at 3:59 AM, Richard Biener <rguenther@suse.de<mailto:rguenther@suse.de>> wrote:
>> 
>> On Tue, 22 Jun 2021, Richard Sandiford wrote:
>> 
>> Kees Cook <keescook@chromium.org<mailto:keescook@chromium.org>> writes:
>> On Mon, Jun 21, 2021 at 03:39:45PM +0000, Qing Zhao wrote:
>> So, if “pattern value” is “0xFFFFFFFFFFFFFFFF”, then it’s a valid canonical virtual memory address.  However, for most OS, “0xFFFFFFFFFFFFFFFF” should be not in user space.
>> 
>> My question is, is “0xFFFFFFFFFFFFFFFFF” good for pointer? Or “0xAAAAAAAAAAAAAAAA” better?
>> 
>> I think 0xFF repeating is fine for this version. Everything else is a
>> "nice to have" for the pattern-init, IMO. :)
>> 
>> Sorry to be awkward, but 0xFF seems worse than 0xAA to me.
>> 
>> For integer types, all values are valid representations, and we're
>> relying on the pattern being “obviously” wrong in context.  0xAAAA…
>> is unlikely to be a correct integer but 0xFFFF… would instead be a
>> “nice” -1.  It would be difficult to tell in a debugger that a -1
>> came from pattern init rather than a deliberate choice.
>> 
>> I agree that, all other things being equal, it would be nice to use NaNs
>> for floats.  But relying on wrong numerical values for floats doesn't
>> seem worse than doing that for integers.
>> 
>> 0xAA… for float is (if I've got this right) -3.0316488252093987e-13,
>> which admittedly doesn't stand out as wrong.  But I'm not sure we
>> should sacrifice integer debugging for float debugging here.
>> 
>> We can always expose the actual value as --param.  Now, I think
>> we'd need a two-byte pattern to reliably produce NaNs anyway,
>> so with floats taken out of the picture the focus should be on
>> pointers where IMHO val & 1 and val & 15 would be nice to have.
>> So sth like 0xf7 would work for those.  With a two-byte pattern
>> we could use 0xffef or 0x7fef.
>> 
>> Anyway, it's probably down to priorities of the project involved
>> (debugging FP stuff or integer stuff).
>> 
>> Richard.
>> 
>> 
> 
> -- 
> Richard Biener <rguenther@suse.de>
> SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
> Germany; GF: Felix Imendörffer; HRB 36809 (AG Nuernberg)


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH][version 3]add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-06-22 14:10                                   ` Qing Zhao
@ 2021-06-22 14:15                                     ` Richard Biener
  2021-06-22 14:33                                       ` Qing Zhao
  0 siblings, 1 reply; 57+ messages in thread
From: Richard Biener @ 2021-06-22 14:15 UTC (permalink / raw)
  To: Qing Zhao; +Cc: Richard Sandiford, Kees Cook, gcc-patches Qing Zhao via

On Tue, 22 Jun 2021, Qing Zhao wrote:

> 
> 
> > On Jun 22, 2021, at 9:00 AM, Richard Biener <rguenther@suse.de> wrote:
> > 
> > On Tue, 22 Jun 2021, Qing Zhao wrote:
> > 
> >> So, I am wondering why not still keep my current implementation on 
> >> assign different patterns for different types?
> >> 
> >> This major issue with this design is the code size and runtime overhead, 
> >> but for debugging purpose, those are not that important, right? And we 
> >> can add some optimization later to improve the code size and runtime 
> >> overhead.
> >> 
> >> Otherwise, if we only use one pattern for all the types in this initial 
> >> version, later we still might need change it.
> >> 
> >> How do you think?
> > 
> > No, let's not re-open that discussion.  As said we can look to support
> > multi-byte pattern if that has a chance to improve things but only
> > as followup.
> 
> I am fine with this.
> 
> However, we need to decide whether we will use one-byte repeatable pattern, or multiple-byte repeatable pattern now,
> Since the implementation will be different. If using one-byte, the implementation will be the simplest, we can use memset for all
> VLA, non-vla, zero-init, or pattern-init consistently.
> 
> However, if we choose multiple-byte pattern, then the implementation will be different, we cannot use memset for pattern-init, and 
> The implemenation for VLA pattern-init also is different.

As said, we can do this as followup.  For now get the easiest thing
working - one-byte patterns via memset.  There's enough bits in the
patch that will likely need followup fixes (the .DEFERED_INIT stuff),
actual code gneration of the init is separate enough we can deal with
it later.  Also IMHO not all targets necessarily need to behave the
same there.

Richard.

> Qing
> > 
> > Thanks,
> > Richard.
> > 
> >> Qing
> >> 
> >> On Jun 22, 2021, at 3:59 AM, Richard Biener <rguenther@suse.de<mailto:rguenther@suse.de>> wrote:
> >> 
> >> On Tue, 22 Jun 2021, Richard Sandiford wrote:
> >> 
> >> Kees Cook <keescook@chromium.org<mailto:keescook@chromium.org>> writes:
> >> On Mon, Jun 21, 2021 at 03:39:45PM +0000, Qing Zhao wrote:
> >> So, if “pattern value” is “0xFFFFFFFFFFFFFFFF”, then it’s a valid canonical virtual memory address.  However, for most OS, “0xFFFFFFFFFFFFFFFF” should be not in user space.
> >> 
> >> My question is, is “0xFFFFFFFFFFFFFFFFF” good for pointer? Or “0xAAAAAAAAAAAAAAAA” better?
> >> 
> >> I think 0xFF repeating is fine for this version. Everything else is a
> >> "nice to have" for the pattern-init, IMO. :)
> >> 
> >> Sorry to be awkward, but 0xFF seems worse than 0xAA to me.
> >> 
> >> For integer types, all values are valid representations, and we're
> >> relying on the pattern being “obviously” wrong in context.  0xAAAA…
> >> is unlikely to be a correct integer but 0xFFFF… would instead be a
> >> “nice” -1.  It would be difficult to tell in a debugger that a -1
> >> came from pattern init rather than a deliberate choice.
> >> 
> >> I agree that, all other things being equal, it would be nice to use NaNs
> >> for floats.  But relying on wrong numerical values for floats doesn't
> >> seem worse than doing that for integers.
> >> 
> >> 0xAA… for float is (if I've got this right) -3.0316488252093987e-13,
> >> which admittedly doesn't stand out as wrong.  But I'm not sure we
> >> should sacrifice integer debugging for float debugging here.
> >> 
> >> We can always expose the actual value as --param.  Now, I think
> >> we'd need a two-byte pattern to reliably produce NaNs anyway,
> >> so with floats taken out of the picture the focus should be on
> >> pointers where IMHO val & 1 and val & 15 would be nice to have.
> >> So sth like 0xf7 would work for those.  With a two-byte pattern
> >> we could use 0xffef or 0x7fef.
> >> 
> >> Anyway, it's probably down to priorities of the project involved
> >> (debugging FP stuff or integer stuff).
> >> 
> >> Richard.
> >> 
> >> 
> > 
> > -- 
> > Richard Biener <rguenther@suse.de>
> > SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
> > Germany; GF: Felix Imendörffer; HRB 36809 (AG Nuernberg)
> 
> 

-- 
Richard Biener <rguenther@suse.de>
SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
Germany; GF: Felix Imendörffer; HRB 36809 (AG Nuernberg)

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH][version 3]add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-06-22 14:15                                     ` Richard Biener
@ 2021-06-22 14:33                                       ` Qing Zhao
  2021-06-22 19:04                                         ` Richard Biener
  0 siblings, 1 reply; 57+ messages in thread
From: Qing Zhao @ 2021-06-22 14:33 UTC (permalink / raw)
  To: Richard Biener; +Cc: Richard Sandiford, Kees Cook, gcc-patches Qing Zhao via



> On Jun 22, 2021, at 9:15 AM, Richard Biener <rguenther@suse.de> wrote:
> 
> On Tue, 22 Jun 2021, Qing Zhao wrote:
> 
>> 
>> 
>>> On Jun 22, 2021, at 9:00 AM, Richard Biener <rguenther@suse.de> wrote:
>>> 
>>> On Tue, 22 Jun 2021, Qing Zhao wrote:
>>> 
>>>> So, I am wondering why not still keep my current implementation on 
>>>> assign different patterns for different types?
>>>> 
>>>> This major issue with this design is the code size and runtime overhead, 
>>>> but for debugging purpose, those are not that important, right? And we 
>>>> can add some optimization later to improve the code size and runtime 
>>>> overhead.
>>>> 
>>>> Otherwise, if we only use one pattern for all the types in this initial 
>>>> version, later we still might need change it.
>>>> 
>>>> How do you think?
>>> 
>>> No, let's not re-open that discussion.  As said we can look to support
>>> multi-byte pattern if that has a chance to improve things but only
>>> as followup.
>> 
>> I am fine with this.
>> 
>> However, we need to decide whether we will use one-byte repeatable pattern, or multiple-byte repeatable pattern now,
>> Since the implementation will be different. If using one-byte, the implementation will be the simplest, we can use memset for all
>> VLA, non-vla, zero-init, or pattern-init consistently.
>> 
>> However, if we choose multiple-byte pattern, then the implementation will be different, we cannot use memset for pattern-init, and 
>> The implemenation for VLA pattern-init also is different.
> 
> As said, we can do this as followup.  For now get the easiest thing
> working - one-byte patterns via memset.  

Okay. I will work on this.

> There's enough bits in the
> patch that will likely need followup fixes (the .DEFERED_INIT stuff),

Do you mean your previous suggestion to merge the handling of VLA to non-VLA during gimplification phase?
I have done with this change locally.

> actual code gneration of the init is separate enough we can deal with
> it later.  Also IMHO not all targets necessarily need to behave the
> same there.

Then, shall we make the code generation part a target hook now? Or do this later?

Qing
> 
> Richard.
> 
>> Qing
>>> 
>>> Thanks,
>>> Richard.
>>> 
>>>> Qing
>>>> 
>>>> On Jun 22, 2021, at 3:59 AM, Richard Biener <rguenther@suse.de<mailto:rguenther@suse.de>> wrote:
>>>> 
>>>> On Tue, 22 Jun 2021, Richard Sandiford wrote:
>>>> 
>>>> Kees Cook <keescook@chromium.org<mailto:keescook@chromium.org>> writes:
>>>> On Mon, Jun 21, 2021 at 03:39:45PM +0000, Qing Zhao wrote:
>>>> So, if “pattern value” is “0xFFFFFFFFFFFFFFFF”, then it’s a valid canonical virtual memory address.  However, for most OS, “0xFFFFFFFFFFFFFFFF” should be not in user space.
>>>> 
>>>> My question is, is “0xFFFFFFFFFFFFFFFFF” good for pointer? Or “0xAAAAAAAAAAAAAAAA” better?
>>>> 
>>>> I think 0xFF repeating is fine for this version. Everything else is a
>>>> "nice to have" for the pattern-init, IMO. :)
>>>> 
>>>> Sorry to be awkward, but 0xFF seems worse than 0xAA to me.
>>>> 
>>>> For integer types, all values are valid representations, and we're
>>>> relying on the pattern being “obviously” wrong in context.  0xAAAA…
>>>> is unlikely to be a correct integer but 0xFFFF… would instead be a
>>>> “nice” -1.  It would be difficult to tell in a debugger that a -1
>>>> came from pattern init rather than a deliberate choice.
>>>> 
>>>> I agree that, all other things being equal, it would be nice to use NaNs
>>>> for floats.  But relying on wrong numerical values for floats doesn't
>>>> seem worse than doing that for integers.
>>>> 
>>>> 0xAA… for float is (if I've got this right) -3.0316488252093987e-13,
>>>> which admittedly doesn't stand out as wrong.  But I'm not sure we
>>>> should sacrifice integer debugging for float debugging here.
>>>> 
>>>> We can always expose the actual value as --param.  Now, I think
>>>> we'd need a two-byte pattern to reliably produce NaNs anyway,
>>>> so with floats taken out of the picture the focus should be on
>>>> pointers where IMHO val & 1 and val & 15 would be nice to have.
>>>> So sth like 0xf7 would work for those.  With a two-byte pattern
>>>> we could use 0xffef or 0x7fef.
>>>> 
>>>> Anyway, it's probably down to priorities of the project involved
>>>> (debugging FP stuff or integer stuff).
>>>> 
>>>> Richard.
>>>> 
>>>> 
>>> 
>>> -- 
>>> Richard Biener <rguenther@suse.de>
>>> SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
>>> Germany; GF: Felix Imendörffer; HRB 36809 (AG Nuernberg)
>> 
>> 
> 
> -- 
> Richard Biener <rguenther@suse.de>
> SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
> Germany; GF: Felix Imendörffer; HRB 36809 (AG Nuernberg)


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH][version 3]add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-06-22  8:25                           ` Richard Sandiford
  2021-06-22  8:59                             ` Richard Biener
@ 2021-06-22 17:55                             ` Kees Cook
  2021-06-22 18:18                               ` Richard Sandiford
  1 sibling, 1 reply; 57+ messages in thread
From: Kees Cook @ 2021-06-22 17:55 UTC (permalink / raw)
  To: Qing Zhao, Richard Biener, gcc-patches Qing Zhao via, richard.sandiford

On Tue, Jun 22, 2021 at 09:25:57AM +0100, Richard Sandiford wrote:
> Kees Cook <keescook@chromium.org> writes:
> > On Mon, Jun 21, 2021 at 03:39:45PM +0000, Qing Zhao wrote:
> >> So, if “pattern value” is “0xFFFFFFFFFFFFFFFF”, then it’s a valid canonical virtual memory address.  However, for most OS, “0xFFFFFFFFFFFFFFFF” should be not in user space.
> >> 
> >> My question is, is “0xFFFFFFFFFFFFFFFFF” good for pointer? Or “0xAAAAAAAAAAAAAAAA” better?
> >
> > I think 0xFF repeating is fine for this version. Everything else is a
> > "nice to have" for the pattern-init, IMO. :)
> 
> Sorry to be awkward, but 0xFF seems worse than 0xAA to me.
> 
> For integer types, all values are valid representations, and we're
> relying on the pattern being “obviously” wrong in context.  0xAAAA…
> is unlikely to be a correct integer but 0xFFFF… would instead be a
> “nice” -1.  It would be difficult to tell in a debugger that a -1
> came from pattern init rather than a deliberate choice.

I can live with 0xAA. On x86_64, this puts it nicely in the middle of
the middle of the non-canonical space:

0x800000000000 - 0xffff7fffffffffff

The only trouble is with 32-bit, where the value 0xAAAAAAAA is a
legitimate allocatable userspace address. If we want some kind-of middle
ground, how about 0xFE? That'll be non-canonical on x86_64, and at the
high end of the i386 kernel address space.

> I agree that, all other things being equal, it would be nice to use NaNs
> for floats.  But relying on wrong numerical values for floats doesn't
> seem worse than doing that for integers.
> 
> 0xAA… for float is (if I've got this right) -3.0316488252093987e-13,
> which admittedly doesn't stand out as wrong.  But I'm not sure we
> should sacrifice integer debugging for float debugging here.

In some future version type-specific patterns would be a nice improvement,
but I don't want that to block getting the zero-init portion landed. :)

-- 
Kees Cook

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH][version 3]add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-06-22 17:55                             ` Kees Cook
@ 2021-06-22 18:18                               ` Richard Sandiford
  2021-06-22 21:31                                 ` Qing Zhao
  0 siblings, 1 reply; 57+ messages in thread
From: Richard Sandiford @ 2021-06-22 18:18 UTC (permalink / raw)
  To: Kees Cook; +Cc: Qing Zhao, Richard Biener, gcc-patches Qing Zhao via

Kees Cook <keescook@chromium.org> writes:
> On Tue, Jun 22, 2021 at 09:25:57AM +0100, Richard Sandiford wrote:
>> Kees Cook <keescook@chromium.org> writes:
>> > On Mon, Jun 21, 2021 at 03:39:45PM +0000, Qing Zhao wrote:
>> >> So, if “pattern value” is “0xFFFFFFFFFFFFFFFF”, then it’s a valid canonical virtual memory address.  However, for most OS, “0xFFFFFFFFFFFFFFFF” should be not in user space.
>> >> 
>> >> My question is, is “0xFFFFFFFFFFFFFFFFF” good for pointer? Or “0xAAAAAAAAAAAAAAAA” better?
>> >
>> > I think 0xFF repeating is fine for this version. Everything else is a
>> > "nice to have" for the pattern-init, IMO. :)
>> 
>> Sorry to be awkward, but 0xFF seems worse than 0xAA to me.
>> 
>> For integer types, all values are valid representations, and we're
>> relying on the pattern being “obviously” wrong in context.  0xAAAA…
>> is unlikely to be a correct integer but 0xFFFF… would instead be a
>> “nice” -1.  It would be difficult to tell in a debugger that a -1
>> came from pattern init rather than a deliberate choice.
>
> I can live with 0xAA. On x86_64, this puts it nicely in the middle of
> the middle of the non-canonical space:
>
> 0x800000000000 - 0xffff7fffffffffff
>
> The only trouble is with 32-bit, where the value 0xAAAAAAAA is a
> legitimate allocatable userspace address. If we want some kind-of middle
> ground, how about 0xFE? That'll be non-canonical on x86_64, and at the
> high end of the i386 kernel address space.

Sounds good to me FWIW.  That'd give float -1.694739530317379e+38
(suspiciously big even for astrophysics, I hope!) and would still
look unusual in an integer context.

>> I agree that, all other things being equal, it would be nice to use NaNs
>> for floats.  But relying on wrong numerical values for floats doesn't
>> seem worse than doing that for integers.
>> 
>> 0xAA… for float is (if I've got this right) -3.0316488252093987e-13,
>> which admittedly doesn't stand out as wrong.  But I'm not sure we
>> should sacrifice integer debugging for float debugging here.
>
> In some future version type-specific patterns would be a nice improvement,
> but I don't want that to block getting the zero-init portion landed. :)

Yeah.

Thanks,
Richard

^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH][version 3]add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-06-22 14:33                                       ` Qing Zhao
@ 2021-06-22 19:04                                         ` Richard Biener
  0 siblings, 0 replies; 57+ messages in thread
From: Richard Biener @ 2021-06-22 19:04 UTC (permalink / raw)
  To: Qing Zhao; +Cc: Richard Sandiford, Kees Cook, gcc-patches Qing Zhao via

On June 22, 2021 4:33:09 PM GMT+02:00, Qing Zhao <qing.zhao@oracle.com> wrote:
>
>
>> On Jun 22, 2021, at 9:15 AM, Richard Biener <rguenther@suse.de>
>wrote:
>> 
>> On Tue, 22 Jun 2021, Qing Zhao wrote:
>> 
>>> 
>>> 
>>>> On Jun 22, 2021, at 9:00 AM, Richard Biener <rguenther@suse.de>
>wrote:
>>>> 
>>>> On Tue, 22 Jun 2021, Qing Zhao wrote:
>>>> 
>>>>> So, I am wondering why not still keep my current implementation on
>
>>>>> assign different patterns for different types?
>>>>> 
>>>>> This major issue with this design is the code size and runtime
>overhead, 
>>>>> but for debugging purpose, those are not that important, right?
>And we 
>>>>> can add some optimization later to improve the code size and
>runtime 
>>>>> overhead.
>>>>> 
>>>>> Otherwise, if we only use one pattern for all the types in this
>initial 
>>>>> version, later we still might need change it.
>>>>> 
>>>>> How do you think?
>>>> 
>>>> No, let's not re-open that discussion.  As said we can look to
>support
>>>> multi-byte pattern if that has a chance to improve things but only
>>>> as followup.
>>> 
>>> I am fine with this.
>>> 
>>> However, we need to decide whether we will use one-byte repeatable
>pattern, or multiple-byte repeatable pattern now,
>>> Since the implementation will be different. If using one-byte, the
>implementation will be the simplest, we can use memset for all
>>> VLA, non-vla, zero-init, or pattern-init consistently.
>>> 
>>> However, if we choose multiple-byte pattern, then the implementation
>will be different, we cannot use memset for pattern-init, and 
>>> The implemenation for VLA pattern-init also is different.
>> 
>> As said, we can do this as followup.  For now get the easiest thing
>> working - one-byte patterns via memset.  
>
>Okay. I will work on this.
>
>> There's enough bits in the
>> patch that will likely need followup fixes (the .DEFERED_INIT stuff),
>
>Do you mean your previous suggestion to merge the handling of VLA to
>non-VLA during gimplification phase?
>I have done with this change locally.

No, just bugs that will inevitably show up. 

>> actual code gneration of the init is separate enough we can deal with
>> it later.  Also IMHO not all targets necessarily need to behave the
>> same there.
>
>Then, shall we make the code generation part a target hook now? Or do
>this later?

Do this later, if the need arises. 

Richard. 

>Qing
>> 
>> Richard.
>> 
>>> Qing
>>>> 
>>>> Thanks,
>>>> Richard.
>>>> 
>>>>> Qing
>>>>> 
>>>>> On Jun 22, 2021, at 3:59 AM, Richard Biener
><rguenther@suse.de<mailto:rguenther@suse.de>> wrote:
>>>>> 
>>>>> On Tue, 22 Jun 2021, Richard Sandiford wrote:
>>>>> 
>>>>> Kees Cook <keescook@chromium.org<mailto:keescook@chromium.org>>
>writes:
>>>>> On Mon, Jun 21, 2021 at 03:39:45PM +0000, Qing Zhao wrote:
>>>>> So, if “pattern value” is “0xFFFFFFFFFFFFFFFF”, then it’s a valid
>canonical virtual memory address.  However, for most OS,
>“0xFFFFFFFFFFFFFFFF” should be not in user space.
>>>>> 
>>>>> My question is, is “0xFFFFFFFFFFFFFFFFF” good for pointer? Or
>“0xAAAAAAAAAAAAAAAA” better?
>>>>> 
>>>>> I think 0xFF repeating is fine for this version. Everything else
>is a
>>>>> "nice to have" for the pattern-init, IMO. :)
>>>>> 
>>>>> Sorry to be awkward, but 0xFF seems worse than 0xAA to me.
>>>>> 
>>>>> For integer types, all values are valid representations, and we're
>>>>> relying on the pattern being “obviously” wrong in context. 
>0xAAAA…
>>>>> is unlikely to be a correct integer but 0xFFFF… would instead be a
>>>>> “nice” -1.  It would be difficult to tell in a debugger that a -1
>>>>> came from pattern init rather than a deliberate choice.
>>>>> 
>>>>> I agree that, all other things being equal, it would be nice to
>use NaNs
>>>>> for floats.  But relying on wrong numerical values for floats
>doesn't
>>>>> seem worse than doing that for integers.
>>>>> 
>>>>> 0xAA… for float is (if I've got this right)
>-3.0316488252093987e-13,
>>>>> which admittedly doesn't stand out as wrong.  But I'm not sure we
>>>>> should sacrifice integer debugging for float debugging here.
>>>>> 
>>>>> We can always expose the actual value as --param.  Now, I think
>>>>> we'd need a two-byte pattern to reliably produce NaNs anyway,
>>>>> so with floats taken out of the picture the focus should be on
>>>>> pointers where IMHO val & 1 and val & 15 would be nice to have.
>>>>> So sth like 0xf7 would work for those.  With a two-byte pattern
>>>>> we could use 0xffef or 0x7fef.
>>>>> 
>>>>> Anyway, it's probably down to priorities of the project involved
>>>>> (debugging FP stuff or integer stuff).
>>>>> 
>>>>> Richard.
>>>>> 
>>>>> 
>>>> 
>>>> -- 
>>>> Richard Biener <rguenther@suse.de>
>>>> SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409
>Nuernberg,
>>>> Germany; GF: Felix Imendörffer; HRB 36809 (AG Nuernberg)
>>> 
>>> 
>> 
>> -- 
>> Richard Biener <rguenther@suse.de>
>> SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409
>Nuernberg,
>> Germany; GF: Felix Imendörffer; HRB 36809 (AG Nuernberg)


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH][version 3]add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-06-22 18:18                               ` Richard Sandiford
@ 2021-06-22 21:31                                 ` Qing Zhao
  2021-06-23  6:05                                   ` Richard Biener
  0 siblings, 1 reply; 57+ messages in thread
From: Qing Zhao @ 2021-06-22 21:31 UTC (permalink / raw)
  To: Richard Sandiford, Kees cook, Richard Biener; +Cc: gcc-patches Qing Zhao via

Okay.

Now, I believe that we agreed on the following:

For this current patch:

1. Use byte-repeatable pattern for pattern-initialization;
2. Use one pattern for all types;
3. Use “0xFE” for the byte pattern value.

Possible future improvement:

1. Type specific patterns if needed;
2. User-specified pattern if needed; (add a new option for user to change the patterns).
3. Make the code generation part a target hook if needed.

Let me know if I miss anything.

Thanks.

Qing

> On Jun 22, 2021, at 1:18 PM, Richard Sandiford <richard.sandiford@arm.com> wrote:
> 
> Kees Cook <keescook@chromium.org> writes:
>> On Tue, Jun 22, 2021 at 09:25:57AM +0100, Richard Sandiford wrote:
>>> Kees Cook <keescook@chromium.org> writes:
>>>> On Mon, Jun 21, 2021 at 03:39:45PM +0000, Qing Zhao wrote:
>>>>> So, if “pattern value” is “0xFFFFFFFFFFFFFFFF”, then it’s a valid canonical virtual memory address.  However, for most OS, “0xFFFFFFFFFFFFFFFF” should be not in user space.
>>>>> 
>>>>> My question is, is “0xFFFFFFFFFFFFFFFFF” good for pointer? Or “0xAAAAAAAAAAAAAAAA” better?
>>>> 
>>>> I think 0xFF repeating is fine for this version. Everything else is a
>>>> "nice to have" for the pattern-init, IMO. :)
>>> 
>>> Sorry to be awkward, but 0xFF seems worse than 0xAA to me.
>>> 
>>> For integer types, all values are valid representations, and we're
>>> relying on the pattern being “obviously” wrong in context.  0xAAAA…
>>> is unlikely to be a correct integer but 0xFFFF… would instead be a
>>> “nice” -1.  It would be difficult to tell in a debugger that a -1
>>> came from pattern init rather than a deliberate choice.
>> 
>> I can live with 0xAA. On x86_64, this puts it nicely in the middle of
>> the middle of the non-canonical space:
>> 
>> 0x800000000000 - 0xffff7fffffffffff
>> 
>> The only trouble is with 32-bit, where the value 0xAAAAAAAA is a
>> legitimate allocatable userspace address. If we want some kind-of middle
>> ground, how about 0xFE? That'll be non-canonical on x86_64, and at the
>> high end of the i386 kernel address space.
> 
> Sounds good to me FWIW.  That'd give float -1.694739530317379e+38
> (suspiciously big even for astrophysics, I hope!) and would still
> look unusual in an integer context.
> 
>>> I agree that, all other things being equal, it would be nice to use NaNs
>>> for floats.  But relying on wrong numerical values for floats doesn't
>>> seem worse than doing that for integers.
>>> 
>>> 0xAA… for float is (if I've got this right) -3.0316488252093987e-13,
>>> which admittedly doesn't stand out as wrong.  But I'm not sure we
>>> should sacrifice integer debugging for float debugging here.
>> 
>> In some future version type-specific patterns would be a nice improvement,
>> but I don't want that to block getting the zero-init portion landed. :)
> 
> Yeah.
> 
> Thanks,
> Richard


^ permalink raw reply	[flat|nested] 57+ messages in thread

* Re: [PATCH][version 3]add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc
  2021-06-22 21:31                                 ` Qing Zhao
@ 2021-06-23  6:05                                   ` Richard Biener
  0 siblings, 0 replies; 57+ messages in thread
From: Richard Biener @ 2021-06-23  6:05 UTC (permalink / raw)
  To: Qing Zhao; +Cc: Richard Sandiford, Kees cook, gcc-patches Qing Zhao via

On Tue, 22 Jun 2021, Qing Zhao wrote:

> Okay.
> 
> Now, I believe that we agreed on the following:
> 
> For this current patch:
> 
> 1. Use byte-repeatable pattern for pattern-initialization;
> 2. Use one pattern for all types;
> 3. Use “0xFE” for the byte pattern value.

Ack.

Richard.

> Possible future improvement:
> 
> 1. Type specific patterns if needed;
> 2. User-specified pattern if needed; (add a new option for user to change the patterns).
> 3. Make the code generation part a target hook if needed.
>
> Let me know if I miss anything.
> 
> Thanks.
> 
> Qing
> 
> > On Jun 22, 2021, at 1:18 PM, Richard Sandiford <richard.sandiford@arm.com> wrote:
> > 
> > Kees Cook <keescook@chromium.org> writes:
> >> On Tue, Jun 22, 2021 at 09:25:57AM +0100, Richard Sandiford wrote:
> >>> Kees Cook <keescook@chromium.org> writes:
> >>>> On Mon, Jun 21, 2021 at 03:39:45PM +0000, Qing Zhao wrote:
> >>>>> So, if “pattern value” is “0xFFFFFFFFFFFFFFFF”, then it’s a valid canonical virtual memory address.  However, for most OS, “0xFFFFFFFFFFFFFFFF” should be not in user space.
> >>>>> 
> >>>>> My question is, is “0xFFFFFFFFFFFFFFFFF” good for pointer? Or “0xAAAAAAAAAAAAAAAA” better?
> >>>> 
> >>>> I think 0xFF repeating is fine for this version. Everything else is a
> >>>> "nice to have" for the pattern-init, IMO. :)
> >>> 
> >>> Sorry to be awkward, but 0xFF seems worse than 0xAA to me.
> >>> 
> >>> For integer types, all values are valid representations, and we're
> >>> relying on the pattern being “obviously” wrong in context.  0xAAAA…
> >>> is unlikely to be a correct integer but 0xFFFF… would instead be a
> >>> “nice” -1.  It would be difficult to tell in a debugger that a -1
> >>> came from pattern init rather than a deliberate choice.
> >> 
> >> I can live with 0xAA. On x86_64, this puts it nicely in the middle of
> >> the middle of the non-canonical space:
> >> 
> >> 0x800000000000 - 0xffff7fffffffffff
> >> 
> >> The only trouble is with 32-bit, where the value 0xAAAAAAAA is a
> >> legitimate allocatable userspace address. If we want some kind-of middle
> >> ground, how about 0xFE? That'll be non-canonical on x86_64, and at the
> >> high end of the i386 kernel address space.
> > 
> > Sounds good to me FWIW.  That'd give float -1.694739530317379e+38
> > (suspiciously big even for astrophysics, I hope!) and would still
> > look unusual in an integer context.
> > 
> >>> I agree that, all other things being equal, it would be nice to use NaNs
> >>> for floats.  But relying on wrong numerical values for floats doesn't
> >>> seem worse than doing that for integers.
> >>> 
> >>> 0xAA… for float is (if I've got this right) -3.0316488252093987e-13,
> >>> which admittedly doesn't stand out as wrong.  But I'm not sure we
> >>> should sacrifice integer debugging for float debugging here.
> >> 
> >> In some future version type-specific patterns would be a nice improvement,
> >> but I don't want that to block getting the zero-init portion landed. :)
> > 
> > Yeah.
> > 
> > Thanks,
> > Richard
> 
> 

-- 
Richard Biener <rguenther@suse.de>
SUSE Software Solutions Germany GmbH, Maxfeldstrasse 5, 90409 Nuernberg,
Germany; GF: Felix Imendörffer; HRB 36809 (AG Nuernberg)

^ permalink raw reply	[flat|nested] 57+ messages in thread

end of thread, other threads:[~2021-06-23  6:05 UTC | newest]

Thread overview: 57+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-05-12 17:16 [PATCH][version 3]add -ftrivial-auto-var-init and variable attribute "uninitialized" to gcc Qing Zhao
2021-05-25 19:26 ` Qing Zhao
2021-05-26 11:18 ` Richard Biener
2021-05-27 19:44   ` Qing Zhao
2021-06-07  7:48     ` Richard Biener
2021-06-07 16:13       ` Qing Zhao
2021-06-08  7:37         ` Richard Biener
2021-06-08 16:56           ` Kees Cook
2021-06-08 17:32             ` Qing Zhao
2021-06-08 17:36               ` Kees Cook
2021-06-07 23:45       ` Kees Cook
2021-06-08  8:27         ` Richard Biener
2021-05-27 21:42   ` Qing Zhao
2021-06-03 20:14   ` Qing Zhao
2021-06-07  7:50     ` Richard Biener
2021-06-03 20:18   ` Qing Zhao
2021-06-07  7:53     ` Richard Biener
2021-06-07 16:18       ` Qing Zhao
2021-06-07 23:48         ` Kees Cook
2021-06-08  7:41         ` Richard Biener
2021-06-08 15:27           ` Qing Zhao
2021-06-08 16:59           ` Kees Cook
2021-06-08 18:05             ` Qing Zhao
2021-06-11 11:04             ` Richard Biener
2021-06-11 17:14               ` Kees Cook
2021-06-10 21:11   ` Qing Zhao
2021-06-11 11:12     ` Richard Biener
2021-06-11 15:49       ` Qing Zhao
2021-06-11 16:24         ` Kees Cook
2021-06-11 17:00         ` Qing Zhao
2021-06-14 16:10         ` Qing Zhao
2021-06-15 13:21           ` Richard Biener
2021-06-15 21:49             ` Qing Zhao
2021-06-16  6:19               ` Richard Biener
2021-06-16 15:04                 ` Qing Zhao
2021-06-16 19:39                   ` Qing Zhao
2021-06-18 23:47                     ` Kees Cook
2021-06-21 15:39                       ` Qing Zhao
2021-06-21 16:18                         ` Kees Cook
2021-06-21 17:11                           ` Qing Zhao
2021-06-22  8:25                           ` Richard Sandiford
2021-06-22  8:59                             ` Richard Biener
2021-06-22 13:54                               ` Qing Zhao
2021-06-22 14:00                                 ` Richard Biener
2021-06-22 14:10                                   ` Qing Zhao
2021-06-22 14:15                                     ` Richard Biener
2021-06-22 14:33                                       ` Qing Zhao
2021-06-22 19:04                                         ` Richard Biener
2021-06-22 17:55                             ` Kees Cook
2021-06-22 18:18                               ` Richard Sandiford
2021-06-22 21:31                                 ` Qing Zhao
2021-06-23  6:05                                   ` Richard Biener
2021-06-21  7:53                   ` Richard Biener
2021-06-21 15:11                     ` Qing Zhao
2021-06-21 15:35                       ` Richard Biener
2021-06-21 16:13                         ` Qing Zhao
2021-06-22  6:24                           ` Richard Biener

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).