On Wed, Jul 14, 2021 at 02:09:50PM +0000, Qing Zhao wrote: > Hi, Richard, > > > On Jul 14, 2021, at 2:14 AM, Richard Biener <richard.guent...@gmail.com> > > wrote: > > > > On Wed, Jul 14, 2021 at 1:17 AM Qing Zhao <qing.z...@oracle.com> wrote: > >> > >> Hi, Kees, > >> > >> I took a look at the kernel testing case you attached in the previous > >> email, and found the testing failed with the following case: > >> > >> #define INIT_STRUCT_static_all = { .one = arg->one, \ > >> .two = arg->two, \ > >> .three = arg->three, \ > >> .four = arg->four, \ > >> } > >> > >> i.e, when the structure type auto variable has been explicitly initialized > >> in the source code. -ftrivial-auto-var-init in the 4th version > >> does not initialize the paddings for such variables. > >> > >> But in the previous version of the patches ( 2 or 3), > >> -ftrivial-auto-var-init initializes the paddings for such variables. > >> > >> I intended to remove this part of the code from the 4th version of the > >> patch since the implementation for initializing such paddings is > >> completely different from > >> the initializing of the whole structure as a whole with memset in this > >> version of the implementation. > >> > >> If we really need this functionality, I will add another separate patch > >> for this additional functionality, but not with this patch. > >> > >> Richard, what’s your comment and suggestions on this? > > > > I think this can be addressed in the gimplifier by adjusting > > gimplify_init_constructor to clear > > the object before the initialization (if it's not done via aggregate > > copying). > > I did this in the previous versions of the patch like the following: > > @@ -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; > > Then the paddings are also initialized to zeroes with this option. (Even for > -ftrivial-auto-var-init=pattern).
Thanks! I've tested with the attached patch to v4 and it passes all my tests again. > Is the above change Okay? (With this change, when > -ftrivial-auto-var-init=pattern, the paddings for the > structure variables that have explicit initializer will be ZEROed, not 0xFE) Padding zeroing in the face of pattern-init is correct (and matches what Clang does). -Kees -- Kees Cook
commit 8c52b69540b064e930e4d9e2e3dc011ca002306d Author: Kees Cook <keesc...@chromium.org> AuthorDate: Wed Jul 14 11:17:27 2021 -0700 Commit: Kees Cook <keesc...@chromium.org> CommitDate: Wed Jul 14 12:08:56 2021 -0700 Fix padding Based on v2 and bddde2d2-8594-4bf6-8142-cd09b0ebb...@oracle.com diff --git a/gcc/gimplify.c b/gcc/gimplify.c index 4db53cda77f8..dd3da86d6663 100644 --- a/gcc/gimplify.c +++ b/gcc/gimplify.c @@ -5071,6 +5071,18 @@ 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 (opt_for_fn (current_function_decl, flag_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/tree.c b/gcc/tree.c index 1aa6e557a049..7889c10d639f 100644 --- a/gcc/tree.c +++ b/gcc/tree.c @@ -10818,6 +10818,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 8bdf16d8b4ab..56a7947d935d 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -5168,6 +5168,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);