diff mbox

Pointer Bounds Checker and trailing arrays (PR68270)

Message ID CACysShjhUYHD_+d0twg=9nZCAXrUyBZ=az++PFw9DjS+SkG2+w@mail.gmail.com
State New
Headers show

Commit Message

Alexander Ivchenko Dec. 20, 2016, 2:44 p.m. UTC
2016-11-26 0:28 GMT+03:00 Ilya Enkovich <enkovich.gnu@gmail.com>:
> 2016-11-25 15:47 GMT+03:00 Alexander Ivchenko <aivchenk@gmail.com>:
>> Hi,
>>
>> The patch below addresses PR68270. could you please take a look?
>>
>> 2016-11-25  Alexander Ivchenko  <aivchenk@gmail.com>
>>
>>        * c-family/c.opt (flag_chkp_flexible_struct_trailing_arrays):
>>        Add new option.
>>        * tree-chkp.c (chkp_parse_array_and_component_ref): Forbid
>>        narrowing when chkp_parse_array_and_component_ref is used and
>>        the ARRAY_REF points to an array in the end of the struct.
>>
>>
>>
>> diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
>> index 7d8a726..e45d6a2 100644
>> --- a/gcc/c-family/c.opt
>> +++ b/gcc/c-family/c.opt
>> @@ -1166,6 +1166,11 @@ C ObjC C++ ObjC++ LTO RejectNegative Report
>> Var(flag_chkp_narrow_to_innermost_ar
>>  Forces Pointer Bounds Checker to use bounds of the innermost arrays in case of
>>  nested static arryas access.  By default outermost array is used.
>>
>> +fchkp-flexible-struct-trailing-arrays
>> +C ObjC C++ ObjC++ LTO RejectNegative Report
>> Var(flag_chkp_flexible_struct_trailing_arrays)
>> +Allow Pointer Bounds Checker to treat all trailing arrays in structures as
>> +possibly flexible.
>
> Words 'allow' and 'possibly' are confusing here. This option is about to force
> checker to do something, not to give him a choice.

Fixed

> New option has to be documented in invoke.texi. It would also be nice to reflect
> changes on GCC MPX wiki page.

Done
> We have an attribute to change compiler behavior when this option is not set.
> But we have no way to make exceptions when this option is used. Should we
> add one?
Something like "bnd_fixed_size" ? Could work. Although the customer
request did not mention the need for that.
Can I add it in a separate patch?


>> +
>>  fchkp-optimize
>>  C ObjC C++ ObjC++ LTO Report Var(flag_chkp_optimize) Init(-1)
>>  Allow Pointer Bounds Checker optimizations.  By default allowed
>> diff --git a/gcc/tree-chkp.c b/gcc/tree-chkp.c
>> index 2769682..40f99c3 100644
>> --- a/gcc/tree-chkp.c
>> +++ b/gcc/tree-chkp.c
>> @@ -3425,7 +3425,9 @@ chkp_parse_array_and_component_ref (tree node, tree *ptr,
>>    if (flag_chkp_narrow_bounds
>>        && !flag_chkp_narrow_to_innermost_arrray
>>        && (!last_comp
>> -  || chkp_may_narrow_to_field (TREE_OPERAND (last_comp, 1))))
>> +  || (chkp_may_narrow_to_field (TREE_OPERAND (last_comp, 1))
>> +      && !(flag_chkp_flexible_struct_trailing_arrays
>> +   && array_at_struct_end_p (var)))))
>
> This is incorrect place for fix. Consider code
>
> struct S {
>   int a;
>   int b[10];
> };
>
> struct S s;
> int *p = s.b;
>
> Here you need to compute bounds for p and you want your option to take effect
> but in this case you won't event reach your new check because there is no
> ARRAY_REF. And even if we change it to
>
> int *p = s.b[5];
>
> then it still would be narrowed because s.b would still be written
> into 'comp_to_narrow'
> variable. Correct place for fix is in chkp_may_narrow_to_field.

Done

> Also you should consider fchkp-narrow-to-innermost-arrray option. Should it
> be more powerfull or not? I think fchkp-narrow-to-innermost-arrray shouldn't
> narrow to variable sized fields. BTW looks like right now bnd_variable_size
> attribute is ignored by fchkp-narrow-to-innermost-arrray. This is another
> problem and may be fixed in another patch though.
The way code works in chkp_parse_array_and_component_ref seems to be
exactly like you say:  fchkp-narrow-to-innermost-arrray won't narrow
to variable sized fields. I will create a separate bug for
bnd_variable_size+ fchkp-narrow-to-innermost-arrray.

