Hi, further comments? Or ok for submit?

And as suggested by Diego, I'd like to make it upstream and google branch.

Thanks,
-Han


On Thu, Dec 8, 2011 at 4:55 PM, Han Shen(沈涵) <shen...@google.com> wrote:
> Hi, Jakub, thanks! Fixed!
>
> Hi, Andrew, it's good suggestion. Done. Also modified foo10.
>
> A small c++ test case was added also.
>
> Patches (also on http://codereview.appspot.com/5461043)
> ============================================
> diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
> index 8684721..0a7a9f7 100644
> --- a/gcc/cfgexpand.c
> +++ b/gcc/cfgexpand.c
> @@ -1507,15 +1507,38 @@ estimated_stack_frame_size (struct cgraph_node *node)
>   return size;
>  }
>
> +/* Helper routine to check if a record or union contains an array field. */
> +
> +static int
> +record_or_union_type_has_array (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))
> +           return record_or_union_type_has_array (field_type);
> +         if (TREE_CODE (field_type) == ARRAY_TYPE)
> +           return 1;
> +       }
> +    }
> +  return 0;
> +}
> +
>  /* Expand all variables used in the function.  */
>
>  static void
>  expand_used_vars (void)
>  {
>   tree var, outer_block = DECL_INITIAL (current_function_decl);
> +  referenced_var_iterator rvi;
>   VEC(tree,heap) *maybe_local_decls = NULL;
>   unsigned i;
>   unsigned len;
> +  int gen_stack_protect_signal = 0;
>
>   /* Compute the phase of the stack frame for this function.  */
>   {
> @@ -1548,6 +1571,28 @@ expand_used_vars (void)
>        }
>     }
>
> +  FOR_EACH_REFERENCED_VAR (cfun, var, rvi)
> +    if (!is_global_var (var))
> +      {
> +       tree var_type = TREE_TYPE (var);
> +       /* Examine local variables that have been address taken. */
> +       if (TREE_ADDRESSABLE (var))
> +         {
> +           ++gen_stack_protect_signal;
> +           break;
> +         }
> +       /* Examine local referenced variables that contain an array or are
> +          arrays. */
> +       if (TREE_CODE (var) == VAR_DECL
> +           && (TREE_CODE (var_type) == ARRAY_TYPE
> +               || (RECORD_OR_UNION_TYPE_P (var_type)
> +                   && record_or_union_type_has_array (var_type))))
> +         {
> +           ++gen_stack_protect_signal;
> +           break;
> +         }
> +      }
> +
>   /* At this point all variables on the local_decls with TREE_USED
>      set are not associated with any block scope.  Lay them out.  */
>
> @@ -1638,12 +1683,17 @@ expand_used_vars (void)
>        dump_stack_var_partition ();
>     }
>
> -  /* There are several conditions under which we should create a
> -     stack guard: protect-all, alloca used, protected decls present.  */
> +  /* There are several conditions under which we should create a stack guard:
> +     protect-all, alloca used, protected decls present or a positive
> +     gen_stack_protect_signal. */
>   if (flag_stack_protect == 2
> -      || (flag_stack_protect
> +      || (flag_stack_protect == 1
>          && (cfun->calls_alloca || has_protected_decls)))
>     create_stack_guard ();
> +  else if (flag_stack_protect == 3
> +          && (gen_stack_protect_signal
> +              || cfun->calls_alloca || has_protected_decls))
> +    create_stack_guard ();
>
>   /* Assign rtl to each variable based on these partitions.  */
>   if (stack_vars_num > 0)
> diff --git a/gcc/common.opt b/gcc/common.opt
> index 55d3f2d..1ad9717 100644
> --- a/gcc/common.opt
> +++ b/gcc/common.opt
> @@ -1848,6 +1848,10 @@ fstack-protector-all
>  Common Report RejectNegative Var(flag_stack_protect, 2)
>  Use a stack protection method for every function
>
> +fstack-protector-strong
> +Common Report RejectNegative Var(flag_stack_protect, 3)
> +Use a smart stack protection method for certain functions
> +
>  fstack-usage
>  Common RejectNegative Var(flag_stack_usage)
>  Output stack usage information on a per-function basis
> diff --git a/gcc/testsuite/g++.dg/fstack-protector-strong.C
> b/gcc/testsuite/g++.dg/fstack-protector-strong.C
> new file mode 100644
> index 0000000..a4f0f81
> --- /dev/null
> +++ b/gcc/testsuite/g++.dg/fstack-protector-strong.C
> @@ -0,0 +1,35 @@
> +/* Test that stack protection is done on chosen functions. */
> +
> +/* { dg-do compile { target i?86-*-* x86_64-*-* } } */
> +/* { dg-options "-O2 -fstack-protector-strong" } */
> +
> +class A
> +{
> +public:
> +  A() {}
> +  ~A() {}
> +  void method();
> +  int state;
> +};
> +
> +/* Frame address exposed to A::method via "this". */
> +int
> +foo1 ()
> +{
> +  A a;
> +  a.method ();
> +  return a.state;
> +}
> +
> +/* Possible destroying foo2's stack via &a. */
> +int
> +global_func (A& a);
> +
> +/* Frame address exposed to global_func. */
> +int foo2 ()
> +{
> +  A a;
> +  return global_func (a);
> +}
> +
> +/* { dg-final { scan-assembler-times "stack_chk_fail" 2 } } */
> diff --git a/gcc/testsuite/gcc.dg/fstack-protector-strong.c
> b/gcc/testsuite/gcc.dg/fstack-protector-strong.c
> new file mode 100644
> index 0000000..5a5cf98
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/fstack-protector-strong.c
> @@ -0,0 +1,135 @@
> +/* Test that stack protection is done on chosen functions. */
> +
> +/* { dg-do compile { target i?86-*-* x86_64-*-* } } */
> +/* { dg-options "-O2 -fstack-protector-strong" } */
> +
> +#include<string.h>
> +#include<stdlib.h>
> +
> +extern int g0;
> +extern int* pg0;
> +int
> +goo (int *);
> +int
> +hoo (int);
> +
> +/* Function frame address escaped function call. */
> +int
> +foo1 ()
> +{
> +  int i;
> +  return goo (&i);
> +}
> +
> +struct ArrayStruct
> +{
> +  int a;
> +  int array[10];
> +};
> +
> +struct AA
> +{
> +  int b;
> +  struct ArrayStruct as;
> +};
> +
> +/* Function frame contains array. */
> +int
> +foo2 ()
> +{
> +  struct AA aa;
> +  int i;
> +  for (i = 0; i < 10; ++i)
> +    {
> +      aa.as.array[i] = i * (i-1) + i / 2;
> +    }
> +  return aa.as.array[5];
> +}
> +
> +/* Address computation based on a function frame address. */
> +int
> +foo3 ()
> +{
> +  int a;
> +  int *p;
> +  p = &a + 5;
> +  return goo (p);
> +}
> +
> +/* Address cast based on a function frame address. */
> +int
> +foo4 ()
> +{
> +  int a;
> +  return goo (g0 << 2 ? (int *)(3 * (long)(void *)(&a)) : 0);
> +}
> +
> +/* Address cast based on a local array. */
> +int
> +foo5 ()
> +{
> +  short array[10];
> +  return goo ((int *)(array + 5));
> +}
> +
> +struct BB
> +{
> +  int one;
> +  int two;
> +  int three;
> +};
> +
> +/* Address computaton based on a function frame address.*/
> +int
> +foo6 ()
> +{
> +  struct BB bb;
> +  return goo (&bb.one + sizeof(int));
> +}
> +
> +/* Function frame address escaped via global variable. */
> +int
> +foo7 ()
> +{
> +  int a;
> +  pg0 = &a;
> +  goo (pg0);
> +  return *pg0;
> +}
> +
> +/* Check that this covers -fstack-protector. */
> +int
> +foo8 ()
> +{
> +  char base[100];
> +  memcpy ((void *)base, (const void *)pg0, 105);
> +  return (int)(base[32]);
> +}
> +
> +/* Check that this covers -fstack-protector. */
> +int
> +foo9 ()
> +{
> +  char* p = alloca (100);
> +  return goo ((int *)(p + 50));
> +}
> +
> +int
> +global2 (struct BB* pbb);
> +
> +/* Address taken on struct. */
> +int
> +foo10 ()
> +{
> +  struct BB bb;
> +  int i;
> +  bb.one = global2 (&bb);
> +  for (i = 0; i < 10; ++i)
> +    {
> +      bb.two = bb.one + bb.two;
> +      bb.three = bb.one + bb.two + bb.three;
> +    }
> +  return bb.three;
> +}
> +
> +/* { dg-final { scan-assembler-times "stack_chk_fail" 10 } } */
> ========================
>
> -Han
>
> On Thu, Dec 8, 2011 at 2:32 PM, Andrew Pinski <pins...@gmail.com> wrote:
>> On Thu, Dec 8, 2011 at 2:02 PM, Han Shen(沈涵) <shen...@google.com> wrote:
>>> +/* Address taken on struct. */
>>> +int foo10()
>>> +{
>>> +  struct BB bb;
>>> +  int i;
>>> +  memset(&bb, 5, sizeof bb);
>>> +  for (i = 0; i < 10; ++i)
>>> +    {
>>> +      bb.one = i;
>>> +      bb.two = bb.one + bb.two;
>>> +      bb.three = bb.one + bb.two + bb.three;
>>> +    }
>>> +  return bb.three;
>>> +}
>>
>> The above testcase could be optimized such that it does not need bb
>> has its address taken.
>>
>> Thanks,
>> Andrew Pinski

Reply via email to