Another gentle ping?
-Han

On Mon, Jan 9, 2012 at 2:18 PM, Han Shen(沈涵) <shen...@google.com> wrote:
> Hi, all, it's been a long time, I've slightly modified my code -
> TREE_ADDRESSABLE is only applied when TREE_CODE is VAR_DECL, and it's
> combined with test for arrays/struct-union-contain-array, which makes
> the code a little bit cleaner.
>
> Comments, approvals? Thanks!
>
> ===== Patch starts ======
> diff --git a/gcc/cfgexpand.c b/gcc/cfgexpand.c
> index 2b2e464..eb48607 100644
> --- a/gcc/cfgexpand.c
> +++ b/gcc/cfgexpand.c
> @@ -1509,15 +1509,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.  */
>   {
> @@ -1550,6 +1573,23 @@ expand_used_vars (void)
>        }
>     }
>
> +  FOR_EACH_REFERENCED_VAR (cfun, var, rvi)
> +    if (!is_global_var (var))
> +      {
> +       tree var_type = TREE_TYPE (var);
> +       /* Examine local referenced variables that have their addresses taken,
> +          contain an array or are arrays. */
> +       if (TREE_CODE (var) == VAR_DECL
> +           && (TREE_CODE (var_type) == ARRAY_TYPE
> +               || TREE_ADDRESSABLE (var)
> +               || (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.  */
>
> @@ -1640,12 +1680,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 6cfe17a..0680057 100644
> --- a/gcc/common.opt
> +++ b/gcc/common.opt
> @@ -1836,6 +1836,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 } } */
>
>
> On Tue, Dec 13, 2011 at 9:23 AM, Han Shen(沈涵) <shen...@google.com> wrote:
>> 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
>
> --
> Han Shen |  Software Engineer |  shen...@google.com |  +1-xxx-xxx-xxxx

Reply via email to