> Also patch lacks tests for various situations (with option and without, with
> ARRAY_REF and without). In case of new attribute and fix for
> fchkp-narrow-to-innermost-arrray behavior additional tests are required.
I added three tests for flag_chkp_flexible_struct_trailing_arrays



The patch is below:

Comments

Ilya Enkovich Dec. 21, 2016, 6 p.m. UTC | #1
2016-12-20 17:44 GMT+03:00 Alexander Ivchenko <aivchenk@gmail.com>:
> 2016-11-26 0:28 GMT+03:00 Ilya Enkovich <enkovich.gnu@gmail.com>:
>> 2016-11-25 15:47 GMT+03:00 Alexander Ivchenko <aivchenk@gmail.com>:
>>> Hi,
>>>
>>> The patch below addresses PR68270. could you please take a look?
>>>
>>> 2016-11-25  Alexander Ivchenko  <aivchenk@gmail.com>
>>>
>>>        * c-family/c.opt (flag_chkp_flexible_struct_trailing_arrays):
>>>        Add new option.
>>>        * tree-chkp.c (chkp_parse_array_and_component_ref): Forbid
>>>        narrowing when chkp_parse_array_and_component_ref is used and
>>>        the ARRAY_REF points to an array in the end of the struct.
>>>
>>>
>>>
>>> diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
>>> index 7d8a726..e45d6a2 100644
>>> --- a/gcc/c-family/c.opt
>>> +++ b/gcc/c-family/c.opt
>>> @@ -1166,6 +1166,11 @@ C ObjC C++ ObjC++ LTO RejectNegative Report
>>> Var(flag_chkp_narrow_to_innermost_ar
>>>  Forces Pointer Bounds Checker to use bounds of the innermost arrays in case of
>>>  nested static arryas access.  By default outermost array is used.
>>>
>>> +fchkp-flexible-struct-trailing-arrays
>>> +C ObjC C++ ObjC++ LTO RejectNegative Report
>>> Var(flag_chkp_flexible_struct_trailing_arrays)
>>> +Allow Pointer Bounds Checker to treat all trailing arrays in structures as
>>> +possibly flexible.
>>
>> Words 'allow' and 'possibly' are confusing here. This option is about to force
>> checker to do something, not to give him a choice.
>
> Fixed
>
>> New option has to be documented in invoke.texi. It would also be nice to reflect
>> changes on GCC MPX wiki page.
>
> Done
>> We have an attribute to change compiler behavior when this option is not set.
>> But we have no way to make exceptions when this option is used. Should we
>> add one?
> Something like "bnd_fixed_size" ? Could work. Although the customer
> request did not mention the need for that.
> Can I add it in a separate patch?
>

Yes.

>
>>> +
>>>  fchkp-optimize
>>>  C ObjC C++ ObjC++ LTO Report Var(flag_chkp_optimize) Init(-1)
>>>  Allow Pointer Bounds Checker optimizations.  By default allowed
>>> diff --git a/gcc/tree-chkp.c b/gcc/tree-chkp.c
>>> index 2769682..40f99c3 100644
>>> --- a/gcc/tree-chkp.c
>>> +++ b/gcc/tree-chkp.c
>>> @@ -3425,7 +3425,9 @@ chkp_parse_array_and_component_ref (tree node, tree *ptr,
>>>    if (flag_chkp_narrow_bounds
>>>        && !flag_chkp_narrow_to_innermost_arrray
>>>        && (!last_comp
>>> -  || chkp_may_narrow_to_field (TREE_OPERAND (last_comp, 1))))
>>> +  || (chkp_may_narrow_to_field (TREE_OPERAND (last_comp, 1))
>>> +      && !(flag_chkp_flexible_struct_trailing_arrays
>>> +   && array_at_struct_end_p (var)))))
>>
>> This is incorrect place for fix. Consider code
>>
>> struct S {
>>   int a;
>>   int b[10];
>> };
>>
>> struct S s;
>> int *p = s.b;
>>
>> Here you need to compute bounds for p and you want your option to take effect
>> but in this case you won't event reach your new check because there is no
>> ARRAY_REF. And even if we change it to
>>
>> int *p = s.b[5];
>>
>> then it still would be narrowed because s.b would still be written
>> into 'comp_to_narrow'
>> variable. Correct place for fix is in chkp_may_narrow_to_field.
>
> Done
>
>> Also you should consider fchkp-narrow-to-innermost-arrray option. Should it
>> be more powerfull or not? I think fchkp-narrow-to-innermost-arrray shouldn't
>> narrow to variable sized fields. BTW looks like right now bnd_variable_size
>> attribute is ignored by fchkp-narrow-to-innermost-arrray. This is another
>> problem and may be fixed in another patch though.
> The way code works in chkp_parse_array_and_component_ref seems to be
> exactly like you say:  fchkp-narrow-to-innermost-arrray won't narrow
> to variable sized fields. I will create a separate bug for
> bnd_variable_size+ fchkp-narrow-to-innermost-arrray.
>
>> Also patch lacks tests for various situations (with option and without, with
>> ARRAY_REF and without). In case of new attribute and fix for
>> fchkp-narrow-to-innermost-arrray behavior additional tests are required.
> I added three tests for flag_chkp_flexible_struct_trailing_arrays
>
>
>
> The patch is below:
>
> diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
> index 2d47d54..21ad6aa 100644
> --- a/gcc/c-family/c.opt
> +++ b/gcc/c-family/c.opt
> @@ -1188,7 +1188,13 @@ narrowing is on, field bounds are used.
> Otherwise full object bounds are used.
>  fchkp-narrow-to-innermost-array
>  C ObjC C++ ObjC++ LTO RejectNegative Report
> Var(flag_chkp_narrow_to_innermost_arrray)
>  Forces Pointer Bounds Checker to use bounds of the innermost arrays in case of
> -nested static arryas access.  By default outermost array is used.
> +nested static arrays access.  By default outermost array is used.
> +
> +fchkp-flexible-struct-trailing-arrays
> +C ObjC C++ ObjC++ LTO RejectNegative Report
> Var(flag_chkp_flexible_struct_trailing_arrays)
> +Forces Pointer Bounds Checker to treat all trailing arrays in structures as
> +possibly flexible.  By default only arrays fields with zero length or that are
> +marked with attribute bnd_variable_size are treated as flexible.
>
>  fchkp-optimize
>  C ObjC C++ ObjC++ LTO Report Var(flag_chkp_optimize) Init(-1)
> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> index 034ae98..2372c22a 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -10886,6 +10886,13 @@ Forces Pointer Bounds Checker to use narrowed
> bounds for the address of the
>  first field in the structure.  By default a pointer to the first field has
>  the same bounds as a pointer to the whole structure.
>
> +@item -fchkp-flexible-struct-trailing-arrays
> +@opindex fchkp-flexible-struct-trailing-arrays
> +@opindex fno-chkp-flexible-struct-trailing-arrays
> +Forces Pointer Bounds Checker to treat all trailing arrays in structures as
> +possibly flexible.  By default only arrays fields with zero length or that are
> +marked with attribute bnd_variable_size are treated as flexible.
> +
>  @item -fchkp-narrow-to-innermost-array
>  @opindex fchkp-narrow-to-innermost-array
>  @opindex fno-chkp-narrow-to-innermost-array
> diff --git a/gcc/testsuite/gcc.target/i386/mpx/vla-trailing-1-lbv.c
> b/gcc/testsuite/gcc.target/i386/mpx/vla-trailing-1-lbv.c
> new file mode 100644
> index 0000000..9739920
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/mpx/vla-trailing-1-lbv.c
> @@ -0,0 +1,29 @@
> +/* { dg-do run } */
> +/* { dg-shouldfail "bounds violation" } */
> +/* { dg-options "-fcheck-pointer-bounds -mmpx
> -fchkp-flexible-struct-trailing-arrays" } */
> +
> +
> +#define SHOULDFAIL
> +
> +#include "mpx-check.h"
> +
> +struct S
> +{
> +  int a;
> +  int p[10];
> +};
> +
> +int rd (int *p, int i)
> +{
> +  int res = p[i];
> +  printf ("%d\n", res);
> +  return res;
> +}
> +
> +int mpx_test (int argc, const char **argv)
> +{
> +  struct S *s = (struct S *)alloca (sizeof(struct S) + sizeof (int)*100);
> +  rd (s->p, -2);
> +
> +  return 0;
> +}
> diff --git a/gcc/testsuite/gcc.target/i386/mpx/vla-trailing-1-nov.c
> b/gcc/testsuite/gcc.target/i386/mpx/vla-trailing-1-nov.c
> new file mode 100644
> index 0000000..f5c8f95
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/mpx/vla-trailing-1-nov.c
> @@ -0,0 +1,29 @@
> +/* { dg-do run } */
> +/* { dg-options "-fcheck-pointer-bounds -mmpx
> -fchkp-flexible-struct-trailing-arrays" } */
> +
> +
> +#include "mpx-check.h"
> +
> +struct S
> +{
> +  int a;
> +  int p[10];
> +};
> +
> +int rd (int *p, int i)
> +{
> +  int res = p[i];
> +  printf ("%d\n", res);
> +  return res;
> +}
> +
> +int mpx_test (int argc, const char **argv)
> +{
> +  struct S *s = (struct S *)alloca (sizeof(struct S) + sizeof (int)*100);
> +  rd (s->p, 0);
> +  rd (s->p, 99);
> +  s->p[0];
> +  s->p[99];
> +
> +  return 0;
> +}
> diff --git a/gcc/testsuite/gcc.target/i386/mpx/vla-trailing-1-ubv.c
> b/gcc/testsuite/gcc.target/i386/mpx/vla-trailing-1-ubv.c
> new file mode 100644
> index 0000000..8385a5a
> --- /dev/null
> +++ b/gcc/testsuite/gcc.target/i386/mpx/vla-trailing-1-ubv.c
> @@ -0,0 +1,29 @@
> +/* { dg-do run } */
> +/* { dg-shouldfail "bounds violation" } */
> +/* { dg-options "-fcheck-pointer-bounds -mmpx
> -fchkp-flexible-struct-trailing-arrays" } */
> +
> +
> +#define SHOULDFAIL
> +
> +#include "mpx-check.h"
> +
> +struct S
> +{
> +  int a;
> +  int p[10];
> +};
> +
> +int rd (int *p, int i)
> +{
> +  int res = p[i];
> +  printf ("%d\n", res);
> +  return res;
> +}
> +
> +int mpx_test (int argc, const char **argv)
> +{
> +  struct S *s = (struct S *)alloca (sizeof(struct S) + sizeof (int)*100);
> +  rd (s->p, 110);
> +
> +  return 0;
> +}
> diff --git a/gcc/tree-chkp.c b/gcc/tree-chkp.c
> index 2769682..6c5e541 100644
> --- a/gcc/tree-chkp.c
> +++ b/gcc/tree-chkp.c
> @@ -3272,6 +3272,8 @@ chkp_may_narrow_to_field (tree field)
>  {
>    return DECL_SIZE (field) && TREE_CODE (DECL_SIZE (field)) == INTEGER_CST
>      && tree_to_uhwi (DECL_SIZE (field)) != 0
> +    && (!flag_chkp_flexible_struct_trailing_arrays
> + || DECL_CHAIN (field))

What if it's not array?

Thanks,
Ilya

>      && (!DECL_FIELD_OFFSET (field)
>   || TREE_CODE (DECL_FIELD_OFFSET (field)) == INTEGER_CST)
>      && (!DECL_FIELD_BIT_OFFSET (field)
diff mbox

Patch

diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 2d47d54..21ad6aa 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -1188,7 +1188,13 @@  narrowing is on, field bounds are used.
Otherwise full object bounds are used.
 fchkp-narrow-to-innermost-array
 C ObjC C++ ObjC++ LTO RejectNegative Report
Var(flag_chkp_narrow_to_innermost_arrray)
 Forces Pointer Bounds Checker to use bounds of the innermost arrays in case of
-nested static arryas access.  By default outermost array is used.
+nested static arrays access.  By default outermost array is used.
+
+fchkp-flexible-struct-trailing-arrays
+C ObjC C++ ObjC++ LTO RejectNegative Report
Var(flag_chkp_flexible_struct_trailing_arrays)
+Forces Pointer Bounds Checker to treat all trailing arrays in structures as
+possibly flexible.  By default only arrays fields with zero length or that are
+marked with attribute bnd_variable_size are treated as flexible.

 fchkp-optimize
 C ObjC C++ ObjC++ LTO Report Var(flag_chkp_optimize) Init(-1)
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 034ae98..2372c22a 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -10886,6 +10886,13 @@  Forces Pointer Bounds Checker to use narrowed
bounds for the address of the
 first field in the structure.  By default a pointer to the first field has
 the same bounds as a pointer to the whole structure.

+@item -fchkp-flexible-struct-trailing-arrays
+@opindex fchkp-flexible-struct-trailing-arrays
+@opindex fno-chkp-flexible-struct-trailing-arrays
+Forces Pointer Bounds Checker to treat all trailing arrays in structures as
+possibly flexible.  By default only arrays fields with zero length or that are
+marked with attribute bnd_variable_size are treated as flexible.
+
 @item -fchkp-narrow-to-innermost-array
 @opindex fchkp-narrow-to-innermost-array
 @opindex fno-chkp-narrow-to-innermost-array
diff --git a/gcc/testsuite/gcc.target/i386/mpx/vla-trailing-1-lbv.c
b/gcc/testsuite/gcc.target/i386/mpx/vla-trailing-1-lbv.c
new file mode 100644
index 0000000..9739920
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/mpx/vla-trailing-1-lbv.c
@@ -0,0 +1,29 @@ 
+/* { dg-do run } */
+/* { dg-shouldfail "bounds violation" } */
+/* { dg-options "-fcheck-pointer-bounds -mmpx
-fchkp-flexible-struct-trailing-arrays" } */
+
+
+#define SHOULDFAIL
+
+#include "mpx-check.h"
+
+struct S
+{
+  int a;
+  int p[10];
+};
+
+int rd (int *p, int i)
+{
+  int res = p[i];
+  printf ("%d\n", res);
+  return res;
+}
+
+int mpx_test (int argc, const char **argv)
+{
+  struct S *s = (struct S *)alloca (sizeof(struct S) + sizeof (int)*100);
+  rd (s->p, -2);
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/mpx/vla-trailing-1-nov.c
b/gcc/testsuite/gcc.target/i386/mpx/vla-trailing-1-nov.c
new file mode 100644
index 0000000..f5c8f95
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/mpx/vla-trailing-1-nov.c
@@ -0,0 +1,29 @@ 
+/* { dg-do run } */
+/* { dg-options "-fcheck-pointer-bounds -mmpx
-fchkp-flexible-struct-trailing-arrays" } */
+
+
+#include "mpx-check.h"
+
+struct S
+{
+  int a;
+  int p[10];
+};
+
+int rd (int *p, int i)
+{
+  int res = p[i];
+  printf ("%d\n", res);
+  return res;
+}
+
+int mpx_test (int argc, const char **argv)
+{
+  struct S *s = (struct S *)alloca (sizeof(struct S) + sizeof (int)*100);
+  rd (s->p, 0);
+  rd (s->p, 99);
+  s->p[0];
+  s->p[99];
+
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.target/i386/mpx/vla-trailing-1-ubv.c
b/gcc/testsuite/gcc.target/i386/mpx/vla-trailing-1-ubv.c
new file mode 100644
index 0000000..8385a5a
--- /dev/null
+++ b/gcc/testsuite/gcc.target/i386/mpx/vla-trailing-1-ubv.c
@@ -0,0 +1,29 @@ 
+/* { dg-do run } */
+/* { dg-shouldfail "bounds violation" } */
+/* { dg-options "-fcheck-pointer-bounds -mmpx
-fchkp-flexible-struct-trailing-arrays" } */
+
+
+#define SHOULDFAIL
+
+#include "mpx-check.h"
+
+struct S
+{
+  int a;
+  int p[10];
+};
+
+int rd (int *p, int i)
+{
+  int res = p[i];
+  printf ("%d\n", res);
+  return res;
+}
+
+int mpx_test (int argc, const char **argv)
+{
+  struct S *s = (struct S *)alloca (sizeof(struct S) + sizeof (int)*100);
+  rd (s->p, 110);
+
+  return 0;
+}
diff --git a/gcc/tree-chkp.c b/gcc/tree-chkp.c
index 2769682..6c5e541 100644
--- a/gcc/tree-chkp.c
+++ b/gcc/tree-chkp.c
@@ -3272,6 +3272,8 @@  chkp_may_narrow_to_field (tree field)
 {
   return DECL_SIZE (field) && TREE_CODE (DECL_SIZE (field)) == INTEGER_CST
     && tree_to_uhwi (DECL_SIZE (field)) != 0
+    && (!flag_chkp_flexible_struct_trailing_arrays
+ || DECL_CHAIN (field))
     && (!DECL_FIELD_OFFSET (field)
  || TREE_CODE (DECL_FIELD_OFFSET (field)) == INTEGER_CST)
     && (!DECL_FIELD_BIT_OFFSET (field)