aboutsummaryrefslogtreecommitdiff
path: root/gcc/gimplify.c
diff options
context:
space:
mode:
authorqing zhao <qing.zhao@oracle.com>2021-09-09 15:44:49 -0700
committerqing zhao <qing.zhao@oracle.com>2021-09-09 15:44:49 -0700
commita25e0b5e6ac8a77a71c229e0a7b744603365b0e9 (patch)
treee46dad7fa274dc376be2ccf4735b5333c5d34315 /gcc/gimplify.c
parent5fe0865ab788bdc387b284a3ad57e5a95a767b18 (diff)
downloadgcc-a25e0b5e6ac8a77a71c229e0a7b744603365b0e9.zip
gcc-a25e0b5e6ac8a77a71c229e0a7b744603365b0e9.tar.gz
gcc-a25e0b5e6ac8a77a71c229e0a7b744603365b0e9.tar.bz2
Add -ftrivial-auto-var-init option and uninitialized variable attribute.
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. With this option, GCC will also initialize any padding of automatic variables that have structure or union types to zeroes. You can control this behavior for a specific variable by using the variable attribute "uninitialized" to control runtime overhead. gcc/ChangeLog: 2021-09-09 qing zhao <qing.zhao@oracle.com> * builtins.c (expand_builtin_memset): Make external visible. * builtins.h (expand_builtin_memset): Declare extern. * common.opt (ftrivial-auto-var-init=): New option. * doc/extend.texi: Document the uninitialized attribute. * doc/invoke.texi: Document -ftrivial-auto-var-init. * flag-types.h (enum auto_init_type): New enumerated type auto_init_type. * gimple-fold.c (clear_padding_type): Add one new parameter. (clear_padding_union): Likewise. (clear_padding_emit_loop): Likewise. (clear_type_padding_in_mask): Likewise. (gimple_fold_builtin_clear_padding): Handle this new parameter. * gimplify.c (gimple_add_init_for_auto_var): New function. (gimple_add_padding_init_for_auto_var): New function. (is_var_need_auto_init): New function. (gimplify_decl_expr): Add initialization to automatic variables per users' requests. (gimplify_call_expr): Add one new parameter for call to __builtin_clear_padding. (gimplify_init_constructor): Add padding initialization in the end. * internal-fn.c (INIT_PATTERN_VALUE): New macro. (expand_DEFERRED_INIT): New function. * internal-fn.def (DEFERRED_INIT): New internal function. * tree-cfg.c (verify_gimple_call): Verify calls to .DEFERRED_INIT. * tree-sra.c (generate_subtree_deferred_init): New function. (scan_function): Avoid setting cannot_scalarize_away_bitmap for calls to .DEFERRED_INIT. (sra_modify_deferred_init): New function. (sra_modify_function_body): Handle calls to DEFERRED_INIT specially. * tree-ssa-structalias.c (find_func_aliases_for_call): Likewise. * tree-ssa-uninit.c (warn_uninit): Handle calls to DEFERRED_INIT specially. (check_defs): Likewise. (warn_uninitialized_vars): Likewise. * tree-ssa.c (ssa_undefined_value_p): Likewise. * tree.c (build_common_builtin_nodes): Build tree node for BUILT_IN_CLEAR_PADDING when needed. gcc/c-family/ChangeLog: 2021-09-09 qing zhao <qing.zhao@oracle.com> * c-attribs.c (handle_uninitialized_attribute): New function. (c_common_attribute_table): Add "uninitialized" attribute. gcc/testsuite/ChangeLog: 2021-09-09 qing zhao <qing.zhao@oracle.com> * c-c++-common/auto-init-1.c: New test. * c-c++-common/auto-init-10.c: New test. * c-c++-common/auto-init-11.c: New test. * c-c++-common/auto-init-12.c: New test. * c-c++-common/auto-init-13.c: New test. * c-c++-common/auto-init-14.c: New test. * c-c++-common/auto-init-15.c: New test. * c-c++-common/auto-init-16.c: New test. * c-c++-common/auto-init-2.c: New test. * c-c++-common/auto-init-3.c: New test. * c-c++-common/auto-init-4.c: New test. * c-c++-common/auto-init-5.c: New test. * c-c++-common/auto-init-6.c: New test. * c-c++-common/auto-init-7.c: New test. * c-c++-common/auto-init-8.c: New test. * c-c++-common/auto-init-9.c: New test. * c-c++-common/auto-init-esra.c: New test. * c-c++-common/auto-init-padding-1.c: New test. * c-c++-common/auto-init-padding-2.c: New test. * c-c++-common/auto-init-padding-3.c: New test. * g++.dg/auto-init-uninit-pred-1_a.C: New test. * g++.dg/auto-init-uninit-pred-2_a.C: New test. * g++.dg/auto-init-uninit-pred-3_a.C: New test. * g++.dg/auto-init-uninit-pred-4.C: New test. * gcc.dg/auto-init-sra-1.c: New test. * gcc.dg/auto-init-sra-2.c: New test. * gcc.dg/auto-init-uninit-1.c: New test. * gcc.dg/auto-init-uninit-12.c: New test. * gcc.dg/auto-init-uninit-13.c: New test. * gcc.dg/auto-init-uninit-14.c: New test. * gcc.dg/auto-init-uninit-15.c: New test. * gcc.dg/auto-init-uninit-16.c: New test. * gcc.dg/auto-init-uninit-17.c: New test. * gcc.dg/auto-init-uninit-18.c: New test. * gcc.dg/auto-init-uninit-19.c: New test. * gcc.dg/auto-init-uninit-2.c: New test. * gcc.dg/auto-init-uninit-20.c: New test. * gcc.dg/auto-init-uninit-21.c: New test. * gcc.dg/auto-init-uninit-22.c: New test. * gcc.dg/auto-init-uninit-23.c: New test. * gcc.dg/auto-init-uninit-24.c: New test. * gcc.dg/auto-init-uninit-25.c: New test. * gcc.dg/auto-init-uninit-26.c: New test. * gcc.dg/auto-init-uninit-3.c: New test. * gcc.dg/auto-init-uninit-34.c: New test. * gcc.dg/auto-init-uninit-36.c: New test. * gcc.dg/auto-init-uninit-37.c: New test. * gcc.dg/auto-init-uninit-4.c: New test. * gcc.dg/auto-init-uninit-5.c: New test. * gcc.dg/auto-init-uninit-6.c: New test. * gcc.dg/auto-init-uninit-8.c: New test. * gcc.dg/auto-init-uninit-9.c: New test. * gcc.dg/auto-init-uninit-A.c: New test. * gcc.dg/auto-init-uninit-B.c: New test. * gcc.dg/auto-init-uninit-C.c: New test. * gcc.dg/auto-init-uninit-H.c: New test. * gcc.dg/auto-init-uninit-I.c: New test. * gcc.target/aarch64/auto-init-1.c: New test. * gcc.target/aarch64/auto-init-2.c: New test. * gcc.target/aarch64/auto-init-3.c: New test. * gcc.target/aarch64/auto-init-4.c: New test. * gcc.target/aarch64/auto-init-5.c: New test. * gcc.target/aarch64/auto-init-6.c: New test. * gcc.target/aarch64/auto-init-7.c: New test. * gcc.target/aarch64/auto-init-8.c: New test. * gcc.target/aarch64/auto-init-padding-1.c: New test. * gcc.target/aarch64/auto-init-padding-10.c: New test. * gcc.target/aarch64/auto-init-padding-11.c: New test. * gcc.target/aarch64/auto-init-padding-12.c: New test. * gcc.target/aarch64/auto-init-padding-2.c: New test. * gcc.target/aarch64/auto-init-padding-3.c: New test. * gcc.target/aarch64/auto-init-padding-4.c: New test. * gcc.target/aarch64/auto-init-padding-5.c: New test. * gcc.target/aarch64/auto-init-padding-6.c: New test. * gcc.target/aarch64/auto-init-padding-7.c: New test. * gcc.target/aarch64/auto-init-padding-8.c: New test. * gcc.target/aarch64/auto-init-padding-9.c: New test. * gcc.target/i386/auto-init-1.c: New test. * gcc.target/i386/auto-init-2.c: New test. * gcc.target/i386/auto-init-21.c: New test. * gcc.target/i386/auto-init-22.c: New test. * gcc.target/i386/auto-init-23.c: New test. * gcc.target/i386/auto-init-24.c: New test. * gcc.target/i386/auto-init-3.c: New test. * gcc.target/i386/auto-init-4.c: New test. * gcc.target/i386/auto-init-5.c: New test. * gcc.target/i386/auto-init-6.c: New test. * gcc.target/i386/auto-init-7.c: New test. * gcc.target/i386/auto-init-8.c: New test. * gcc.target/i386/auto-init-padding-1.c: New test. * gcc.target/i386/auto-init-padding-10.c: New test. * gcc.target/i386/auto-init-padding-11.c: New test. * gcc.target/i386/auto-init-padding-12.c: New test. * gcc.target/i386/auto-init-padding-2.c: New test. * gcc.target/i386/auto-init-padding-3.c: New test. * gcc.target/i386/auto-init-padding-4.c: New test. * gcc.target/i386/auto-init-padding-5.c: New test. * gcc.target/i386/auto-init-padding-6.c: New test. * gcc.target/i386/auto-init-padding-7.c: New test. * gcc.target/i386/auto-init-padding-8.c: New test. * gcc.target/i386/auto-init-padding-9.c: New test.
Diffstat (limited to 'gcc/gimplify.c')
-rw-r--r--gcc/gimplify.c151
1 files changed, 142 insertions, 9 deletions
diff --git a/gcc/gimplify.c b/gcc/gimplify.c
index 99d1c7fc..3314f76 100644
--- a/gcc/gimplify.c
+++ b/gcc/gimplify.c
@@ -1743,6 +1743,94 @@ force_labels_r (tree *tp, int *walk_subtrees, void *data ATTRIBUTE_UNUSED)
return NULL_TREE;
}
+/* Generate an initialization to automatic variable DECL based on INIT_TYPE.
+ Build a call to internal const function DEFERRED_INIT:
+ 1st argument: SIZE of the DECL;
+ 2nd argument: INIT_TYPE;
+ 3rd argument: IS_VLA, 0 NO, 1 YES;
+
+ as LHS = DEFERRED_INIT (SIZE of the DECL, INIT_TYPE, IS_VLA)
+ if IS_VLA is false, the LHS is the DECL itself,
+ if IS_VLA is true, the LHS is a MEM_REF whose address is the pointer
+ to this DECL. */
+static void
+gimple_add_init_for_auto_var (tree decl,
+ enum auto_init_type init_type,
+ bool is_vla,
+ gimple_seq *seq_p)
+{
+ gcc_assert (auto_var_p (decl));
+ gcc_assert (init_type > AUTO_INIT_UNINITIALIZED);
+ location_t loc = EXPR_LOCATION (decl);
+ tree decl_size = TYPE_SIZE_UNIT (TREE_TYPE (decl));
+
+ tree init_type_node
+ = build_int_cst (integer_type_node, (int) init_type);
+ tree is_vla_node
+ = build_int_cst (integer_type_node, (int) is_vla);
+
+ tree call = build_call_expr_internal_loc (loc, IFN_DEFERRED_INIT,
+ TREE_TYPE (decl), 3,
+ decl_size, init_type_node,
+ is_vla_node);
+
+ gimplify_assign (decl, call, seq_p);
+}
+
+/* Generate padding initialization for automatic vairable DECL.
+ 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 padding is initialized to zero. So, we always initialize paddings
+ to zeroes regardless INIT_TYPE.
+ To do the padding initialization, we insert a call to
+ __BUILTIN_CLEAR_PADDING (&decl, 0, for_auto_init = true).
+ Note, we add an additional dummy argument for __BUILTIN_CLEAR_PADDING,
+ 'for_auto_init' to distinguish whether this call is for automatic
+ variable initialization or not.
+ */
+static void
+gimple_add_padding_init_for_auto_var (tree decl, bool is_vla,
+ gimple_seq *seq_p)
+{
+ tree addr_of_decl = NULL_TREE;
+ bool for_auto_init = true;
+ tree fn = builtin_decl_explicit (BUILT_IN_CLEAR_PADDING);
+
+ if (is_vla)
+ {
+ /* The temporary address variable for this vla should be
+ created in gimplify_vla_decl. */
+ gcc_assert (DECL_HAS_VALUE_EXPR_P (decl));
+ gcc_assert (TREE_CODE (DECL_VALUE_EXPR (decl)) == INDIRECT_REF);
+ addr_of_decl = TREE_OPERAND (DECL_VALUE_EXPR (decl), 0);
+ }
+ else
+ {
+ mark_addressable (decl);
+ addr_of_decl = build_fold_addr_expr (decl);
+ }
+
+ gimple *call = gimple_build_call (fn,
+ 3, addr_of_decl,
+ build_zero_cst (TREE_TYPE (addr_of_decl)),
+ build_int_cst (integer_type_node,
+ (int) for_auto_init));
+ gimplify_seq_add_stmt (seq_p, call);
+}
+
+/* Return true if the DECL need to be automaticly initialized by the
+ compiler. */
+static bool
+is_var_need_auto_init (tree decl)
+{
+ if (auto_var_p (decl)
+ && (flag_auto_var_init > AUTO_INIT_UNINITIALIZED)
+ && (!lookup_attribute ("uninitialized", DECL_ATTRIBUTES (decl))))
+ return true;
+ return false;
+}
+
/* Gimplify a DECL_EXPR node *STMT_P by making any necessary allocation
and initialization explicit. */
@@ -1840,6 +1928,26 @@ 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. */
+ else if (is_var_need_auto_init (decl))
+ {
+ gimple_add_init_for_auto_var (decl,
+ flag_auto_var_init,
+ is_vla,
+ seq_p);
+ /* The expanding of a call to the above .DEFERRED_INIT will apply
+ block initialization to the whole space covered by this variable.
+ As a result, all the paddings will be initialized to zeroes
+ for zero initialization and 0xFE byte-repeatable patterns for
+ pattern initialization.
+ In order to make the paddings as zeroes for pattern init, We
+ should add a call to __builtin_clear_padding to clear the
+ paddings to zero in compatiple with CLANG. */
+ if (flag_auto_var_init == AUTO_INIT_PATTERN)
+ gimple_add_padding_init_for_auto_var (decl, is_vla, seq_p);
+ }
}
return GS_ALL_DONE;
@@ -3411,11 +3519,15 @@ gimplify_call_expr (tree *expr_p, gimple_seq *pre_p, bool want_value)
{
/* Remember the original type of the argument in an internal
dummy second argument, as in GIMPLE pointer conversions are
- useless. */
+ useless. also mark this call as not for automatic initialization
+ in the internal dummy third argument. */
p = CALL_EXPR_ARG (*expr_p, 0);
+ bool for_auto_init = false;
*expr_p
- = build_call_expr_loc (EXPR_LOCATION (*expr_p), fndecl, 2, p,
- build_zero_cst (TREE_TYPE (p)));
+ = build_call_expr_loc (EXPR_LOCATION (*expr_p), fndecl, 3, p,
+ build_zero_cst (TREE_TYPE (p)),
+ build_int_cst (integer_type_node,
+ (int) for_auto_init));
return GS_OK;
}
break;
@@ -4872,6 +4984,9 @@ gimplify_init_constructor (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
tree object, ctor, type;
enum gimplify_status ret;
vec<constructor_elt, va_gc> *elts;
+ bool cleared = false;
+ bool is_empty_ctor = false;
+ bool is_init_expr = (TREE_CODE (*expr_p) == INIT_EXPR);
gcc_assert (TREE_CODE (TREE_OPERAND (*expr_p, 1)) == CONSTRUCTOR);
@@ -4914,7 +5029,7 @@ gimplify_init_constructor (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
struct gimplify_init_ctor_preeval_data preeval_data;
HOST_WIDE_INT num_ctor_elements, num_nonzero_elements;
HOST_WIDE_INT num_unique_nonzero_elements;
- bool cleared, complete_p, valid_const_initializer;
+ bool complete_p, valid_const_initializer;
/* Aggregate types must lower constructors to initialization of
individual elements. The exception is that a CONSTRUCTOR node
@@ -4923,6 +5038,7 @@ gimplify_init_constructor (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
{
if (notify_temp_creation)
return GS_OK;
+ is_empty_ctor = true;
break;
}
@@ -5248,13 +5364,28 @@ gimplify_init_constructor (tree *expr_p, gimple_seq *pre_p, gimple_seq *post_p,
if (want_value)
{
*expr_p = object;
- return GS_OK;
+ ret = GS_OK;
}
else
{
*expr_p = NULL;
- return GS_ALL_DONE;
- }
+ ret = GS_ALL_DONE;
+ }
+
+ /* If the user requests to initialize automatic variables, we
+ should initialize paddings inside the variable. Add a call to
+ __BUILTIN_CLEAR_PADDING (&object, 0, for_auto_init = true) to
+ initialize paddings of object always to zero regardless of
+ INIT_TYPE. Note, we will not insert this call if the aggregate
+ variable has be completely cleared already or it's initialized
+ with an empty constructor. */
+ if (is_init_expr
+ && ((AGGREGATE_TYPE_P (type) && !cleared && !is_empty_ctor)
+ || !AGGREGATE_TYPE_P (type))
+ && is_var_need_auto_init (object))
+ gimple_add_padding_init_for_auto_var (object, false, pre_p);
+
+ return ret;
}
/* Given a pointer value OP0, return a simplified version of an
@@ -5395,10 +5526,12 @@ gimplify_modify_expr_rhs (tree *expr_p, tree *from_p, tree *to_p,
crack at this before we break it down. */
if (ret != GS_UNHANDLED)
break;
+
/* If we're initializing from a CONSTRUCTOR, break this into
individual MODIFY_EXPRs. */
- return gimplify_init_constructor (expr_p, pre_p, post_p, want_value,
- false);
+ ret = gimplify_init_constructor (expr_p, pre_p, post_p, want_value,
+ false);
+ return ret;
case COND_EXPR:
/* If we're assigning to a non-register type, push the assignment