2019-12-10 Jakub Jelinek <jakub@redhat.com>
+ PR middle-end/92825
+ * cfgexpand.c (add_stack_protection_conflicts): Change return type
+ from void to bool, return true if at least one stack_vars[i].decl
+ is addressable.
+ (record_or_union_type_has_array_p, stack_protect_decl_p): Remove.
+ (expand_used_vars): Don't call stack_protect_decl_p, instead for
+ -fstack-protector-strong set gen_stack_protect_signal to true
+ if add_stack_protection_conflicts returned true. Formatting fixes.
+ * doc/invoke.texi (-fstack-protector-strong): Clarify that optimized
+ out variables or variables not living on the stack don't count.
+ (-fstack-protector): Likewise. Clarify it affects >= 8 byte arrays
+ rather than > 8 byte.
+
* ipa-param-manipulation.c
(ipa_param_body_adjustments::register_replacement): Fix comment typo
- accross -> across.
}
/* Ensure that variables in different stack protection phases conflict
- so that they are not merged and share the same stack slot. */
+ so that they are not merged and share the same stack slot.
+ Return true if there are any address taken variables. */
-static void
+static bool
add_stack_protection_conflicts (void)
{
size_t i, j, n = stack_vars_num;
unsigned char *phase;
+ bool ret = false;
phase = XNEWVEC (unsigned char, n);
for (i = 0; i < n; ++i)
- phase[i] = stack_protect_decl_phase (stack_vars[i].decl);
+ {
+ phase[i] = stack_protect_decl_phase (stack_vars[i].decl);
+ if (TREE_ADDRESSABLE (stack_vars[i].decl))
+ ret = true;
+ }
for (i = 0; i < n; ++i)
{
}
XDELETEVEC (phase);
+ return ret;
}
/* Create a decl for the guard at the top of the stack frame. */
return estimated_poly_value (size);
}
-/* Helper routine to check if a record or union contains an array field. */
-
-static int
-record_or_union_type_has_array_p (const_tree tree_type)
-{
- tree fields = TYPE_FIELDS (tree_type);
- tree f;
-
- for (f = fields; f; f = DECL_CHAIN (f))
- if (TREE_CODE (f) == FIELD_DECL)
- {
- tree field_type = TREE_TYPE (f);
- if (RECORD_OR_UNION_TYPE_P (field_type)
- && record_or_union_type_has_array_p (field_type))
- return 1;
- if (TREE_CODE (field_type) == ARRAY_TYPE)
- return 1;
- }
- return 0;
-}
-
-/* Check if the current function has local referenced variables that
- have their addresses taken, contain an array, or are arrays. */
-
-static bool
-stack_protect_decl_p ()
-{
- unsigned i;
- tree var;
-
- FOR_EACH_LOCAL_DECL (cfun, i, var)
- if (!is_global_var (var))
- {
- tree var_type = TREE_TYPE (var);
- if (VAR_P (var)
- && (TREE_CODE (var_type) == ARRAY_TYPE
- || TREE_ADDRESSABLE (var)
- || (RECORD_OR_UNION_TYPE_P (var_type)
- && record_or_union_type_has_array_p (var_type))))
- return true;
- }
- return false;
-}
-
/* Check if the current function has calls that use a return slot. */
static bool
}
if (flag_stack_protect == SPCT_FLAG_STRONG)
- gen_stack_protect_signal
- = stack_protect_decl_p () || stack_protect_return_slot_p ();
+ gen_stack_protect_signal = stack_protect_return_slot_p ();
/* At this point all variables on the local_decls with TREE_USED
set are not associated with any block scope. Lay them out. */
if (stack_vars_num > 0)
{
+ bool has_addressable_vars = false;
+
add_scope_conflicts ();
/* If stack protection is enabled, we don't share space between
|| (flag_stack_protect == SPCT_FLAG_EXPLICIT
&& lookup_attribute ("stack_protect",
DECL_ATTRIBUTES (current_function_decl)))))
- add_stack_protection_conflicts ();
+ has_addressable_vars = add_stack_protection_conflicts ();
+
+ if (flag_stack_protect == SPCT_FLAG_STRONG && has_addressable_vars)
+ gen_stack_protect_signal = true;
/* Now that we have collected all stack variables, and have computed a
minimal interference graph, attempt to save some stack space. */
case SPCT_FLAG_STRONG:
if (gen_stack_protect_signal
- || cfun->calls_alloca || has_protected_decls
+ || cfun->calls_alloca
+ || has_protected_decls
|| lookup_attribute ("stack_protect",
DECL_ATTRIBUTES (current_function_decl)))
create_stack_guard ();
break;
case SPCT_FLAG_DEFAULT:
- if (cfun->calls_alloca || has_protected_decls
+ if (cfun->calls_alloca
+ || has_protected_decls
|| lookup_attribute ("stack_protect",
DECL_ATTRIBUTES (current_function_decl)))
create_stack_guard ();
DECL_ATTRIBUTES (current_function_decl)))
create_stack_guard ();
break;
+
default:
- ;
+ break;
}
/* Assign rtl to each variable based on these partitions. */
Emit extra code to check for buffer overflows, such as stack smashing
attacks. This is done by adding a guard variable to functions with
vulnerable objects. This includes functions that call @code{alloca}, and
-functions with buffers larger than 8 bytes. The guards are initialized
-when a function is entered and then checked when the function exits.
-If a guard check fails, an error message is printed and the program exits.
+functions with buffers larger than or equal to 8 bytes. The guards are
+initialized when a function is entered and then checked when the function
+exits. If a guard check fails, an error message is printed and the program
+exits. Only variables that are actually allocated on the stack are
+considered, optimized away variables or variables allocated in registers
+don't count.
@item -fstack-protector-all
@opindex fstack-protector-all
@opindex fstack-protector-strong
Like @option{-fstack-protector} but includes additional functions to
be protected --- those that have local array definitions, or have
-references to local frame addresses.
+references to local frame addresses. Only variables that are actually
+allocated on the stack are considered, optimized away variables or variables
+allocated in registers don't count.
@item -fstack-protector-explicit
@opindex fstack-protector-explicit