Re: [V2][PATCH 0/3] New attribute "counted_by" to annotate bounds for C99 FAM(PR108896)

2023-08-10 Thread Martin Uecker
Am Donnerstag, dem 10.08.2023 um 16:42 +0200 schrieb Jakub Jelinek:
> On Thu, Aug 10, 2023 at 04:38:21PM +0200, Martin Uecker wrote:
> > Am Donnerstag, dem 10.08.2023 um 13:59 + schrieb Qing Zhao:
> > > 
> > > > On Aug 10, 2023, at 2:58 AM, Martin Uecker  wrote:
> > > > 
> > > > Am Mittwoch, dem 09.08.2023 um 20:10 + schrieb Qing Zhao:
> > > > > 
> > > > > > On Aug 9, 2023, at 12:21 PM, Michael Matz  wrote:
> > > > 
> > 
> > > > I am not sure for the reason given above. The following
> > > > code would not work:
> > > > 
> > > > struct foo_flex { int a; short b; char t[]; } x;
> > > > x.a = 1;
> > > > struct foo_flex *p = malloc(sizeof(x) + x.a);
> > > > if (!p) abort();
> > > > memcpy(p, &x, sizeof(x)); // initialize struct
> > > > 
> > > Okay. 
> > > Then, the user still should use the sizeof(struct foo_flex) + N * 
> > > sizeof(foo->t) for the allocation, even though this might allocate more 
> > > bytes than necessary. (But this is safe)
> > > 
> > > Let me know if I still miss anything.
> > 
> > The question is not only what the user should use to
> > allocate, but also what BDOS should return.  In my
> > example the user uses the sizeof() + N * sizeof
> > formula and the memcpy is safe, but it would be flagged
> > as a buffer overrun if BDOS uses the offsetof formula.
> 
> BDOS/BOS (at least the 0 level) should return what is actually
> allocated for the var, what size was passed to malloc and if it
> is a var with flex array member with initialization what is actually the
> size on the stack or in .data/.rodata etc.

Agreed.

But what about a struct with FAM with the new "counted_by" attribute
if the original allocation is not visible?

Martin

> And for 1 level the same unless it is just access to some element, then
> it should be capped by the size of that element.
> 






Re: [V2][PATCH 0/3] New attribute "counted_by" to annotate bounds for C99 FAM(PR108896)

2023-08-10 Thread Martin Uecker
Am Donnerstag, dem 10.08.2023 um 13:59 + schrieb Qing Zhao:
> 
> > On Aug 10, 2023, at 2:58 AM, Martin Uecker  wrote:
> > 
> > Am Mittwoch, dem 09.08.2023 um 20:10 + schrieb Qing Zhao:
> > > 
> > > > On Aug 9, 2023, at 12:21 PM, Michael Matz  wrote:
> > 

> > I am not sure for the reason given above. The following
> > code would not work:
> > 
> > struct foo_flex { int a; short b; char t[]; } x;
> > x.a = 1;
> > struct foo_flex *p = malloc(sizeof(x) + x.a);
> > if (!p) abort();
> > memcpy(p, &x, sizeof(x)); // initialize struct
> > 
> Okay. 
> Then, the user still should use the sizeof(struct foo_flex) + N * 
> sizeof(foo->t) for the allocation, even though this might allocate more bytes 
> than necessary. (But this is safe)
> 
> Let me know if I still miss anything.

The question is not only what the user should use to
allocate, but also what BDOS should return.  In my
example the user uses the sizeof() + N * sizeof
formula and the memcpy is safe, but it would be flagged
as a buffer overrun if BDOS uses the offsetof formula.

Martin




c: Support for -Wuseless-cast [RR84510]

2023-08-10 Thread Martin Uecker via Gcc-patches



This patch adds the missing support for -Wuseless-cast
to the C FE as requested by some users. It found about 
50 useless casts in one of my projects without false 
positives.

(I also implemented a detection for various
unneeded pointer casts in convert_for_assignment
such as unneeded casts from / to void or casts
followed by an implicit conversion to the original
type, but I did not figure out how to reliably 
identify casts there... But this would be a potential
future enhancement.)


Regression tested on bootstrapped on x86_64-pc-linux-gnu.



c: Support for -Wuseless-cast [RR84510]

Add support for Wuseless-cast C (and ObjC).

PR c/84510

gcc/c/:
* c-typeck.cc (build_c_cast): Add warning.

gcc/doc/:
* invoke.texi: Update.

gcc/testsuite/:
* Wuseless-cast.c: New test.

diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 0ed87fcc7be..c7b567ba7ab 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -1490,7 +1490,7 @@ C++ ObjC++ Var(warn_zero_as_null_pointer_constant) Warning
 Warn when a literal '0' is used as null pointer.
 
 Wuseless-cast
-C++ ObjC++ Var(warn_useless_cast) Warning
+C ObjC C++ ObjC++ Var(warn_useless_cast) Warning
 Warn about useless casts.
 
 Wsubobject-linkage
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 7cf411155c6..6f2fff51683 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -6062,9 +6062,13 @@ build_c_cast (location_t loc, tree type, tree expr)
 
   if (type == TYPE_MAIN_VARIANT (TREE_TYPE (value)))
 {
-  if (RECORD_OR_UNION_TYPE_P (type))
-   pedwarn (loc, OPT_Wpedantic,
-"ISO C forbids casting nonscalar to the same type");
+  if (RECORD_OR_UNION_TYPE_P (type)
+ && pedwarn (loc, OPT_Wpedantic,
+ "ISO C forbids casting nonscalar to the same type"))
+ ;
+  else if (warn_useless_cast)
+   warning_at (loc, OPT_Wuseless_cast,
+   "useless cast to type %qT", type);
 
   /* Convert to remove any qualifiers from VALUE's type.  */
   value = convert (type, value);
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 674f956f4b8..75ca72f3190 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -4772,7 +4772,7 @@ pointers after reallocation.
 
 @opindex Wuseless-cast
 @opindex Wno-useless-cast
-@item -Wuseless-cast @r{(C++ and Objective-C++ only)}
+@item -Wuseless-cast @r{(C, Objective-C, C++ and Objective-C++ only)}
 Warn when an expression is cast to its own type.  This warning does not
 occur when a class object is converted to a non-reference type as that
 is a way to create a temporary:
diff --git a/gcc/testsuite/gcc.dg/Wuseless-cast.c 
b/gcc/testsuite/gcc.dg/Wuseless-cast.c
new file mode 100644
index 000..86e87584b87
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wuseless-cast.c
@@ -0,0 +1,26 @@
+/* { dg-do compile } */
+/* { dg-options "-Wuseless-cast" } */
+
+void foo(void)
+{  
+   // casts to the same type
+   int i = 0;
+   const int ic = 0;
+   struct foo { int x; } x = { 0 };
+   int q[3];
+   (int)ic;/* { dg-warning "useless cast" } */
+   (int)i; /* { dg-warning "useless cast" } */
+   (const int)ic;  /* { dg-warning "useless cast" } */
+   (const int)i;   /* { dg-warning "useless cast" } */
+   (struct foo)x;  /* { dg-warning "useless cast" } */
+   (int(*)[3])&q;  /* { dg-warning "useless cast" } */
+   (_Atomic(int))i;/* { dg-warning "useless cast" } */
+
+   // not the same
+   int n = 3;
+   (int(*)[n])&q;  // no warning
+   int j = (int)0UL;
+   enum X { A = 1 } xx = { A };
+   enum Y { B = 1 } yy = (enum Y)xx;
+}
+




Re: [V2][PATCH 0/3] New attribute "counted_by" to annotate bounds for C99 FAM(PR108896)

2023-08-09 Thread Martin Uecker
Am Mittwoch, dem 09.08.2023 um 20:10 + schrieb Qing Zhao:
> 
> > On Aug 9, 2023, at 12:21 PM, Michael Matz  wrote:

...
> 
> By definition, the sizeof() of a struct with FAM might not be the same as the 
> non-FAM one. 
> i.e, for the following two structures, one with FAM, the other with fixed 
> array:
> 
> struct foo_flex { int a; short b; char t[]; } x = { .t = { 1, 2, 3 } };
> struct foo_fix {int a; short b; char t[3]; } 
> 
> With current GCC:
> sizeof(foo_flex) == 8
> sizeof(foo_fix) == 12
> 
> I think that the current behavior of sizeof for structure with FAM in GCC is 
> correct. 

Yes, sadly the sizeof has to be like this as required by ISO C.

> 
> The major issue is what was pointed out by Martin in the previous email:
> 
> Whether using the following formula is correct to compute the allocation?
> 
> sizeof(struct foo_flex) + N * sizeof(foo->t);

That formula is safe for allocation, but might allocate more padding
than the minimum amount and it might allocate less storage than a
similar array with fixed array.

> As pointed out  in the wikipedia, the value computed by this formula might
>  be bigger than the actual size since “sizeof(struct foo_flex)” might include 
> paddings that are used as part of the array.
> 
> So the more accurate formula should be
> 
> offset(struct foo_flex, t[0]) + N * sizeof(foo->t);
> 
> With GCC, offset(struct foo_flex,t[0]) == 6, which is also correct. 

This formula might be considered incorrect / dangerous because
it might allocate less storage than sizeof(struct foo_flex). 


https://godbolt.org/z/8accq75f3
> 
...
> > As in: I think sizeof for both structs should return 12, and 12 bytes 
> > should be reserved for objects of such types.
> > 
> > And then the next question is what __builtin_object_size should do with 
> > these: should it return the size with or without padding at end (i.e. 
> > could/should it return 9 even if sizeof is 12).  I can see arguments for 
> > both.
> 
> Currently, GCC’s __builtin_object_size use the following formula to compute 
> the object size for
> The structure with FAM:
> 
> offset(struct foo_flex, t[0]) + N * sizeof(foo->t);
> 
> I think it’s correct. 
> 
> I think that the users might need to use this formula to compute the 
> allocation size for a structure with FAM too.

I am not sure for the reason given above. The following
code would not work:

struct foo_flex { int a; short b; char t[]; } x;
x.a = 1;
struct foo_flex *p = malloc(sizeof(x) + x.a);
if (!p) abort();
memcpy(p, &x, sizeof(x)); // initialize struct


Martin





Re: [V2][PATCH 0/3] New attribute "counted_by" to annotate bounds for C99 FAM(PR108896)

2023-08-08 Thread Martin Uecker via Gcc-patches



I am sure this has been discussed before, but seeing that you
test for a specific formula, let me point out the following:

There at least three different size expression which could
make sense. Consider

short foo { int a; short b; char t[]; }; 

Most people seem to use

sizeof(struct foo) + N * sizeof(foo->t);

which for N == 3 yields 11 bytes on x86-64 because the formula
adds the padding of the original struct. There is an example
in the  C standard that uses this formula.


But he minimum size of an object which stores N elements is

max(sizeof (struct s), offsetof(struct s, t[n]))

which is 9 bytes. 

This is what clang uses for statically allocated objects with
initialization, while GCC uses the rule above (11 bytes). But 
bdos / bos  then returns the smaller size of 9 which is a bit
confusing.


https://godbolt.org/z/K1hvaK1ns

https://github.com/llvm/llvm-project/issues/62929
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109956


Then there is also the size of a similar array where the FAM
is replaced with an array of static size:

struct foo { int a; short b; char t[3]; }; 

This would make the most sense to me, but it has 12 bytes
because the padding is according to the usual alignment
rules.


Martin



Am Montag, dem 07.08.2023 um 09:16 -0700 schrieb Kees Cook:
> On Fri, Aug 04, 2023 at 07:44:28PM +, Qing Zhao wrote:
> > This is the 2nd version of the patch, per our discussion based on the
> > review comments for the 1st version, the major changes in this version
> > are:
> 
> Thanks for the update!
> 
> > 
> > 1. change the name "element_count" to "counted_by";
> > 2. change the parameter for the attribute from a STRING to an
> > Identifier;
> > 3. Add logic and testing cases to handle anonymous structure/unions;
> > 4. Clarify documentation to permit the situation when the allocation
> > size is larger than what's specified by "counted_by", at the same time,
> > it's user's error if allocation size is smaller than what's specified by
> > "counted_by";
> > 5. Add a complete testing case for using counted_by attribute in
> > __builtin_dynamic_object_size when there is mismatch between the
> > allocation size and the value of "counted_by", the expecting behavior
> > for each case and the explanation on why in the comments. 
> 
> All the "normal" test cases I have are passing; this is wonderful! :)
> 
> I'm still seeing unexpected situations when I've intentionally set
> counted_by to be smaller than alloc_size, but I assume it's due to not
> yet having the patch you mention below.
> 
> > As discussed, I plan to add two more separate patch sets after this initial
> > patch set is approved and committed.
> > 
> > set 1. A new warning option and a new sanitizer option for the user error
> >    when the allocation size is smaller than the value of "counted_by".
> > set 2. An improvement to __builtin_dynamic_object_size  for the following
> >    case:
> > 
> > struct A
> > {
> > size_t foo;
> > int array[] __attribute__((counted_by (foo)));
> > };
> > 
> > extern struct fix * alloc_buf ();
> > 
> > int main ()
> > {
> > struct fix *p = alloc_buf ();
> > __builtin_object_size(p->array, 0) == sizeof(struct A) + p->foo * 
> > sizeof(int);
> >   /* with the current algorithm, it’s UNKNOWN */ 
> > __builtin_object_size(p->array, 2) == sizeof(struct A) + p->foo * 
> > sizeof(int);
> >   /* with the current algorithm, it’s UNKNOWN */
> > }
> 
> Should the above be bdos instead of bos?
> 
> > Bootstrapped and regression tested on both aarch64 and X86, no issue.
> 
> I've updated the Linux kernel's macros for the name change and done
> build tests with my first pass at "easy" cases for adding counted_by:
> https://git.kernel.org/pub/scm/linux/kernel/git/kees/linux.git/commit/?h=devel/counted_by&id=adc5b3cb48a049563dc673f348eab7b6beba8a9b
> 
> Everything is working as expected. :)
> 
> -Kees
> 

-- 
Univ.-Prof. Dr. rer. nat. Martin Uecker
Graz University of Technology
Institute of Biomedical Imaging





[C PATCH] Support typename as selector in _Generic

2023-08-05 Thread Martin Uecker via Gcc-patches


Clang now has an extension which accepts a typename for
_Generic.  This is simple to implement and is useful.

Do we want this?

Clang calls it a "Clang extension" in the pedantic
warning.  I changed it to "an extension"  I am not
sure what the policy is.

Do we need an extra warning option? Clang has one.

No documentation so far.

Bootstrapped and regression tested on x86_64-pc-linux-gnu.

Martin


c: Support typename as selector in _Generic

Support typenames as first argument to _Generic which is an
extension supported by Clang. It makes it easier to test
for types with qualifiers in combination with typeof.

gcc/c/:
* c-parser.cc (c_parser_generic_selection): Support typename
in _Generic selector.

gcc/testsuite/:
* gnu2x-generic.c: New test.


diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index 57a01dc2fa3..9aea2425294 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -9312,30 +9312,51 @@ c_parser_generic_selection (c_parser *parser)
   if (!parens.require_open (parser))
 return error_expr;
 
-  c_inhibit_evaluation_warnings++;
   selector_loc = c_parser_peek_token (parser)->location;
-  selector = c_parser_expr_no_commas (parser, NULL);
-  selector = default_function_array_conversion (selector_loc, selector);
-  c_inhibit_evaluation_warnings--;
 
-  if (selector.value == error_mark_node)
+  if (c_token_starts_typename (c_parser_peek_token (parser)))
 {
-  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
-  return selector;
-}
-  mark_exp_read (selector.value);
-  selector_type = TREE_TYPE (selector.value);
-  /* In ISO C terms, rvalues (including the controlling expression of
- _Generic) do not have qualified types.  */
-  if (TREE_CODE (selector_type) != ARRAY_TYPE)
-selector_type = TYPE_MAIN_VARIANT (selector_type);
-  /* In ISO C terms, _Noreturn is not part of the type of expressions
- such as &abort, but in GCC it is represented internally as a type
- qualifier.  */
-  if (FUNCTION_POINTER_TYPE_P (selector_type)
-  && TYPE_QUALS (TREE_TYPE (selector_type)) != TYPE_UNQUALIFIED)
-selector_type
-  = build_pointer_type (TYPE_MAIN_VARIANT (TREE_TYPE (selector_type)));
+  /* Language extension introduced by Clang.  */
+  pedwarn (selector_loc, OPT_Wpedantic, "passing a type argument as "
+  "first argument to %<_Generic%> is an extension");
+  struct c_type_name *type_name;
+  c_inhibit_evaluation_warnings++;
+  type_name = c_parser_type_name (parser);
+  c_inhibit_evaluation_warnings--;
+  if (NULL == type_name)
+   {
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+ return error_expr;
+   }
+  /* Qualifiers are preserved.  */
+  selector_type = groktypename (type_name, NULL, NULL);
+}
+  else
+{
+  c_inhibit_evaluation_warnings++;
+  selector = c_parser_expr_no_commas (parser, NULL);
+  selector = default_function_array_conversion (selector_loc, selector);
+  c_inhibit_evaluation_warnings--;
+
+  if (selector.value == error_mark_node)
+   {
+ c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
+ return selector;
+   }
+  mark_exp_read (selector.value);
+  selector_type = TREE_TYPE (selector.value);
+  /* In ISO C terms, rvalues (including the controlling expression of
+_Generic) do not have qualified types.  */
+  if (TREE_CODE (selector_type) != ARRAY_TYPE)
+   selector_type = TYPE_MAIN_VARIANT (selector_type);
+  /* In ISO C terms, _Noreturn is not part of the type of expressions
+such as &abort, but in GCC it is represented internally as a type
+qualifier.  */
+  if (FUNCTION_POINTER_TYPE_P (selector_type)
+ && TYPE_QUALS (TREE_TYPE (selector_type)) != TYPE_UNQUALIFIED)
+  selector_type
+   = build_pointer_type (TYPE_MAIN_VARIANT (TREE_TYPE (selector_type)));
+}
 
   if (!c_parser_require (parser, CPP_COMMA, "expected %<,%>"))
 {
@@ -9401,7 +9422,7 @@ c_parser_generic_selection (c_parser *parser)
   assoc.expression = c_parser_expr_no_commas (parser, NULL);
 
   if (!match)
- c_inhibit_evaluation_warnings--;
+   c_inhibit_evaluation_warnings--;
 
   if (assoc.expression.value == error_mark_node)
{
diff --git a/gcc/testsuite/gcc.dg/gnu2x-generic.c 
b/gcc/testsuite/gcc.dg/gnu2x-generic.c
new file mode 100644
index 000..82b09578072
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/gnu2x-generic.c
@@ -0,0 +1,16 @@
+/* { dg-do compile } */
+
+_Static_assert(_Generic(const int, const int: 1, int: 0), "");
+_Static_assert(_Generic(  int, const int: 0, int: 1), "");
+_Static_assert(_Generic(int[4], int[4]: 1), "");
+_Static_assert(_Generic(typeof(int[4]), int[4]: 1), "");
+
+void foo(int n)
+{
+   _Static_assert(_Generic(int[n++], int[4]: 1), "");
+}
+
+#pragma GCC diagnostic warning "-Wpedantic"
+_Static_a

[committed] c: Less warnings for parameters declared as arrays [PR98536]

2023-08-05 Thread Martin Uecker via Gcc-patches


I splitted up the patch into two parts and committed only
the FE parts which were already approved and the tests.
This solves one of the two issues.

Bootstrapped and regression tested on x86_64-pc-linux-gnu.


Less warnings for parameters declared as arrays [PR98536]

To avoid false positivies, tune the warnings for parameters declared
as arrays with size expressions.  Do not warn when more bounds are
specified in the declaration than before.

PR c/98536

c-family/
* c-warn.cc (warn_parm_array_mismatch): Do not warn if more
bounds are specified.

gcc/testsuite:
* gcc.dg/Wvla-parameter-4.c: Adapt test.
* gcc.dg/attr-access-2.c: Adapt test.


diff --git a/gcc/c-family/c-warn.cc b/gcc/c-family/c-warn.cc
index d4d62c48b20..b7c5d7c01a2 100644
--- a/gcc/c-family/c-warn.cc
+++ b/gcc/c-family/c-warn.cc
@@ -3599,23 +3599,13 @@ warn_parm_array_mismatch (location_t origloc, tree 
fndecl, tree newparms)
  continue;
}
 
- if (newunspec != curunspec)
+ if (newunspec > curunspec)
{
  location_t warnloc = newloc, noteloc = origloc;
  const char *warnparmstr = newparmstr.c_str ();
  const char *noteparmstr = curparmstr.c_str ();
  unsigned warnunspec = newunspec, noteunspec = curunspec;
 
- if (newunspec < curunspec)
-   {
- /* If the new declaration has fewer unspecified bounds
-point the warning to the previous declaration to make
-it clear that that's the one to change.  Otherwise,
-point it to the new decl.  */
- std::swap (warnloc, noteloc);
- std::swap (warnparmstr, noteparmstr);
- std::swap (warnunspec, noteunspec);
-   }
  if (warning_n (warnloc, OPT_Wvla_parameter, warnunspec,
 "argument %u of type %s declared with "
 "%u unspecified variable bound",
@@ -3643,14 +3633,10 @@ warn_parm_array_mismatch (location_t origloc, tree 
fndecl, tree newparms)
}
 
   /* Iterate over the lists of VLA variable bounds, comparing each
-pair for equality, and diagnosing mismatches.  The case of
-the lists having different lengths is handled above so at
-this point they do .  */
-  for (tree newvbl = newa->size, curvbl = cura->size; newvbl;
+pair for equality, and diagnosing mismatches.  */
+  for (tree newvbl = newa->size, curvbl = cura->size; newvbl && curvbl;
   newvbl = TREE_CHAIN (newvbl), curvbl = TREE_CHAIN (curvbl))
{
- gcc_assert (curvbl);
-
  tree newpos = TREE_PURPOSE (newvbl);
  tree curpos = TREE_PURPOSE (curvbl);
 
diff --git a/gcc/testsuite/gcc.dg/Wvla-parameter-4.c 
b/gcc/testsuite/gcc.dg/Wvla-parameter-4.c
index 599ad19a3e4..f35faea361a 100644
--- a/gcc/testsuite/gcc.dg/Wvla-parameter-4.c
+++ b/gcc/testsuite/gcc.dg/Wvla-parameter-4.c
@@ -12,11 +12,6 @@ typedef int IA3[3];
 /* Verify the warning points to the declaration with more unspecified
bounds, guiding the user to specify them rather than making them all
unspecified.  */
-void* f_pIA3ax (IA3 *x[*]); // { dg-warning "argument 1 of type 
'int \\\(\\\*\\\[\\\*]\\\)\\\[3]' .aka '\[^\n\r\}\]+'. declared with 1 
unspecified variable bound" }
-void* f_pIA3ax (IA3 *x[*]);
-void* f_pIA3ax (IA3 *x[n]); // { dg-message "subsequently declared 
as 'int \\\(\\\*\\\[n]\\\)\\\[3]' with 0 unspecified variable bounds" "note" }
-void* f_pIA3ax (IA3 *x[n]) { return x; }
-
 
 void* f_pIA3an (IA3 *x[n]);  // { dg-message "previously declared 
as 'int \\\(\\\*\\\[n]\\\)\\\[3]' with 0 unspecified variable bounds" "note" }
 void* f_pIA3an (IA3 *x[n]);
diff --git a/gcc/testsuite/gcc.dg/attr-access-2.c 
b/gcc/testsuite/gcc.dg/attr-access-2.c
index 76baddffc9f..616b7a9527c 100644
--- a/gcc/testsuite/gcc.dg/attr-access-2.c
+++ b/gcc/testsuite/gcc.dg/attr-access-2.c
@@ -60,16 +60,6 @@ RW (2, 1) void f10 (int n, char a[n])   // { dg-warning 
"attribute 'access *\\\(
 // { dg-warning "argument 2 of type 
'char\\\[n]' declared as a variable length array"  "" { target *-*-* } .-1 }
 { (void)&n; (void)&a; }
 
-
-/* The following is diagnosed to point out declarations with the T[*]
-   form in headers where specifying the bound is just as important as
-   in the definition (to detect bugs).  */
-  void f11 (int, char[*]);  // { dg-warning "argument 2 of type 
'char\\\[\\\*\\\]' declared with 1 unspecified variable bound" }
-  void f11 (int m, char a[m]);  // { dg-message "subsequently declared 
as 'char\\\[m]' with 0 unspecified variable bounds" "note" }
-RW (2, 1) void f11 (int n, char arr[n]) // { dg-message "subsequently declared 
as 'char\\\[n]' with 0 unspecifi

[C PATCH] _Generic should not warn in non-active branches [PR68193,PR97100]

2023-08-03 Thread Martin Uecker via Gcc-patches



Here is a patch to reduce false positives in _Generic.

Bootstrapped and regression tested on x86_64-linux.

Martin

c: _Generic should not warn in non-active branches [PR68193,PR97100]

To avoid false diagnostics, use c_inhibit_evaluation_warnings when
a generic association is known to match during parsing.  We may still
generate false positives if the default branch comes earler than
a specific association that matches.

PR c/68193
PR c/97100

gcc/c/:
* c-parser.cc (c_parser_generic_selection): Inhibit evaluation
warnings branches that are known not be taken during parsing.

gcc/testsuite/ChangeLog:
* gcc.dg/pr68193.c: New test.


diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index 24a6eb6e459..d1863b301e0 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -9350,7 +9350,17 @@ c_parser_generic_selection (c_parser *parser)
  return error_expr;
}
 
+  bool match = assoc.type == NULL_TREE
+  || comptypes (assoc.type, selector_type);
+
+  if (!match)
+   c_inhibit_evaluation_warnings++;
+
   assoc.expression = c_parser_expr_no_commas (parser, NULL);
+
+  if (!match)
+ c_inhibit_evaluation_warnings--;
+
   if (assoc.expression.value == error_mark_node)
{
  c_parser_skip_until_found (parser, CPP_CLOSE_PAREN, NULL);
@@ -9387,7 +9397,7 @@ c_parser_generic_selection (c_parser *parser)
  match_found = associations.length ();
}
}
-  else if (comptypes (assoc.type, selector_type))
+  else if (match)
{
  if (match_found < 0 || matched_assoc.type == NULL_TREE)
{
diff --git a/gcc/testsuite/gcc.dg/pr68193.c b/gcc/testsuite/gcc.dg/pr68193.c
new file mode 100644
index 000..2267593e363
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr68193.c
@@ -0,0 +1,15 @@
+/*  pr69193 */
+/* { dg-do compile } */
+/* { dg-options "-Wall" } */
+
+int
+main (void)
+{
+  int i = 0;
+  int j = _Generic (i,
+   int: 0,
+   long int: (i = (long int) 9223372036854775808UL));
+  return i + j;
+}
+
+




Re: [C PATCH]: Add Walloc-type to warn about insufficient size in allocations

2023-08-02 Thread Martin Uecker via Gcc-patches
Am Mittwoch, dem 02.08.2023 um 16:45 + schrieb Qing Zhao:
> 
> > On Aug 1, 2023, at 10:31 AM, Martin Uecker  wrote:
> > 
> > Am Dienstag, dem 01.08.2023 um 13:27 + schrieb Qing Zhao:
> > > 
> > > > On Aug 1, 2023, at 3:51 AM, Martin Uecker via Gcc-patches 
> > > >  wrote:
> > > > 
> > 
> > 
> > > > > Hi Martin,
> > > > > Just wondering if it'd be a good idea perhaps to warn if alloc size is
> > > > > not a multiple of TYPE_SIZE_UNIT instead of just less-than ?
> > > > > So it can catch cases like:
> > > > > int *p = malloc (sizeof (int) + 2); // probably intended malloc
> > > > > (sizeof (int) * 2)
> > > > > 
> > > > > FWIW, this is caught using -fanalyzer:
> > > > > f.c: In function 'f':
> > > > > f.c:3:12: warning: allocated buffer size is not a multiple of the
> > > > > pointee's size [CWE-131] [-Wanalyzer-allocation-size]
> > > > >3 |   int *p = __builtin_malloc (sizeof(int) + 2);
> > > > >  |^~
> > > > > 
> > > > > Thanks,
> > > > > Prathamesh
> > > > 
> > > > Yes, this is probably a good idea.  It might need special
> > > > logic for flexible array members then...
> > > 
> > > Why special logic for FAM on such warning? (Not a multiple of 
> > > TYPE_SIZE_UNIT for the element).
> > > 
> > 
> > For
> > 
> > struct { int n; char buf[]; } *p = malloc(sizeof *p + n);
> > p->n = n;
> > 
> > the size would not be a multiple.
> 
> But n is still a multiple of sizeof (char), right? Do I miss anything here?

Right, for a struct with FAM we could check that it is
sizeof () plus a multiple of the element size of the FAM.
Still special logic... 

Martin


> Qing
> > 
> > Martin
> > 
> > 
> > 
> > 
> 

-- 
Univ.-Prof. Dr. rer. nat. Martin Uecker
Graz University of Technology
Institute of Biomedical Imaging




Re: [V1][PATCH 0/3] New attribute "element_count" to annotate bounds for C99 FAM(PR108896)

2023-08-01 Thread Martin Uecker via Gcc-patches
Am Dienstag, dem 01.08.2023 um 15:45 -0700 schrieb Kees Cook:
> On Mon, Jul 31, 2023 at 08:14:42PM +, Qing Zhao wrote:
> > /* In general, Due to type casting, the type for the pointee of a pointer
> >does not say anything about the object it points to,
> >So, __builtin_object_size can not directly use the type of the pointee
> >to decide the size of the object the pointer points to.
> > 
> >there are only two reliable ways:
> >A. observed allocations  (call to the allocation functions in the 
> > routine)
> >B. observed accesses (read or write access to the location of the 
> >  pointer points to)
> > 
> >that provide information about the type/existence of an object at
> >the corresponding address.
> > 
> >for A, we use the "alloc_size" attribute for the corresponding allocation
> >functions to determine the object size;
> > 
> >For B, we use the SIZE info of the TYPE attached to the corresponding 
> > access.
> >(We treat counted_by attribute as a complement to the SIZE info of the 
> > TYPE
> > for FMA) 
> > 
> >The only other way in C which ensures that a pointer actually points
> >to an object of the correct type is 'static':
> > 
> >void foo(struct P *p[static 1]);   
> > 
> >See https://gcc.gnu.org/pipermail/gcc-patches/2023-July/624814.html
> >for more details.  */
> 
> This is a great explanation; thank you!
> 
> In the future I might want to have a new builtin that will allow
> a program to query a pointer when neither A nor B have happened. But
> for the first version of the __counted_by infrastructure, the above
> limitations seen fine.
> 
> For example, maybe __builtin_counted_size(p) (which returns sizeof(*p) +
> sizeof(*p->flex_array_member) * p->counted_by_member). Though since
> there might be multiple flex array members, maybe this can't work. :)

We had a _Lengthof proposal for arrays (instead of sizeof/sizeof)
and thought about how to extend this to structs with FAM. The
problem is that it can not rely on an attribute.

With GCC's VLA in structs you could do 

struct foo { int n; char buf[n_init]; } *p = malloc(sizeof *p);
p->n_init = n;

and get sizeof and bounds checking with UBSan
https://godbolt.org/z/d4nneqs3P

(but also compiler bugs and other issues)


Also see my experimental container library, where you can do:

vec_decl(int);
vec(int)* v = vec_alloc(int);

vec_push(&v, 1);
vec_push(&v, 3);

auto p = &vec_array(v);
(*p)[1] = 1; // bounds check

Here, "vec_array()" would give you a regular C array view
of the vector contant and with correct dynamic size, so you
can apply "sizeof" and  have bounds checking with UBSan and
it just works (with clang / GCC without changes). 
https://github.com/uecker/noplate



Martin









Re: _BitInt vs. _Atomic

2023-08-01 Thread Martin Uecker
Am Dienstag, dem 01.08.2023 um 15:54 + schrieb Michael Matz:
> Hello,
> 
> On Mon, 31 Jul 2023, Martin Uecker wrote:
> 
> > >  Say you have a loop like so:
> > > 
> > > _Atomic T obj;
> > > ...
> > > T expected1, expected2, newval;
> > > newval = ...;
> > > expected1 = ...;
> > > do {
> > >   expected2 = expected1;
> > >   if (atomic_compare_exchange_weak(&obj, &expected2, newval);
> > > break;
> > >   expected1 = expected2;
> > > } while (1);
> > > 
> > > As written this looks of course stupid, and you may say "don't do that", 
> > > but internally the copies might result from temporaries (compiler 
> > > generated or wrapper function arguments, or suchlike). 
> > >  Now, while 
> > > expected2 will contain the copied padding bits after the cmpxchg the 
> > > copies to and from expected1 will possibly destroy them.  Either way I 
> > > don't see why the above loop should be out-of-spec, so I can write it and 
> > > expect it to proceed eventually (certainly when the _strong variant is 
> > > used).  Any argument that would declare the above loop out-of-spec I 
> > > would 
> > > consider a defect in the spec.
> > 
> > It is "out-of-spec" for C in the sense that it can not be
> > expected work with the semantics as specified in the C standard.
> 
> (I call that a defect.  See below)

This was extensively discussed in WG14 (before my time). In fact,
there was a defect report about the previous version defined in
terms of values and the wording was changed to memcmp / memcpy
operating on padding bytes (also to align with C++ at that time):

https://www.open-std.org/jtc1/sc22/wg14/www/docs/n2059.htm#dr_431
https://www.open-std.org/jtc1/sc22/wg14/www/docs/n1906.htm


> > In practice, what the semantics specified using memcpy/memcmp
> > allow one to do is to also apply atomic operations on non-atomic 
> > types.  This is not guaranteed to work by the C standard, but
> > in practice  people often have to do this.  For example, nobody
> > is going to copy a 256 GB numerical array with non-atomic types
> > into another data structure with atomic versions of the same
> > type just so that you can apply atomic operations on it.
> > So one simply does an unsafe cast and hopes the compiler does
> > not break this.
> > 
> > If the non-atomic struct now has non-zero values in the padding, 
> > and the compiler would clear those automatically for "expected", 
> > you would create the problem of an infinite loop (this time 
> > for real).
> 
> Only because cmpxchg is defined in terms of memcpy/memcmp. 

Yes, but this is intentional.

>  If it were 
> defined in terms of the == operator (obviously applied recursively 
> member-wise for structs) and simple-assignment that wouldn't be a problem. 

C has no == operator or any concept of struct equality. 

It would also cause implementation overhead and I guess
could cause severe performance issues when there several
padding bytes distributed over an object and you need to
jump over those when doing copying or doing comparisons.
(how do vectorization?)

> In addition that would get rid of all discussion of what happens or 
> doesn't happen with padding.  Introducing reliance on padding bits (which 
> IMHO goes against some fundamental ideas of the C standard) has 
> far-reaching consequences, see below. 

Working with representation bytes of objects is a rather 
fundamental property of C. That you can do this using
character pointers or that you can copy objects with
memcpy and that the result are compared with memcmp is
something I expect to work in C. 

>  The current definition of the 
> atomic_cmpxchg is also inconsistent with the rest of the standard:
> 
> We have:
> 
>   ... (C is non-atomic variant of A) ...
>   _Bool atomic_compare_exchange_strong(volatile A *object,
>C *expected, C desired);
>   ... (is equivalent to atomic variant of:) 
>   if (memcmp(object, expected, sizeof (*object)) == 0)
> { memcpy(object, &desired, sizeof (*object)); return true; }
>   else
> { memcpy(expected, object, sizeof (*object)); return false; }
> 
> But we also have:
> 
>   The size, representation, and alignment of an atomic type need not be 
>   the same as those of the corresponding unqualified type.
> 
>   (with later text only suggesting that at least for atomic integer 
>   types these please be the same.  But here we aren't talking about
>   integer types even.)

Reading the old meeting minutes, it seems WG14 considered
the c

Re: [C PATCH]: Add Walloc-type to warn about insufficient size in allocations

2023-08-01 Thread Martin Uecker via Gcc-patches
Am Dienstag, dem 01.08.2023 um 13:27 + schrieb Qing Zhao:
> 
> > On Aug 1, 2023, at 3:51 AM, Martin Uecker via Gcc-patches 
> >  wrote:
> > 


> > > Hi Martin,
> > > Just wondering if it'd be a good idea perhaps to warn if alloc size is
> > > not a multiple of TYPE_SIZE_UNIT instead of just less-than ?
> > > So it can catch cases like:
> > > int *p = malloc (sizeof (int) + 2); // probably intended malloc
> > > (sizeof (int) * 2)
> > > 
> > > FWIW, this is caught using -fanalyzer:
> > > f.c: In function 'f':
> > > f.c:3:12: warning: allocated buffer size is not a multiple of the
> > > pointee's size [CWE-131] [-Wanalyzer-allocation-size]
> > >    3 |   int *p = __builtin_malloc (sizeof(int) + 2);
> > >  |^~
> > > 
> > > Thanks,
> > > Prathamesh
> > 
> > Yes, this is probably a good idea.  It might need special
> > logic for flexible array members then...
> 
> Why special logic for FAM on such warning? (Not a multiple of TYPE_SIZE_UNIT 
> for the element).
> 

For

struct { int n; char buf[]; } *p = malloc(sizeof *p + n);
p->n = n;

the size would not be a multiple.

Martin






Re: [C PATCH]: Add Walloc-type to warn about insufficient size in allocations

2023-08-01 Thread Martin Uecker via Gcc-patches
Am Dienstag, dem 01.08.2023 um 02:11 +0530 schrieb Prathamesh Kulkarni:
> On Fri, 21 Jul 2023 at 16:52, Martin Uecker via Gcc-patches
>  wrote:
> > 
> > 
> > 
> > This patch adds a warning for allocations with insufficient size
> > based on the "alloc_size" attribute and the type of the pointer
> > the result is assigned to. While it is theoretically legal to
> > assign to the wrong pointer type and cast it to the right type
> > later, this almost always indicates an error. Since this catches
> > common mistakes and is simple to diagnose, it is suggested to
> > add this warning.
> > 
> > 
> > Bootstrapped and regression tested on x86.
> > 
> > 
> > Martin
> > 
> > 
> > 
> > Add option Walloc-type that warns about allocations that have
> > insufficient storage for the target type of the pointer the
> > storage is assigned to.
> > 
> > gcc:
> > * doc/invoke.texi: Document -Wstrict-flex-arrays option.
> > 
> > gcc/c-family:
> > 
> > * c.opt (Walloc-type): New option.
> > 
> > gcc/c:
> > * c-typeck.cc (convert_for_assignment): Add Walloc-type warning.
> > 
> > gcc/testsuite:
> > 
> > * gcc.dg/Walloc-type-1.c: New test.
> > 
> > 
> > diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
> > index 4abdc8d0e77..8b9d148582b 100644
> > --- a/gcc/c-family/c.opt
> > +++ b/gcc/c-family/c.opt
> > @@ -319,6 +319,10 @@ Walloca
> >  C ObjC C++ ObjC++ Var(warn_alloca) Warning
> >  Warn on any use of alloca.
> > 
> > +Walloc-type
> > +C ObjC Var(warn_alloc_type) Warning
> > +Warn when allocating insufficient storage for the target type of the
> > assigned pointer.
> > +
> >  Walloc-size-larger-than=
> >  C ObjC C++ LTO ObjC++ Var(warn_alloc_size_limit) Joined Host_Wide_Int
> > ByteSize Warning Init(HOST_WIDE_INT_MAX)
> >  -Walloc-size-larger-than=   Warn for calls to allocation
> > functions that
> > diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
> > index 7cf411155c6..2e392f9c952 100644
> > --- a/gcc/c/c-typeck.cc
> > +++ b/gcc/c/c-typeck.cc
> > @@ -7343,6 +7343,32 @@ convert_for_assignment (location_t location,
> > location_t expr_loc, tree type,
> > "request for implicit conversion "
> > "from %qT to %qT not permitted in C++", rhstype,
> > type);
> > 
> > +  /* Warn of new allocations are not big enough for the target
> > type.  */
> > +  tree fndecl;
> > +  if (warn_alloc_type
> > + && TREE_CODE (rhs) == CALL_EXPR
> > + && (fndecl = get_callee_fndecl (rhs)) != NULL_TREE
> > + && DECL_IS_MALLOC (fndecl))
> > +   {
> > + tree fntype = TREE_TYPE (fndecl);
> > + tree fntypeattrs = TYPE_ATTRIBUTES (fntype);
> > + tree alloc_size = lookup_attribute ("alloc_size",
> > fntypeattrs);
> > + if (alloc_size)
> > +   {
> > + tree args = TREE_VALUE (alloc_size);
> > + int idx = TREE_INT_CST_LOW (TREE_VALUE (args)) - 1;
> > + /* For calloc only use the second argument.  */
> > + if (TREE_CHAIN (args))
> > +   idx = TREE_INT_CST_LOW (TREE_VALUE (TREE_CHAIN
> > (args))) - 1;
> > + tree arg = CALL_EXPR_ARG (rhs, idx);
> > + if (TREE_CODE (arg) == INTEGER_CST
> > + && tree_int_cst_lt (arg, TYPE_SIZE_UNIT (ttl)))
> Hi Martin,
> Just wondering if it'd be a good idea perhaps to warn if alloc size is
> not a multiple of TYPE_SIZE_UNIT instead of just less-than ?
> So it can catch cases like:
> int *p = malloc (sizeof (int) + 2); // probably intended malloc
> (sizeof (int) * 2)
> 
> FWIW, this is caught using -fanalyzer:
> f.c: In function 'f':
> f.c:3:12: warning: allocated buffer size is not a multiple of the
> pointee's size [CWE-131] [-Wanalyzer-allocation-size]
> 3 |   int *p = __builtin_malloc (sizeof(int) + 2);
>   |^~
> 
> Thanks,
> Prathamesh

Yes, this is probably a good idea.  It might need special
logic for flexible array members then...


Martin


> > +warning_at (location, OPT_Walloc_type, "allocation of
> > "
> > +"insufficient size %qE for type %qT with
> > "
> > +"size %qE", arg, ttl, TYPE_SIZE_UNIT
> > (ttl));
> &g

Re: [C PATCH]: Add Walloc-type to warn about insufficient size in allocations

2023-07-31 Thread Martin Uecker via Gcc-patches
Am Montag, dem 31.07.2023 um 15:39 -0400 schrieb Siddhesh Poyarekar:
> On 2023-07-21 07:21, Martin Uecker via Gcc-patches wrote:
> > 
> > 
> > This patch adds a warning for allocations with insufficient size
> > based on the "alloc_size" attribute and the type of the pointer
> > the result is assigned to. While it is theoretically legal to
> > assign to the wrong pointer type and cast it to the right type
> > later, this almost always indicates an error. Since this catches
> > common mistakes and is simple to diagnose, it is suggested to
> > add this warning.
> >   

...

> > 
> 
> Wouldn't this be much more useful in later phases with ranger feedback 
> like with the warn_access warnings?  That way the comparison won't be 
> limited to constant sizes.

Possibly. Having it in the FE made it simple to implement and
also reliable.  One thing I considered is also looking deeper
into the argument and detect obvious mistakes, e.g. if the
type in a sizeof is the right one. Such extensions would be
easier in the FE.

But I wouldn't mind replacing or extending this with something
smarter emitted from later phases. I probably do not have time
to work on this is myself in the near future though.

Martin




Re: _BitInt vs. _Atomic

2023-07-31 Thread Martin Uecker
Am Montag, dem 31.07.2023 um 14:33 + schrieb Michael Matz:
> Hello,
> 
> On Fri, 28 Jul 2023, Martin Uecker wrote:
> 
> > > > Sorry, somehow I must be missing something here.
> > > > 
> > > > If you add something you would create a new value and this may (in
> > > > an object) have random new padding.  But the "expected" value should
> > > > be updated by a failed atomic_compare_exchange cycle and then have
> > > > same padding as the value stored in the atomic. So the next cycle
> > > > should succeed.  The user would not change the representation of
> > > > the "expected" value but create a new value for another object
> > > > by adding something.
> > > 
> > > You're right that it would pass the expected value not something after an
> > > operation on it usually.  But still, expected type will be something like
> > > _BitInt(37) or _BitInt(195) and so neither the atomic_load nor what
> > > atomic_compare_exchange copies back on failure is guaranteed to have the
> > > padding bits preserved.
> > 
> > For atomic_load in C a value is returned. A value does not care about
> > padding and when stored into a new object can produce new and different
> > padding.  
> > 
> > But for atomic_compare_exchange the memory content is copied into 
> > an object passed by pointer, so here the C standard requires to
> > that the padding is preserved. It explicitely states that the effect
> > is like:
> > 
> > if (memcmp(object, expected, sizeof(*object)) == 0)
> >   memcpy(object, &desired, sizeof(*object));
> > else
> >   memcpy(expected, object, sizeof(*object));
> > 
> > > It is true that if it is larger than 16 bytes the libatomic 
> > > atomic_compare_exchange will memcpy the value back which copies the 
> > > padding bits, but is there a guarantee that the user code doesn't 
> > > actually copy that value further into some other variable?  
> > 
> > I do not think it would be surprising for C user when
> > the next atomic_compare_exchange fails in this case.
> 
> But that is a problem (the same one the cited C++ paper tries to resolve, 
> IIUC). 

I do not quite understand the paper. I can't see
how the example 3 in

https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0528r0.html

could loop indefinitely with the memcpy / memcmp semantics,
but somehow the authors seem to claim this. 


>  Say you have a loop like so:
> 
> _Atomic T obj;
> ...
> T expected1, expected2, newval;
> newval = ...;
> expected1 = ...;
> do {
>   expected2 = expected1;
>   if (atomic_compare_exchange_weak(&obj, &expected2, newval);
> break;
>   expected1 = expected2;
> } while (1);
> 
> As written this looks of course stupid, and you may say "don't do that", 
> but internally the copies might result from temporaries (compiler 
> generated or wrapper function arguments, or suchlike). 
>  Now, while 
> expected2 will contain the copied padding bits after the cmpxchg the 
> copies to and from expected1 will possibly destroy them.  Either way I 
> don't see why the above loop should be out-of-spec, so I can write it and 
> expect it to proceed eventually (certainly when the _strong variant is 
> used).  Any argument that would declare the above loop out-of-spec I would 
> consider a defect in the spec.

It is "out-of-spec" for C in the sense that it can not be
expected work with the semantics as specified in the C standard.

But I agree with you that it would be better if it just worked.

A compiler could, for example, always clear the padding when
initializing or storing atomic values.  It might also clear
the padding of the initial "expected", when it is
initialized or stored to.

But it should not clear / ignore the padding when copying 
to "expected" using atomic_compare_exhange or when comparing
to the memory content. See below why I think this would not
be helpful.

> 
> It's never a good idea to introduce reliance on padding bits.  Exactly 
> because you can trivially destroy them with simple value copies.
> 
> > > Anyway, for smaller or equal to 16 (or 8) bytes if 
> > > atomic_compare_exchange is emitted inline I don't see what would 
> > > preserve the bits.
> > 
> > This then seems to be incorrect for C.
> 
> Or the spec is.

In practice, what the semantics specified using memcpy/memcmp
allow one to do is to also apply atomic operations on non-atomic 
types.  This is not guaranteed to work by the C standard, but
in practice  people often have to do this.  For example, nobody
is going to copy a 256 GB numerical array with non-atomic types
into another data structure with atomic versions of the same
type just so that you can apply atomic operations on it. So
one simply does an unsafe cast and hopes the compiler does not
break this.

If the non-atomic struct now has non-zero values in the padding, 
and the compiler would clear those automatically for "expected", 
you would create the problem of an infinite loop (this time 
for real).


Martin









[PING 3] [PATCH] Less warnings for parameters declared as arrays [PR98541, PR98536]

2023-07-31 Thread Martin Uecker via Gcc-patches


Joseph, I would appreciate if you could take a look at this?  

This fixes the remaining issues which requires me to turn the
warnings off with -Wno-vla-parameter and -Wno-nonnull in my
projects.

Am Montag, dem 03.04.2023 um 21:34 +0200 schrieb Martin Uecker:
> 
> With the relatively new warnings (11..) affecting VLA bounds,
> I now get a lot of false positives with -Wall. In general, I find
> the new warnings very useful, but they seem a bit too
> aggressive and some minor tweaks are needed, otherwise they are
> too noisy.  This patch suggests two changes:
> 
> 1. For VLA bounds non-null is implied only when 'static' is
> used (similar to clang) and not already when a bound > 0 is
> specified:
> 
> int foo(int n, char buf[static n]);
> 
> int foo(10, 0); // warning with 'static' but not without.
> 
> 
> (It also seems problematic to require a size of 0 to indicate 
> that the pointer may be null, because 0 is not allowed in
> ISO C as a size. It is also inconsistent to how arrays with
> static bound behave.) 
> 
> There seems to be agreement about this change in PR98541.
> 
> 
> 2. GCC always warns when the number of unspecified
> bounds is different between two declarations:
> 
> int foo(int n, char buf[*]);
> int foo(int n, char buf[n]);
> 
> or
> 
> int foo(int n, char buf[n]);
> int foo(int n, char buf[*]);
> 
> But the first version is useful if the size expression
> can not be specified in a header (e.g. because it uses
> a macro or variable not available there) and there is
> currently no easy way to avoid this.  The warning for
> both cases was by design,  but I suggest to limit the
> warning to the second case. 
> 
> Note that the logic currently applied by GCC is too
> simplistic anyway, as GCC does not warn for
> 
> int foo(int x, int y, double m[*][y]);
> int foo(int x, int y, double m[x][*]);
> 
> because the number of specified / unspecified bounds
> is the same.  So I suggest to go with the attached
> patch now and add  more precise warnings later
> if there is more experience with these warning 
> in gernal and if this then still seems desirable.
> 
> 
> Martin
> 
> 
> Less warnings for parameters declared as arrays [PR98541, PR98536]
> 
> To avoid false positivies, tune the warnings for parameters declared
> as arrays with size expressions.  Only warn about null arguments with
> 'static'.  Also do not warn when more bounds are specified in the new
> declaration than before.
> 
> PR c/98541
> PR c/98536
> 
> c-family/
> * c-warn.cc (warn_parm_array_mismatch): Do not warn if more
> bounds are specified.
> 
> gcc/
> * gimple-ssa-warn-access.cc
>   (pass_waccess::maybe_check_access_sizes): For VLA bounds
> in parameters, only warn about null pointers with 'static'.
> 
> gcc/testsuite:
> * gcc.dg/Wnonnull-4: Adapt test.
> * gcc.dg/Wstringop-overflow-40.c: Adapt test.
> * gcc.dg/Wvla-parameter-4.c: Adapt test.
> * gcc.dg/attr-access-2.c: Adapt test.
> 
> 
> diff --git a/gcc/c-family/c-warn.cc b/gcc/c-family/c-warn.cc
> index 9ac43a1af6e..f79fb876142 100644
> --- a/gcc/c-family/c-warn.cc
> +++ b/gcc/c-family/c-warn.cc
> @@ -3599,23 +3599,13 @@ warn_parm_array_mismatch (location_t origloc, tree 
> fndecl, tree newparms)
> continue;
>   }
>  
> -   if (newunspec != curunspec)
> +   if (newunspec > curunspec)
>   {
> location_t warnloc = newloc, noteloc = origloc;
> const char *warnparmstr = newparmstr.c_str ();
> const char *noteparmstr = curparmstr.c_str ();
> unsigned warnunspec = newunspec, noteunspec = curunspec;
>  
> -   if (newunspec < curunspec)
> - {
> -   /* If the new declaration has fewer unspecified bounds
> -  point the warning to the previous declaration to make
> -  it clear that that's the one to change.  Otherwise,
> -  point it to the new decl.  */
> -   std::swap (warnloc, noteloc);
> -   std::swap (warnparmstr, noteparmstr);
> -   std::swap (warnunspec, noteunspec);
> - }
> if (warning_n (warnloc, OPT_Wvla_parameter, warnunspec,
>"argument %u of type %s declared with "
>"%u unspecified variable bound",
> @@ -3641,16 +3631,11 @@ warn_parm_array_mismatch (location_t origloc, tree 
&

Re: _BitInt vs. _Atomic

2023-07-28 Thread Martin Uecker
Am Freitag, dem 28.07.2023 um 17:10 +0200 schrieb Jakub Jelinek:
> On Fri, Jul 28, 2023 at 04:53:30PM +0200, Martin Uecker wrote:
> > > The thing is that user doesn't have much control over those
> > > padding bits, so whether _Atomic operations on long double (when it is 80
> > > bit and stores from hw actually store 10 bytes rather than 12 or 16), or
> > > _BitInt(37) or _BitInt(195) or struct S { char a; int b; }; then depend
> > > purely on luck.  If the expected value is based on atomic_load on the
> > > atomic_compare_exchange location or whatever atomic_compare_exchange gave
> > > back, if in the loop one e.g. adds something to it, then again it might 
> > > get
> > > different padding bits from what is originally in memory, so it isn't true
> > > that it will always succeed at least in the second loop iteration.
> > 
> > Sorry, somehow I must be missing something here.
> > 
> > If you add something you would create a new value and this may (in
> > an object) have random new padding.  But the "expected" value should
> > be updated by a failed atomic_compare_exchange cycle and then have
> > same padding as the value stored in the atomic. So the next cycle
> > should succeed.  The user would not change the representation of
> > the "expected" value but create a new value for another object
> > by adding something.
> 
> You're right that it would pass the expected value not something after an
> operation on it usually.  But still, expected type will be something like
> _BitInt(37) or _BitInt(195) and so neither the atomic_load nor what
> atomic_compare_exchange copies back on failure is guaranteed to have the
> padding bits preserved.

For atomic_load in C a value is returned. A value does not care about
padding and when stored into a new object can produce new and different
padding.  

But for atomic_compare_exchange the memory content is copied into 
an object passed by pointer, so here the C standard requires to
that the padding is preserved. It explicitely states that the effect
is like:

if (memcmp(object, expected, sizeof(*object)) == 0)
  memcpy(object, &desired, sizeof(*object));
else
  memcpy(expected, object, sizeof(*object));


> It is true that if it is larger than 16 bytes the libatomic
> atomic_compare_exchange will memcpy the value back which copies the padding
> bits, but is there a guarantee that the user code doesn't actually copy that
> value further into some other variable?  

I do not think it would be surprising for C user when
the next atomic_compare_exchange fails in this case.

> Anyway, for smaller or equal
> to 16 (or 8) bytes if atomic_compare_exchange is emitted inline I don't see
> what would preserve the bits.

This then seems to be incorrect for C.

Martin



Re: _BitInt vs. _Atomic

2023-07-28 Thread Martin Uecker
Am Freitag, dem 28.07.2023 um 16:26 +0200 schrieb Jakub Jelinek:
> On Fri, Jul 28, 2023 at 04:03:39PM +0200, Martin Uecker wrote:
> > > On Thu, Jul 27, 2023 at 07:06:03PM +, Joseph Myers wrote:
> > > > I think there should be tests for _Atomic _BitInt types.  Hopefully 
> > > > atomic 
> > > > compound assignment just works via the logic for compare-and-exchange 
> > > > loops, but does e.g. atomic_fetch_add work with _Atomic _BitInt types?
> > > 
> > > So, there are 2 issues.
> > > 
> > > One is something I haven't seen being handled for C at all so far, but
> > > handled for C++ - padding bits.
> > > 
> > > Already e.g. x86 long double has some padding bits - 16 bits on ia32,
> > > 48 bits on x86_64, when one does
> > >   _Atomic long double l;
> > > ...
> > >   l += 2.0;
> > > it will sometimes work and sometimes hang forever.
> > > Similarly atomic_compare_exchange with structs which contain padding
> > > (unions with padding bits are lost case, there is nothing that can be
> > > reliably done for that, because we don't know at runtime what is the 
> > > active
> > > union member if any).  And _BitInt if it doesn't use all bits in
> > > all containing limbs has padding as well (and psABI doesn't say it is sign
> > > or zero extended).
> > 
> > What is the problem here?  In C, atomic_compare_exchange is defined in terms
> > of the memory content which includes padding.  So it may fail spuriously
> > due to padding differences (but it may fail anyway for arbitrary reasons
> > even without padding differences), but then should work in the second 
> > iterations.
> 
> See https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2018/p0528r3.html
> for background.  

Thanks. I have seen this at that time, but it seems to refer to 
C++ specific problems. At least at that time, I concluded (maybe
incorrectly) that this is not a serious problem for how things 
work in C.


> The thing is that user doesn't have much control over those
> padding bits, so whether _Atomic operations on long double (when it is 80
> bit and stores from hw actually store 10 bytes rather than 12 or 16), or
> _BitInt(37) or _BitInt(195) or struct S { char a; int b; }; then depend
> purely on luck.  If the expected value is based on atomic_load on the
> atomic_compare_exchange location or whatever atomic_compare_exchange gave
> back, if in the loop one e.g. adds something to it, then again it might get
> different padding bits from what is originally in memory, so it isn't true
> that it will always succeed at least in the second loop iteration.

Sorry, somehow I must be missing something here.

If you add something you would create a new value and this may (in
an object) have random new padding.  But the "expected" value should
be updated by a failed atomic_compare_exchange cycle and then have
same padding as the value stored in the atomic. So the next cycle
should succeed.  The user would not change the representation of
the "expected" value but create a new value for another object
by adding something.


Martin






Re: _BitInt vs. _Atomic

2023-07-28 Thread Martin Uecker
Am Freitag, dem 28.07.2023 um 16:03 +0200 schrieb Martin Uecker:
> 
> > On Thu, Jul 27, 2023 at 07:06:03PM +, Joseph Myers wrote:
> > > I think there should be tests for _Atomic _BitInt types.  Hopefully 
> > > atomic 
> > > compound assignment just works via the logic for compare-and-exchange 
> > > loops, but does e.g. atomic_fetch_add work with _Atomic _BitInt types?
> > 
> > So, there are 2 issues.
> > 
> > One is something I haven't seen being handled for C at all so far, but
> > handled for C++ - padding bits.
> > 
> > Already e.g. x86 long double has some padding bits - 16 bits on ia32,
> > 48 bits on x86_64, when one does
> >   _Atomic long double l;
> > ...
> >   l += 2.0;
> > it will sometimes work and sometimes hang forever.
> > Similarly atomic_compare_exchange with structs which contain padding
> > (unions with padding bits are lost case, there is nothing that can be
> > reliably done for that, because we don't know at runtime what is the active
> > union member if any).  And _BitInt if it doesn't use all bits in
> > all containing limbs has padding as well (and psABI doesn't say it is sign
> > or zero extended).
> 
> What is the problem here?  In C, atomic_compare_exchange is defined in terms
> of the memory content which includes padding.  So it may fail spuriously
> due to padding differences (but it may fail anyway for arbitrary reasons
> even without padding differences), but then should work in the second 
> iterations.

(only the weak version can fail spuriously, but the strong one can still
fail if there are differences in the padding)





Re: _BitInt vs. _Atomic

2023-07-28 Thread Martin Uecker



> On Thu, Jul 27, 2023 at 07:06:03PM +, Joseph Myers wrote:
> > I think there should be tests for _Atomic _BitInt types.  Hopefully atomic 
> > compound assignment just works via the logic for compare-and-exchange 
> > loops, but does e.g. atomic_fetch_add work with _Atomic _BitInt types?
> 
> So, there are 2 issues.
> 
> One is something I haven't seen being handled for C at all so far, but
> handled for C++ - padding bits.
> 
> Already e.g. x86 long double has some padding bits - 16 bits on ia32,
> 48 bits on x86_64, when one does
>   _Atomic long double l;
> ...
>   l += 2.0;
> it will sometimes work and sometimes hang forever.
> Similarly atomic_compare_exchange with structs which contain padding
> (unions with padding bits are lost case, there is nothing that can be
> reliably done for that, because we don't know at runtime what is the active
> union member if any).  And _BitInt if it doesn't use all bits in
> all containing limbs has padding as well (and psABI doesn't say it is sign
> or zero extended).

What is the problem here?  In C, atomic_compare_exchange is defined in terms
of the memory content which includes padding.  So it may fail spuriously
due to padding differences (but it may fail anyway for arbitrary reasons
even without padding differences), but then should work in the second 
iterations.

Martin





[C PATCH] Synthesize nonnull attribute for parameters declared with static

2023-07-26 Thread Martin Uecker



C programmers increasingly use static to indicate that
pointer parameters are non-null.  Clang can exploit this
for warnings and optimizations.  GCC has some warnings
but not all warnings it has for nonnull.  Below is a
patch to add a nonnull attribute automatically for such 
arguments and to remove the special and more limited
nonnull warnings for static. This patch found some 
misplaced annotations in one of my projects via
-Wnonnull-compare which clang does not seem to have, 
so I think this could be useful.



Parameters declared with `static` are nonnull. We synthesize
an artifical nonnull attribute for such parameters to get the
same warnings and optimizations.

Bootstrapped and regression tested on x86.


gcc/c-family/:
* c-attribs.cc (build_attr_access_from_parms): Synthesize
nonnull attribute for parameters declared with `static`.

gcc/:
* gimple-ssa-warn-access.cc (pass_waccess::maybe_check_access_sizes):
remove warning for parameters declared with `static`.

gcc/testsuite/:
* gcc.dg/Wnonnull-8.c: Adapt test.
* gcc.dg/Wnonnull-9.c: New test.


diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc
index e2792ca6898..ae7ffeb1f65 100644
--- a/gcc/c-family/c-attribs.cc
+++ b/gcc/c-family/c-attribs.cc
@@ -5280,6 +5280,7 @@ build_attr_access_from_parms (tree parms, bool
skip_voidptr)
 arg2pos.put (arg, argpos);
 }
+ tree nnlist = NULL_TREE;
 argpos = 0;
 for (tree arg = parms; arg; arg = TREE_CHAIN (arg), ++argpos)
 {
@@ -5313,6 +5314,11 @@ build_attr_access_from_parms (tree parms, bool
skip_voidptr)
 tree str = TREE_VALUE (argspec);
 const char *s = TREE_STRING_POINTER (str);
+ /* Collect the list of nonnull arguments which use "[static ..]". */
+ if (s != NULL && s[0] == '[' && s[1] == 's')
+ nnlist = tree_cons (NULL_TREE, build_int_cst (integer_type_node,
+ argpos + 1), nnlist);
+
 /* Create the attribute access string from the arg spec string,
 optionally followed by position of the VLA bound argument if
 it is one. */
@@ -5380,6 +5386,10 @@ build_attr_access_from_parms (tree parms, bool
skip_voidptr)
 if (!spec.length ())
 return NULL_TREE;
+ /* If we have nonnull arguments, synthesize an attribute. */
+ if (nnlist != NULL_TREE)
+ nnlist = build_tree_list (get_identifier ("nonnull"), nnlist);
+
 /* Attribute access takes a two or three arguments. Wrap VBLIST in
 another list in case it has more nodes than would otherwise fit. */
 vblist = build_tree_list (NULL_TREE, vblist);
@@ -5390,7 +5400,7 @@ build_attr_access_from_parms (tree parms, bool
skip_voidptr)
 tree str = build_string (spec.length (), spec.c_str ());
 tree attrargs = tree_cons (NULL_TREE, str, vblist);
 tree name = get_identifier ("access");
- return build_tree_list (name, attrargs);
+ return tree_cons (name, attrargs, nnlist);
 }
 /* Handle a "nothrow" attribute; arguments as in
diff --git a/gcc/gimple-ssa-warn-access.cc b/gcc/gimple-ssa-warn-
access.cc
index ac07a6f9b95..b1cd06c 100644
--- a/gcc/gimple-ssa-warn-access.cc
+++ b/gcc/gimple-ssa-warn-access.cc
@@ -3504,16 +3504,6 @@ pass_waccess::maybe_check_access_sizes (rdwr_map
*rwm, tree fndecl, tree fntype,
 ptridx + 1, sizidx + 1, sizstr))
 arg_warned = OPT_Wnonnull;
 }
- else if (access_size && access.second.static_p)
- {
- /* Warn about null pointers for [static N] array arguments
- but do not warn for ordinary (i.e., nonstatic) arrays. */
- if (warning_at (loc, OPT_Wnonnull,
- "argument %i to %<%T[static %E]%> "
- "is null where non-null expected",
- ptridx + 1, argtype, access_nelts))
- arg_warned = OPT_Wnonnull;
- }
 if (arg_warned != no_warning)
 {
diff --git a/gcc/testsuite/gcc.dg/Wnonnull-8.c
b/gcc/testsuite/gcc.dg/Wnonnull-8.c
index 02871a76689..b24fd67cebc 100644
--- a/gcc/testsuite/gcc.dg/Wnonnull-8.c
+++ b/gcc/testsuite/gcc.dg/Wnonnull-8.c
@@ -10,5 +10,5 @@ foo (int a[static 7])
 int
 main ()
 {
- foo ((int *) 0); /* { dg-warning "argument 1 to 'int\\\[static 7\\\]'
is null where non-null expected" } */
+ foo ((int *) 0); /* { dg-warning "argument 1 null where non-null
expected" } */
 }
diff --git a/gcc/testsuite/gcc.dg/Wnonnull-9.c
b/gcc/testsuite/gcc.dg/Wnonnull-9.c
new file mode 100644
index 000..1c57eefd2ae
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Wnonnull-9.c
@@ -0,0 +1,17 @@
+/* { dg-do compile } */
+/* { dg-options "-Wall" } */
+
+
+void
+foo (int a[static 1])
+{
+ if ((void*)0 == a) /* { dg-warning "argument" "compared to NULL" } */
+ return;
+}
+
+int
+main ()
+{
+ foo ((void*)0); /* { dg-warning "argument 1 null where non-null
expected" } */
+}
+





[C PATCH]: Add Walloc-type to warn about insufficient size in allocations

2023-07-21 Thread Martin Uecker via Gcc-patches



This patch adds a warning for allocations with insufficient size
based on the "alloc_size" attribute and the type of the pointer 
the result is assigned to. While it is theoretically legal to
assign to the wrong pointer type and cast it to the right type
later, this almost always indicates an error. Since this catches
common mistakes and is simple to diagnose, it is suggested to
add this warning.
 

Bootstrapped and regression tested on x86. 


Martin



Add option Walloc-type that warns about allocations that have
insufficient storage for the target type of the pointer the
storage is assigned to.

gcc:
* doc/invoke.texi: Document -Wstrict-flex-arrays option.

gcc/c-family:

* c.opt (Walloc-type): New option.

gcc/c:
* c-typeck.cc (convert_for_assignment): Add Walloc-type warning.

gcc/testsuite:

* gcc.dg/Walloc-type-1.c: New test.


diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 4abdc8d0e77..8b9d148582b 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -319,6 +319,10 @@ Walloca
 C ObjC C++ ObjC++ Var(warn_alloca) Warning
 Warn on any use of alloca.
 
+Walloc-type
+C ObjC Var(warn_alloc_type) Warning
+Warn when allocating insufficient storage for the target type of the
assigned pointer.
+
 Walloc-size-larger-than=
 C ObjC C++ LTO ObjC++ Var(warn_alloc_size_limit) Joined Host_Wide_Int
ByteSize Warning Init(HOST_WIDE_INT_MAX)
 -Walloc-size-larger-than=   Warn for calls to allocation
functions that
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 7cf411155c6..2e392f9c952 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -7343,6 +7343,32 @@ convert_for_assignment (location_t location,
location_t expr_loc, tree type,
"request for implicit conversion "
"from %qT to %qT not permitted in C++", rhstype,
type);
 
+  /* Warn of new allocations are not big enough for the target
type.  */
+  tree fndecl;
+  if (warn_alloc_type
+ && TREE_CODE (rhs) == CALL_EXPR
+ && (fndecl = get_callee_fndecl (rhs)) != NULL_TREE
+ && DECL_IS_MALLOC (fndecl))
+   {
+ tree fntype = TREE_TYPE (fndecl);
+ tree fntypeattrs = TYPE_ATTRIBUTES (fntype);
+ tree alloc_size = lookup_attribute ("alloc_size",
fntypeattrs);
+ if (alloc_size)
+   {
+ tree args = TREE_VALUE (alloc_size);
+ int idx = TREE_INT_CST_LOW (TREE_VALUE (args)) - 1;
+ /* For calloc only use the second argument.  */
+ if (TREE_CHAIN (args))
+   idx = TREE_INT_CST_LOW (TREE_VALUE (TREE_CHAIN
(args))) - 1;
+ tree arg = CALL_EXPR_ARG (rhs, idx);
+ if (TREE_CODE (arg) == INTEGER_CST
+ && tree_int_cst_lt (arg, TYPE_SIZE_UNIT (ttl)))
+warning_at (location, OPT_Walloc_type, "allocation of
"
+"insufficient size %qE for type %qT with
"
+"size %qE", arg, ttl, TYPE_SIZE_UNIT
(ttl));
+   }
+   }
+
   /* See if the pointers point to incompatible address spaces.  */
   asl = TYPE_ADDR_SPACE (ttl);
   asr = TYPE_ADDR_SPACE (ttr);
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 88e3c625030..6869bed64c3 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -8076,6 +8076,15 @@ always leads to a call to another @code{cold}
function such as wrappers of
 C++ @code{throw} or fatal error reporting functions leading to
@code{abort}.
 @end table
 
+@opindex Wno-alloc-type
+@opindex Walloc-type
+@item -Walloc-type
+Warn about calls to allocation functions decorated with attribute
+@code{alloc_size} that specify insufficient size for the target type
of
+the pointer the result is assigned to, including those to the built-in
+forms of the functions @code{aligned_alloc}, @code{alloca},
@code{calloc},
+@code{malloc}, and @code{realloc}.
+
 @opindex Wno-alloc-zero
 @opindex Walloc-zero
 @item -Walloc-zero
diff --git a/gcc/testsuite/gcc.dg/Walloc-type-1.c
b/gcc/testsuite/gcc.dg/Walloc-type-1.c
new file mode 100644
index 000..bc62e5e9aa3
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Walloc-type-1.c
@@ -0,0 +1,37 @@
+/* Tests the warnings for insufficient allocation size. 
+   { dg-do compile }
+ * { dg-options "-Walloc-type" } 
+ * */
+#include 
+#include 
+
+struct b { int x[10]; };
+
+void fo0(void)
+{
+struct b *p = malloc(sizeof *p);
+}
+
+void fo1(void)
+{
+struct b *p = malloc(sizeof p);/* { dg-
warning "allocation of insufficient size" } */
+}
+
+void fo2(void)
+{
+struct b *p = alloca(sizeof p);/* { dg-
warning "allocation of insufficient size" } */
+}
+
+void fo3(void)
+{
+struct b *p = calloc(1, sizeof p); /* { dg-warning
"allocation of insufficient size" } */
+}
+
+void g(struct b* p);
+
+void fo4(void)
+{
+g(malloc(4));  /* { dg-warning "allocation of
insufficient size" } */
+}
+
+





[PING 2] [PATCH] Less warnings for parameters declared as arrays [PR98541, PR98536]

2023-07-19 Thread Martin Uecker via Gcc-patches



Ok for gcc-14 now?


Am Dienstag, dem 04.04.2023 um 19:31 -0600 schrieb Jeff Law:
> 
> 
> On 4/3/23 13:34, Martin Uecker via Gcc-patches wrote:
> > 
> > 
> > With the relatively new warnings (11..) affecting VLA bounds,
> > I now get a lot of false positives with -Wall. In general, I find
> > the new warnings very useful, but they seem a bit too
> > aggressive and some minor tweaks are needed, otherwise they are
> > too noisy.  This patch suggests two changes:
> > 
> > 1. For VLA bounds non-null is implied only when 'static' is
> > used (similar to clang) and not already when a bound > 0 is
> > specified:
> > 
> > int foo(int n, char buf[static n]);
> > 
> > int foo(10, 0); // warning with 'static' but not without.
> > 
> > 
> > (It also seems problematic to require a size of 0 to indicate
> > that the pointer may be null, because 0 is not allowed in
> > ISO C as a size. It is also inconsistent to how arrays with
> > static bound behave.)
> > 
> > There seems to be agreement about this change in PR98541.
> > 
> > 
> > 2. GCC always warns when the number of unspecified
> > bounds is different between two declarations:
> > 
> > int foo(int n, char buf[*]);
> > int foo(int n, char buf[n]);
> > 
> > or
> > 
> > int foo(int n, char buf[n]);
> > int foo(int n, char buf[*]);
> > 
> > But the first version is useful if the size expression
> > can not be specified in a header (e.g. because it uses
> > a macro or variable not available there) and there is
> > currently no easy way to avoid this.  The warning for
> > both cases was by design,  but I suggest to limit the
> > warning to the second case.
> > 
> > Note that the logic currently applied by GCC is too
> > simplistic anyway, as GCC does not warn for
> > 
> > int foo(int x, int y, double m[*][y]);
> > int foo(int x, int y, double m[x][*]);
> > 
> > because the number of specified / unspecified bounds
> > is the same.  So I suggest to go with the attached
> > patch now and add  more precise warnings later
> > if there is more experience with these warning
> > in gernal and if this then still seems desirable.
> > 
> > 
> > Martin
> > 
> > 
> >  Less warnings for parameters declared as arrays [PR98541,
> > PR98536]
> >  
> >  To avoid false positivies, tune the warnings for parameters
> > declared
> >  as arrays with size expressions.  Only warn about null
> > arguments with
> >  'static'.  Also do not warn when more bounds are specified in
> > the new
> >  declaration than before.
> >  
> >  PR c/98541
> >  PR c/98536
> >  
> >  c-family/
> >  * c-warn.cc (warn_parm_array_mismatch): Do not warn if
> > more
> >  bounds are specified.
> >  
> >  gcc/
> >  * gimple-ssa-warn-access.cc
> >    (pass_waccess::maybe_check_access_sizes): For VLA
> > bounds
> >  in parameters, only warn about null pointers with
> > 'static'.
> >  
> >  gcc/testsuite:
> >  * gcc.dg/Wnonnull-4: Adapt test.
> >  * gcc.dg/Wstringop-overflow-40.c: Adapt test.
> >  * gcc.dg/Wvla-parameter-4.c: Adapt test.
> >  * gcc.dg/attr-access-2.c: Adapt test.
> Neither appears to be a regression.  Seems like it should defer to
> gcc-14.
> jeff




Re: [PATCH] core: Support heap-based trampolines

2023-07-19 Thread Martin Uecker via Gcc-patches
Am Mittwoch, dem 19.07.2023 um 15:23 +0100 schrieb Iain Sandoe:
> Hi Martin,
> 
> > On 19 Jul 2023, at 11:43, Martin Uecker via Gcc-patches 
> >  wrote:
> > 
> > Am Mittwoch, dem 19.07.2023 um 10:29 +0100 schrieb Iain Sandoe:
> 
> > > > On 19 Jul 2023, at 10:04, Martin Uecker 
> > > > wrote:
> > > 
> > > > > > On 17 Jul 2023, 
> > > > > 
> > > > 
> > > > > > > You mention setjmp/longjmp - on darwin and other platforms
> > > > > requiring
> > > > > > > non-stack based trampolines
> > > > > > > does the system runtime provide means to deal with this issue
> > > > > > > like
> > > > > an
> > > > > > > alternate allocation method
> > > > > > > or a way to register cleanup?
> > > > > > 
> > > > > > There is an alternate mechanism relying on system libraries
> > > > > > that is
> > > > > possible on darwin specifically (I don’t know for other targets)
> > > > > but
> > > > > it will only work for signed binaries, and would require us to
> > > > > codesign everything produced by gcc. During development, it was
> > > > > deemed too big an ask and the current strategy was chosen (Iain
> > > > > can
> > > > > surely add more background on that if needed).
> > > > > 
> > > > > I do not think that this solves the setjump/longjump issue -
> > > > > since
> > > > > there’s still a notional allocation that takes place (it’s just
> > > > > that
> > > > > the mechanism for determining permissions is different).
> > > > > 
> > > > > It is also a big barrier for the general user - and prevents
> > > > > normal
> > > > > folks from distributing GCC - since codesigning requires an
> > > > > external
> > > > > certificate (i.e. I would really rather avoid it).
> > > > > 
> > > > > > > Was there ever an attempt to provide a "generic" trampoline
> > > > > > > driven
> > > > > by
> > > > > > > a more complex descriptor?
> 
> > > > > > My own opinion is that executable stack should go away on all
> > > > > targets at some point, so a truly generic solution to the problem
> > > > > would be great.
> > > > > 
> > > > > indeed it would.
> > > 
> > > > I think we need a solution rather sooner than later on all archs.
> > > 
> > > AFAICS the  heap-based trampolines can work for any arch**, this
> > > issue is about
> > > system security policy, rather than arch, specifically?
> > > 
> > > It seems to me that for any system security policy that permits JIT,
> > > (but not
> > > executable stack) the heap-based trampolines are viable.
> > 
> > I agree. 
> > 
> > BTW; One option we discussed before, was to map a page with 
> > pre-allocated trampolines, which look up the address of
> > a callee and the static chain in a table based on its own
> > address. Then no code generation is involved.
> 
> That reads similar to the scheme Apple have implemented for libobjc and 
> libffi.
> In order to be extensible (i.e to allow the table to grow at runtime), it 
> means
> having some loadable executable object; if that is implemented in a way shared
> between users (delivered as part of the implementation) then, for Darwin at
> least, it must be codesigned - which is somewhere I really want to avoid going
> with GCC.  
> 
> > The difficult part is avoiding leaks with longjmp / setjmp.
> > One idea was to have a shadow stack consisting of the
> > pre-allocated trampolines, but this probably causes other
> > issues...
> 
> With a per-thread table, I *think* for most targets, we discussed in the team
> maintaining a ’tide mark’ of the stack as part of the saved data in the
> trampoline (not used as part of the execution, but only as part of the 
> allocation
> mangement)… but ..
> 
> > I wonder how difficult it is to have longjmp / setjmp walk 
> > the stack in C?   This would also be useful for C++
> > interoperability and to free  heap-allocated VLAs.
> 
> … this would be a better solution (as we can see trampolines are a small
> leak c.f. the general uses)?
> 
> > As a user of nested functions, from my side it would also 
> &g

Re: [PATCH] core: Support heap-based trampolines

2023-07-19 Thread Martin Uecker via Gcc-patches
Am Mittwoch, dem 19.07.2023 um 10:29 +0100 schrieb Iain Sandoe:
> Hi Martin,
> 
> > On 19 Jul 2023, at 10:04, Martin Uecker 
> > wrote:
> 
> > > > On 17 Jul 2023, 
> > > 
> > 
> > > > > You mention setjmp/longjmp - on darwin and other platforms
> > > requiring
> > > > > non-stack based trampolines
> > > > > does the system runtime provide means to deal with this issue
> > > > > like
> > > an
> > > > > alternate allocation method
> > > > > or a way to register cleanup?
> > > > 
> > > > There is an alternate mechanism relying on system libraries
> > > > that is
> > > possible on darwin specifically (I don’t know for other targets)
> > > but
> > > it will only work for signed binaries, and would require us to
> > > codesign everything produced by gcc. During development, it was
> > > deemed too big an ask and the current strategy was chosen (Iain
> > > can
> > > surely add more background on that if needed).
> > > 
> > > I do not think that this solves the setjump/longjump issue -
> > > since
> > > there’s still a notional allocation that takes place (it’s just
> > > that
> > > the mechanism for determining permissions is different).
> > > 
> > > It is also a big barrier for the general user - and prevents
> > > normal
> > > folks from distributing GCC - since codesigning requires an
> > > external
> > > certificate (i.e. I would really rather avoid it).
> > > 
> > > > > Was there ever an attempt to provide a "generic" trampoline
> > > > > driven
> > > by
> > > > > a more complex descriptor?
> > > 
> > > We did look at the “unused address bits” mechanism that Ada has
> > > used
> > > - but that is not really available to a non-private ABI (unless
> > > the
> > > system vendor agrees to change ABI to leave a bit spare) for the
> > > base
> > > arch either the bits are not there (e.g. X86) or reserved (e.g.
> > > AArch64).
> > > 
> > > Andrew Burgess did the original work he might have comments on
> > > alternatives we tried
> > > 
> > 
> > For reference, I proposed a patch for this in 2018. It was not
> > accepted because minimum alignment for functions would increase
> > for some archs:
> > 
> > https://gcc.gnu.org/legacy-ml/gcc-patches/2018-12/msg01532.html
> 
> Right - that was the one we originally looked at and has the issue
> that it 
> breaks ABI - and thus would need vendor by-in to alter as you say.
> 
> > > > > (well, it could be a bytecode interpreter and the trampoline
> > > > > being
> > > > > bytecode on the stack?!)
> > > > 
> > > > My own opinion is that executable stack should go away on all
> > > targets at some point, so a truly generic solution to the problem
> > > would be great.
> > > 
> > > indeed it would.
> 
> > I think we need a solution rather sooner than later on all archs.
> 
> AFAICS the  heap-based trampolines can work for any arch**, this
> issue is about
> system security policy, rather than arch, specifically?
> 
> It seems to me that for any system security policy that permits JIT,
> (but not
> executable stack) the heap-based trampolines are viable.

I agree. 

BTW; One option we discussed before, was to map a page with 
pre-allocated trampolines, which look up the address of
a callee and the static chain in a table based on its own
address. Then no code generation is involved.

The difficult part is avoiding leaks with longjmp / setjmp.
One idea was to have a shadow stack consisting of the
pre-allocated trampolines, but this probably causes other
issues...

I wonder how difficult it is to have longjmp / setjmp walk 
the stack in C?   This would also be useful for C++
interoperability and to free  heap-allocated VLAs.


As a user of nested functions, from my side it would also 
ok to simply add a wide function pointer type that contains
address + static chain.  This would require changing code, 
but would also work with Clang's blocks and solve other 
language interoperability problems, while avoiding all 
existing ABI issues.

> 
> This seems to be a useful step forward; and we can add some other
> mechanism to the flag’s supported list if someone develops one?

I think it is a useful step forward.

Martin


> 
> Iain
> 
> ** modulo the target maintainers implementing the builtins.
> 
> 
> 



Re: [PATCH] core: Support heap-based trampolines

2023-07-19 Thread Martin Uecker via Gcc-patches



> 
> > On 17 Jul 2023, 
> 

> >> You mention setjmp/longjmp - on darwin and other platforms
> requiring
> >> non-stack based trampolines
> >> does the system runtime provide means to deal with this issue like
> an
> >> alternate allocation method
> >> or a way to register cleanup?
> > 
> > There is an alternate mechanism relying on system libraries that is
> possible on darwin specifically (I don’t know for other targets) but
> it will only work for signed binaries, and would require us to
> codesign everything produced by gcc. During development, it was
> deemed too big an ask and the current strategy was chosen (Iain can
> surely add more background on that if needed).
> 
> I do not think that this solves the setjump/longjump issue - since
> there’s still a notional allocation that takes place (it’s just that
> the mechanism for determining permissions is different).
> 
> It is also a big barrier for the general user - and prevents normal
> folks from distributing GCC - since codesigning requires an external
> certificate (i.e. I would really rather avoid it).
> 
> >> Was there ever an attempt to provide a "generic" trampoline driven
> by
> >> a more complex descriptor?
> 
> We did look at the “unused address bits” mechanism that Ada has used
> - but that is not really available to a non-private ABI (unless the
> system vendor agrees to change ABI to leave a bit spare) for the base
> arch either the bits are not there (e.g. X86) or reserved (e.g.
> AArch64).
> 
> Andrew Burgess did the original work he might have comments on
> alternatives we tried
> 

For reference, I proposed a patch for this in 2018. It was not
accepted because minimum alignment for functions would increase
for some archs:

https://gcc.gnu.org/legacy-ml/gcc-patches/2018-12/msg01532.html



> >> (well, it could be a bytecode interpreter and the trampoline being
> >> bytecode on the stack?!)
> > 
> > My own opinion is that executable stack should go away on all
> targets at some point, so a truly generic solution to the problem
> would be great.
> 
> indeed it would.
> 

I think we need a solution rather sooner than later on all archs.

Martin

> > Having something that works reliably across all targets, like you
> suggest, is a much bigger project that this patch, and I am not aware
> of any previous attempt at it.
> 
> The bytecode interpreter idea is neat;  (a) I wonder about
> performance and (b) it is, as FX says, a bigger project - certainly
> bigger than the voluntary Darwin time available :(
> 
> Iain
> 
> > 
> > 
> >> Otherwise I suggest to split the patch into libgcc, generic and
> target parts.
> > 
> > 
> 




Re: [V1][PATCH 0/3] New attribute "element_count" to annotate bounds for C99 FAM(PR108896)

2023-07-19 Thread Martin Uecker via Gcc-patches
Am Montag, dem 17.07.2023 um 16:40 -0700 schrieb Kees Cook:
> On Mon, Jul 17, 2023 at 09:17:48PM +, Qing Zhao wrote:
> > 
> > > On Jul 13, 2023, at 4:31 PM, Kees Cook 
> > > wrote:
> > > 
> > > In the bug, the problem is that "p" isn't known to be allocated,
> > > if I'm
> > > reading that correctly?
> > 
> > I think that the major point in PR109557
> > (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109557):
> > 
> > for the following pointer p.3_1, 
> > 
> > p.3_1 = p;
> > _2 = __builtin_object_size (p.3_1, 0);
> > 
> > Question: why the size of p.3_1 cannot use the TYPE_SIZE of the
> > pointee of p when the TYPE_SIZE can be determined at compile time?
> > 
> > Answer:  From just knowing the type of the pointee of p, the
> > compiler cannot determine the size of the object.  
> 
> Why is that? "p" points to "struct P", which has a fixed size. There
> must be an assumption somewhere that a pointer is allocated,
> otherwise
> __bos would almost never work?

It often does not work, because it relies on the optimizer
propagating the information instead of the type system.

This is why it would be better to have proper *bounds* checks,
and not just object size checks. It is not quite clear to me
how BOS and bounds checking is supposed to work together,
but FAMs should be bounds checked. 

...

> 
> > 
> > > This may be
> > > desirable in a few situations. One example would be a large
> > > allocation
> > > that is slowly filled up by the program.
> > 
> > So, for such situation, whenever the allocation is filled up, the
> > field that hold the “counted_by” attribute should be increased at
> > the same time,
> > Then, the “counted_by” value always sync with the real allocation. 
> > > I.e. the counted_by member is
> > > slowly increased during runtime (but not beyond the true
> > > allocation size).
> > 
> > Then there should be source code to increase the “counted_by” field
> > whenever the allocated space increased too. 
> > > 
> > > Of course allocation size is only available in limited
> > > situations, so
> > > the loss of that info is fine: we have counted_by for everything
> > > else.
> > 
> > The point is: allocation size should synced with the value of
> > “counted_by”. LLVM’s RFC also have the similar requirement:
> > https://discourse.llvm.org/t/rfc-enforcing-bounds-safety-in-c-fbounds-safety/70854#maintaining-correctness-of-bounds-annotations-18
> 
> Right, I'm saying it would be nice if __alloc_size was checked as
> well,
> in the sense that if it is available, it knows without question what
> the
> size of the allocation is. If __alloc_size and __counted_by conflict,
> the smaller of the two should be the truth.
> 
> But, as I said, if there is some need to explicitly ignore
> __alloc_size
> when __counted_by is present, I can live with it; we just need to
> document it.
> 
> If the RFC and you agree that the __counted_by variable can only ever
> be
> (re)assigned after the flex array has been (re)allocated, then I
> guess
> we'll see how it goes. :) I think most places in the kernel using
> __counted_by will be fine, but I suspect we may have cases where we
> need
> to update it like in the loop I described above. If that's true, we
> can
> revisit the requirement then. :)

It should be the other way round: You should first set
'count' and then reassign the pointer, because you can then
often check the pointer assignment (reading 'count').  The
other way round this works only sometimes, i.e. if both
assignments are close together and the optimizer can see this.



Martin






Re: [V1][PATCH 0/3] New attribute "element_count" to annotate bounds for C99 FAM(PR108896)

2023-07-18 Thread Martin Uecker via Gcc-patches
Am Dienstag, dem 18.07.2023 um 16:25 + schrieb Qing Zhao:
> 
> 
> > On Jul 18, 2023, at 12:03 PM, Martin Uecker 
> > wrote:
> > 
> > Am Dienstag, dem 18.07.2023 um 15:37 + schrieb Qing Zhao:
> > > 
> > > 
> > > > On Jul 17, 2023, at 7:40 PM, Kees Cook 
> > > > wrote:
> > > > 
> > > > On Mon, Jul 17, 2023 at 09:17:48PM +, Qing Zhao wrote:
> > > > > 
> > > > > > On Jul 13, 2023, at 4:31 PM, Kees Cook
> > > > > > 
> > > > > > wrote:
> > > > > > 
> > > > > > In the bug, the problem is that "p" isn't known to be
> > > > > > allocated, if I'm
> > > > > > reading that correctly?
> > > > > 
> > > > > I think that the major point in PR109557
> > > > > (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109557):
> > > > > 
> > > > > for the following pointer p.3_1, 
> > > > > 
> > > > > p.3_1 = p;
> > > > > _2 = __builtin_object_size (p.3_1, 0);
> > > > > 
> > > > > Question: why the size of p.3_1 cannot use the TYPE_SIZE of
> > > > > the
> > > > > pointee of p when the TYPE_SIZE can be determined at compile
> > > > > time?
> > > > > 
> > > > > Answer:  From just knowing the type of the pointee of p, the
> > > > > compiler cannot determine the size of the object.  
> > > > 
> > > > Why is that? "p" points to "struct P", which has a fixed size.
> > > > There
> > > > must be an assumption somewhere that a pointer is allocated,
> > > > otherwise
> > > > __bos would almost never work?
> > > 
> > > My understanding from the comments in PR109557 was: 
> > > 
> > > In general the pointer could point to the first object of an
> > > array
> > > that has more elements, or to an object of a different type. 
> > > Without seeing the real allocation to the pointer, the compiler
> > > cannot assume that the pointer point to an object that has
> > > the exact same type as its declaration. 
> > > 
> > > Sid and Martin, is the above understand correctly?
> > 
> > Yes. 
> > 
> > In the example, it *could* work because the compiler
> > could inline 'store' or otherwise use its knowledge about
> > the function definition to conclude that 'p' points to
> > an object of size 'sizeof (struct P)'. But this is fragile
> > because it relies on optimization and will not work across
> > TUs.
> > 
> > > Honestly, I am still not 100% clear on this yet.
> > 
> > > Jakub, Sid and Martin, could  you please explain a little bit
> > > more
> > > here, especially for the following small example?
> > > 
> > > [opc@qinzhao-ol8u3-x86 109557]$ cat t.c
> > > #include 
> > > #include 
> > > struct P {
> > >   int k;
> > >   int x[10]; 
> > > } *p;
> > > 
> > > void store(int a, int b) 
> > > {
> > >   p = (struct P *)malloc (sizeof (struct P));
> > >   p->k = a;
> > >   p->x[b] = 0;
> > >   assert (__builtin_dynamic_object_size (p->x, 1) == sizeof
> > > (int[10]));
> > >   assert (__builtin_dynamic_object_size (p, 1) == sizeof (struct
> > > P));
> > >   return;
> > > }
> > > 
> > > int main()
> > > {
> > >   store(7, 7);
> > >   assert (__builtin_dynamic_object_size (p->x, 1) == sizeof
> > > (int[10]));
> > >   assert (__builtin_dynamic_object_size (p, 1) == sizeof (struct
> > > P));
> > >   free (p);
> > > }
> > > [opc@qinzhao-ol8u3-x86 109557]$ sh t
> > > /home/opc/Install/latest/bin/gcc -O -fdump-tree-all t.c
> > > a.out: t.c:21: main: Assertion `__builtin_dynamic_object_size (p-
> > > >x,
> > > 1) == sizeof (int[10])' failed.
> > > t: line 19: 859944 Aborted (core dumped) ./a.out
> > > 
> > > 
> > > In the above, among the 4 assertions, only the last one failed.
> > 
> > I don't know why this is the case. 
> > 
> > > 
> > > Why GCC can use the TYPE_SIZE of the pointee of the pointer “p-
> > > >x” as
> > > the size of the object, 
> > 
> > I do not think it can do this in general. Is this 

Re: [V1][PATCH 0/3] New attribute "element_count" to annotate bounds for C99 FAM(PR108896)

2023-07-18 Thread Martin Uecker via Gcc-patches
 struct grows {
> > int alloc_count;
> > int valid_count;
> > struct element item[] __counted_by(valid_count);
> > } *p;
> > 
> > void something(void)
> > {
> > p = malloc(sizeof(*p) + sizeof(*p->item) * 100);
> > p->alloc_count = 100;
> > p->valid_count = 0;
> > 
> > /* this loop doesn't check that we don't go over 100. */
> > while (items_to_copy) {
> > struct element *item_ptr = get_next_item();
> > /* __counted_by stays in sync: */
> > p->valid_count++;
> > p->item[p->valid_count - 1] = *item_ptr;
> > }
> > }
> > 
> > We would want to catch cases there p->item[] is accessed with an
> > index
> > that is >= p->valid_count, even though the allocation is
> > (currently)
> > larger.
> > 
> > However, if we ever reached valid_count >= alloc_count, we need to
> > trap
> > too, since we can still "see" the true allocation size.
> > 
> > Now, the __alloc_size hint is visible in very few places, so if
> > there is
> > a strong reason to do so, I can live with saying that __counted_by
> > takes
> > full precedence over __alloc_size. It seems it should be possible
> > to
> > compare when both are present, but I can live with __counted_by
> > being
> > the universal truth. :)
> > 
> 
> Thanks for the example and the explanation. Understood now.
> 
> LLVM’s RFC requires the following relationship:
> (https://discourse.llvm.org/t/rfc-enforcing-bounds-safety-in-c-fbound
> s-safety/70854#maintaining-correctness-of-bounds-annotations-18)
> 
> Buffer’s real allocated size >= counted_by value
> 
> Should be true all the time. 
> 
> I think that this is a reasonable requirement. 
> 
> (Otherwise, if counted_by > buffer’s real allocated size, overflow
> might happen)
> 
> Is the above enough to cover your use cases?
> 
> If so, I will study a little bit more to see how to implement this.
> > > 
> > > > > or
> > > > > p->foo was not set to any value as in test 3 and 4
> > > > 
> > > > For tests 3 and 4, yes, this was my mistake. I have fixed up
> > > > the tests
> > > > now. Bill noticed the same issue. Sorry for the think-o!
> > > > 
> > > > > 
> > > > > 
> > > > > i.e, the value of p->foo is NOT synced with the number of
> > > > > elements allocated for the array p->array.  
> > > > > 
> > > > > I think that this should be considered as an user error, and
> > > > > the documentation of the attribute should include
> > > > > this requirement.  (In the LLVM’s RFC, such requirement was
> > > > > included in the programing model: 
> > > > > https://discourse.llvm.org/t/rfc-enforcing-bounds-safety-in-c-fbounds-safety/70854#maintaining-correctness-of-bounds-annotations-18
> > > > > )
> > > > > 
> > > > > We can add a new warning option -Wcounted-by to report such
> > > > > user error if needed.
> > > > > 
> > > > > What’s your opinion on this?
> > > > 
> > > > I think it is correct to allow mismatch between allocation and
> > > > counted_by as long as only the least of the two is used.
> > > 
> > > What’s your mean by “only the least of the two is used”?
> > 
> > I was just restating the above: if size information is available
> > via
> > both __alloc_size and __counted_by, the smaller of the two should
> > be
> > used.
> 
> If we are consistent with LLVM’s RFC, __alloc_size >= __counted_by
> all the time.
> Then we can always use the counted_by info for the array size. 
> > 
> > > 
> > > > This may be
> > > > desirable in a few situations. One example would be a large
> > > > allocation
> > > > that is slowly filled up by the program.
> > > 
> > > So, for such situation, whenever the allocation is filled up, the
> > > field that hold the “counted_by” attribute should be increased at
> > > the same time,
> > > Then, the “counted_by” value always sync with the real
> > > allocation. 
> > > > I.e. the counted_by member is
> > > > slowly increased during runtime (but not beyond the true
> > > > allocation size).
> > > 
> > > Then there should be source code to increase the “counted_by”
> > > field whenever the allocated space increased too. 
> > > > 
> > > > Of course allocation size is only available in limited
> > > > situations, so
> > > > the loss of that info is fine: we have counted_by for
> > > > everything else.
> > > 
> > > The point is: allocation size should synced with the value of
> > > “counted_by”. LLVM’s RFC also have the similar requirement:
> > > https://discourse.llvm.org/t/rfc-enforcing-bounds-safety-in-c-fbounds-safety/70854#maintaining-correctness-of-bounds-annotations-18
> > 
> > Right, I'm saying it would be nice if __alloc_size was checked as
> > well,
> > in the sense that if it is available, it knows without question
> > what the
> > size of the allocation is. If __alloc_size and __counted_by
> > conflict,
> > the smaller of the two should be the truth.
> 
> > 
> > But, as I said, if there is some need to explicitly ignore
> > __alloc_size
> > when __counted_by is present, I can live with it; we just need to
> > document it.
> > 
> > If the RFC and you agree that the __counted_by variable can only
> > ever be
> > (re)assigned after the flex array has been (re)allocated, then I
> > guess
> > we'll see how it goes. :) I think most places in the kernel using
> > __counted_by will be fine, but I suspect we may have cases where we
> > need
> > to update it like in the loop I described above. If that's true, we
> > can
> > revisit the requirement then. :)
> 
> I guess if we can always keep  the relationship:   __alloc_size >=
> __counted_by all the time. Should be fine.
> 
> Please check whether this is enough for kernel, I will check whether
> this is doable For GCC.
> 
> thanks.
> 
> 
> Qing
> > 
> > -Kees
> > 
> > -- 
> > Kees Cook
> 

-- 
Univ.-Prof. Dr. rer. nat. Martin Uecker
Graz University of Technology
Institute of Biomedical Imaging




Re: [V1][PATCH 0/3] New attribute "element_count" to annotate bounds for C99 FAM(PR108896)

2023-07-06 Thread Martin Uecker via Gcc-patches
Am Donnerstag, dem 06.07.2023 um 18:56 + schrieb Qing Zhao:
> Hi, Kees,
> 
> I have updated my V1 patch with the following changes:
> A. changed the name to "counted_by"
> B. changed the argument from a string to an identifier
> C. updated the documentation and testing cases accordingly.
> 
> And then used this new gcc to test 
> https://github.com/kees/kernel-tools/blob/trunk/fortify/array-bounds.c (with 
> the following change)
> [opc@qinzhao-ol8u3-x86 Kees]$ !1091
> diff array-bounds.c array-bounds.c.org
> 32c32
> < # define __counted_by(member)   __attribute__((counted_by (member)))
> ---
> > # define __counted_by(member)   
> > __attribute__((__element_count__(#member)))
> 34c34
> < # define __counted_by(member)   __attribute__((counted_by (member)))
> ---
> > # define __counted_by(member)   /* 
> > __attribute__((__element_count__(#member))) */
> 
> Then I got the following result:
> [opc@qinzhao-ol8u3-x86 Kees]$ ./array-bounds 2>&1 | grep -v ^'#'
> TAP version 13
> 1..12
> ok 1 global.fixed_size_seen_by_bdos
> ok 2 global.fixed_size_enforced_by_sanitizer
> not ok 3 global.unknown_size_unknown_to_bdos
> not ok 4 global.unknown_size_ignored_by_sanitizer
> ok 5 global.alloc_size_seen_by_bdos
> ok 6 global.alloc_size_enforced_by_sanitizer
> not ok 7 global.element_count_seen_by_bdos
> ok 8 global.element_count_enforced_by_sanitizer
> not ok 9 global.alloc_size_with_smaller_element_count_seen_by_bdos
> not ok 10 global.alloc_size_with_smaller_element_count_enforced_by_sanitizer
> ok 11 global.alloc_size_with_bigger_element_count_seen_by_bdos
> ok 12 global.alloc_size_with_bigger_element_count_enforced_by_sanitizer
> 
> The same as your previous results. Then I took a look at all the failed 
> testing: 3, 4, 7, 9, and 10. And studied the reasons for all of them.
> 
>  in a summary, there are two major issues:
> 1.  The reason for the failed testing 7 is the same issue as I observed in 
> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=109557
> Which is not a bug, it’s an expected behavior. 
> 
> 2. The common issue for  the failed testing 3, 4, 9, 10 is:
> 
> for the following annotated structure: 
> 
> 
> struct annotated {
> unsigned long flags;
> size_t foo;
> int array[] __attribute__((counted_by (foo)));
> };
> 
> 
> struct annotated *p;
> int index = 16;
> 
> p = malloc(sizeof(*p) + index * sizeof(*p->array));  // allocated real size 
> 
> p->foo = index + 2;  // p->foo was set by a different value than the real 
> size of p->array as in test 9 and 10
> or
> p->foo was not set to any value as in test 3 and 4
> 
> 
> 
> i.e, the value of p->foo is NOT synced with the number of elements allocated 
> for the array p->array.  
> 
> I think that this should be considered as an user error, and the 
> documentation of the attribute should include
> this requirement.  (In the LLVM’s RFC, such requirement was included in the 
> programing model: 
> https://discourse.llvm.org/t/rfc-enforcing-bounds-safety-in-c-fbounds-safety/70854#maintaining-correctness-of-bounds-annotations-18)
> 
> We can add a new warning option -Wcounted-by to report such user error if 
> needed.
> 
> What’s your opinion on this?


Additionally, we could also have a sanitizer that
checks this at run-time.


Personally, I am still not very happy that in the
following example the two 'n's refer to different
entities:

void f(int n)
{
struct foo {
int n;   
int (*p[])[n] [[counted_by(n)]];
};
}

But I guess it will be difficult to convince everybody
that it would be wise to use a new syntax for
disambiguation:

void f(int n)
{
struct foo {
int n;   
int (*p[])[n] [[counted_by(.n)]];
};
}

Martin


> 
> thanks.
> 
> Qing
> 
> 
> > On May 26, 2023, at 4:40 PM, Kees Cook  wrote:
> > 
> > On Thu, May 25, 2023 at 04:14:47PM +, Qing Zhao wrote:
> > > GCC will pass the number of elements info from the attached attribute to 
> > > both 
> > > __builtin_dynamic_object_size and bounds sanitizer to check the 
> > > out-of-bounds
> > > or dynamic object size issues during runtime for flexible array members.
> > > 
> > > This new feature will provide nice protection to flexible array members 
> > > (which
> > > currently are completely ignored by both __builtin_dynamic_object_size and
> > > bounds sanitizers).
> > 
> > Testing went pretty well, though I think I found some bdos issues:
> > 
> > - some things that bdos can't know the size of, and correctly returned
> >  SIZE_MAX in the past, now thinks are 0-sized.
> > - while bdos correctly knows the size of an element_count-annotated
> >  flexible array, it doesn't know the size of the containing object
> >  (i.e. it returns SIZE_MAX).
> > 
> > Also, I think I found a precedence issue:
> > 
> > - if both __alloc_size and 'element_count' are in use, the _smallest_
> >  of the two is what I would expect to be enforced by the sanitizer
> >  and reported by __bdos. As is, alloc_size appears to be used when
> >  

Re: [V1][PATCH 1/3] Provide element_count attribute to flexible array member field (PR108896)

2023-06-16 Thread Martin Uecker via Gcc-patches
Am Freitag, dem 16.06.2023 um 16:21 + schrieb Joseph Myers:
> On Fri, 16 Jun 2023, Martin Uecker via Gcc-patches wrote:
> 
> > > Note that no expressions can start with the '.' token at present.  As 
> > > soon 
> > > as you invent a new kind of expression that can start with that token, 
> > > you 
> > > have syntactic ambiguity.
> > > 
> > > struct s1 { int c; char a[(struct s2 { int c; char b[.c]; }) {.c=.c}.c]; 
> > > };
> > > 
> > > Is ".c=.c" a use of the existing syntax for designated initializers, with 
> > > the first ".c" being a designator and the second being a use of the new 
> > > kind of expression, or is it an assignment expression, where both the LHS 
> > > and the RHS of the assignment use the new kind of expression?  And do 
> > > those .c, when the use the new kind of expression, refer to the inner or 
> > > outer struct definition?
> > 
> > I would treat this is one integrated feature. Essentially .c is
> > somthing like this->c for the current struct for designated
> > initializer *and* size expressions because it is semantically 
> > so close.In the initializer I would allow only 
> > the current use for designated initialization for all names of
> > member of the currently initialized struct,  so .c = .c would 
> > be invalid.   It should never refer to the outer struct if there
> 
> I'm not clear on what the intended disambiguation rule here is, when "." 
> is seen in initializer list context - does this rule depend on whether the 
> following identifier is a member of the struct being initialized, so 
> ".c=.c" would be OK above if the initialized struct didn't have a member 
> called c but the outer struct definition did? 

When initializers are parsed it is already clear what
the names of the members of the inner struct are, so
one can differentiate between designated initializers 
and potential other uses in an expression. 

So the main rule is: if you parse .something in a context
where a designator is allowed and "something" is a member
of the current struct, then it is a designator.

So for 

struct foo { int c; int buf[(struct { int d; }){ .d = .c }]; };

one knows during parsing that the .d is a designator
and that .c is not. For

struct foo { int c; int buf[(struct { int d; }){ .c = .c }]; };

one knows that both uses of .c are not.

Whether these different use cases should be allowed or not
is a different question, but my point is that there does
not seem to be a problem directly identifying the uses 
as a designator as usual. To me, this seems to imply that
it is safe to use the same syntax.

>  That seems like a rather 
> messy rule.  And does "would allow only" apply other than in the ambiguous 
> context?  That seems to be implied by ".c=.c" being invalid above, because 
> to make it invalid you need to disallow the new construct being used for 
> the second .c, not just make the first .c interpreted as a designator.

Yes. 
> 
> Again, this sort of thing needs a detailed written specification, with 
> multiple iterations discussed among different implementations. 

Oh, I agree with this.

>  The above 
> paragraph doesn't make clear to me any of: the disambiguation rules; what 
> is allowed in what context; how name lookup works (consider tricky cases 
> such as a reference to an identifier declared *later* in the same struct, 
> possibly in the context of C2x tag compatibility where a previous 
> definition of the struct is visible); when these expressions get 
> evaluated; what the underlying principles are behind those choices.

I also agree that all this needs careful consideration and written
rules.  My point is mereley that there does not seem to be a
fundamental issue differentiating the new feature from 
designators during parsing, so there may not be a risk using 
the same syntax.

> Using a token (existing or new) other than '.' - one that doesn't 
> introduce ambiguity in any context where expressions can be used - would 
> help significantly, although some of the issues would still apply.

The cost of using a new symbol is that one has two different
syntax for something which is semantically equivalent, i.e.
a notion to refer to a member of the current struct.

Martin

> 




Re: [V1][PATCH 1/3] Provide element_count attribute to flexible array member field (PR108896)

2023-06-16 Thread Martin Uecker via Gcc-patches
Am Donnerstag, dem 15.06.2023 um 16:55 + schrieb Joseph Myers:
> On Thu, 15 Jun 2023, Qing Zhao via Gcc-patches wrote:
> 
...
> > 1. Update the routine “c_parser_postfix_expression” (is this the right 
> > place? ) to accept the new designator syntax.
> 
> Any design that might work with an expression is the sort of thing that 
> would likely involve many iterations on the specification (i.e. proposed 
> wording changes to the C standard) for the interpretation of the new kinds 
> of expressions, including how to resolve syntactic ambiguities and how 
> name lookup works, before it could be considered ready to implement, and 
> then a lot more work on the specification based on implementation 
> experience.
> 
> Note that no expressions can start with the '.' token at present.  As soon 
> as you invent a new kind of expression that can start with that token, you 
> have syntactic ambiguity.
> 
> struct s1 { int c; char a[(struct s2 { int c; char b[.c]; }) {.c=.c}.c]; };
> 
> Is ".c=.c" a use of the existing syntax for designated initializers, with 
> the first ".c" being a designator and the second being a use of the new 
> kind of expression, or is it an assignment expression, where both the LHS 
> and the RHS of the assignment use the new kind of expression?  And do 
> those .c, when the use the new kind of expression, refer to the inner or 
> outer struct definition?

I would treat this is one integrated feature. Essentially .c is
somthing like this->c for the current struct for designated
initializer *and* size expressions because it is semantically 
so close.In the initializer I would allow only 
the current use for designated initialization for all names of
member of the currently initialized struct,  so .c = .c would 
be invalid.   It should never refer to the outer struct if there
is a member with the same name in the inner struct, i.e. the
outside member is then hidden. 

So this would be ok:

struct s1 { int d; char a[(struct s2 { int c; char b[.c]; }) {.c=.d}.c]; };

Here the use of .d would be ok because it is not from the struct
currently initialized, but from an outside scope.

Martin






Re: [RFC] Add stdckdint.h header for C23

2023-06-11 Thread Martin Uecker via Gcc-patches


Hi Jakup,

two comments which may or may not be helpful:

Clang extended _Generic in a similar way:
https://github.com/llvm/llvm-project/commit/12728e144994efe84715f4e5dbb8c3104e9f0b5a

Although for _Generic you can achieve the same with checking
for compatiblilty of pointer to the type, and I do not think
this helps with the classification problem.


If I am not missing something, you should be able to check
for an enumerated type using _Generic by checking that the
type is not compatible to another enum type:

enum type_check { _X = 1 };

#define type_is_enum(x) \
_Generic(x, unsigned int: _Generic(x, enum type_check: 0, default: 1), 
default: 0)

https://godbolt.org/z/j6z4a4Mdn

For C23 with fixed underlying type this may become more
complicated. Maybe this becomes to messy.

Martin





Re: [C PATCH 3/4] introduce ubsan checking for assigment of VM types 3/4

2023-05-31 Thread Martin Uecker via Gcc-patches
Am Dienstag, dem 30.05.2023 um 22:59 + schrieb Joseph Myers:
> On Mon, 29 May 2023, Martin Uecker via Gcc-patches wrote:
> 
> >     Support instrumentation of function arguments for functions
> >     called via a declaration.  We can support only simple size
> 
> What do you mean by "via a declaration"?
> 
> If the *definition* is visible (and known to be the definition used
> at runtime rather than being interposed) then you can determine in
> some cases  that there is UB from bad bounds.  If only some other
> declaration is visible, or the definition might be interposed, VLA
> sizes in the declaration are equivalent to [*]; it's suspicious if
> they don't match, but it's not UB and so it would seem rather
> questionable for UBSan to treat it as such (cf. the rejection in 
> GCC of sanitization for some questionable cases of unsigned integer
> overflow that aren't UB either).

You are right that it is UB only with the additional
assumption that the bounds in the seen declaration are
the same as the ones in the definition.   But we now warn
about any mismatch since GCC 11 with -Wall based on the
understanding  that any such mismatch should be considered
a bug. There also does not seem  to be any valid use case
for having mismatching bounds and I think the intention 
of WG14 is clearly that they can be used for checking 
(cf. WG14 charter). So I think this is a different
situation for unsigned integer overflow.

Fom a practial point of view is is certainly very useful 
for users to be able to verify these bounds at run-time. 
But we could make it a separate UBSan option if it is
really a concern.

BTW: There was a similar discussion years ago about making
certain bound checks for arrays part of UBSan because it is
not clear that the bounds in the type of 'x' in x[n] are
relevant rather than the ones of the underlying array
(which may be different).  In the end both GCC and clang
have these UBSan checks now and I think  everybody is
happy about it.


> > + /*  Give up.  If we do not understand a size expression,
> > we can
> > + also not instrument any of the others because it may
> > have
> > + side effects affecting them.  (We could restart and
> > instrument
> > + the only the ones with integer constants.)   */
> > +   warning_at (location, 0, "Function call not
> > instrumented.");
> > +   return void_node;
> 
> This is not a properly formatted diagnostic message (should start
> with a 
> lowercase letter and not end with '.').

Thanks. I would probably remove this warning and re-introduce it
with another patch that also adds an option fir it.

Martin







Re: [C PATCH 3/4] introduce ubsan checking for assigment of VM types 3/4

2023-05-29 Thread Martin Uecker via Gcc-patches



c: introduce ubsan checking for assigment of VM types 3/4

Support instrumentation of function arguments for functions
called via a declaration.  We can support only simple size
expressions without side effects, because the UBSan
instrumentation is done before the call, but the expressions
are evaluated in the callee.

gcc/c-family:
* c-ubsan.cc (ubsan_instrument_vm_assign): Add arguments
for size expressions.
* c-ubsan.h (ubsan_instrument_vm_assign): Dito.

gcc/c:
* c-typeck.cc (process_vm_constraints): Add support
for instrumenting function arguments.

gcc/testsuide/gcc.dg:
* ubsan/vm-bounds-2.c: Update.
* ubsan/vm-bounds-3.c: New test.
* ubsan/vm-bounds-4.c: New test.

diff --git a/gcc/c-family/c-ubsan.cc b/gcc/c-family/c-ubsan.cc
index 59ef9708188..a8f95aa39e8 100644
--- a/gcc/c-family/c-ubsan.cc
+++ b/gcc/c-family/c-ubsan.cc
@@ -337,19 +337,13 @@ ubsan_instrument_vla (location_t loc, tree size)
 /* Instrument assignment of variably modified types.  */
 
 tree
-ubsan_instrument_vm_assign (location_t loc, tree a, tree b)
+ubsan_instrument_vm_assign (location_t loc, tree a, tree as, tree b, tree bs)
 {
   tree t, tt;
 
   gcc_assert (TREE_CODE (a) == ARRAY_TYPE);
   gcc_assert (TREE_CODE (b) == ARRAY_TYPE);
 
-  tree as = TYPE_MAX_VALUE (TYPE_DOMAIN (a));
-  tree bs = TYPE_MAX_VALUE (TYPE_DOMAIN (b));
-
-  as = fold_build2 (PLUS_EXPR, sizetype, as, size_one_node);
-  bs = fold_build2 (PLUS_EXPR, sizetype, bs, size_one_node);
-
   t = build2 (NE_EXPR, boolean_type_node, as, bs);
   if (flag_sanitize_trap & SANITIZE_VLA)
 tt = build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_TRAP), 0);
diff --git a/gcc/c-family/c-ubsan.h b/gcc/c-family/c-ubsan.h
index 1b07b0645f2..42be1d691a8 100644
--- a/gcc/c-family/c-ubsan.h
+++ b/gcc/c-family/c-ubsan.h
@@ -26,7 +26,7 @@ extern tree ubsan_instrument_shift (location_t, enum 
tree_code, tree, tree);
 extern tree ubsan_instrument_vla (location_t, tree);
 extern tree ubsan_instrument_return (location_t);
 extern tree ubsan_instrument_bounds (location_t, tree, tree *, bool);
-extern tree ubsan_instrument_vm_assign (location_t, tree, tree);
+extern tree ubsan_instrument_vm_assign (location_t, tree, tree, tree, tree);
 extern bool ubsan_array_ref_instrumented_p (const_tree);
 extern void ubsan_maybe_instrument_array_ref (tree *, bool);
 extern void ubsan_maybe_instrument_reference (tree *);
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index a8fccc6f6ed..aeddac315fc 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -3408,7 +3408,8 @@ static tree
 convert_argument (location_t ploc, tree function, tree fundecl,
  tree type, tree origtype, tree val, tree valtype,
  bool npc, tree rname, int parmnum, int argnum,
- bool excess_precision, int warnopt)
+ bool excess_precision, int warnopt,
+ vec *instr_vec)
 {
   /* Formal parm type is specified by a function prototype.  */
 
@@ -3567,7 +3568,7 @@ convert_argument (location_t ploc, tree function, tree 
fundecl,
val, origtype, ic_argpass,
npc, fundecl, function,
parmnum + 1, warnopt,
-   NULL);
+   instr_vec);
 
   if (targetm.calls.promote_prototypes (fundecl ? TREE_TYPE (fundecl) : 0)
   && INTEGRAL_TYPE_P (type)
@@ -3582,15 +3583,111 @@ convert_argument (location_t ploc, tree function, tree 
fundecl,
 
 static tree
 process_vm_constraints (location_t location,
-   vec *instr_vec)
+   vec *instr_vec,
+   tree function, tree fundecl, vec *values)
 {
   unsigned int i;
   struct instrument_data* d;
   tree instr_expr = void_node;
+  tree args = NULL;
+
+  /* Find the arguments for the function declaration / type.  */
+  if (function)
+{
+  if (FUNCTION_DECL == TREE_CODE (function))
+   {
+ fundecl = function;
+ args = DECL_ARGUMENTS (fundecl);
+   }
+  else
+   {
+ /* Functions called via pointers are not yet supported.  */
+ return void_node;
+   }
+}
 
   FOR_EACH_VEC_SAFE_ELT (instr_vec, i, d)
 {
-  tree in = ubsan_instrument_vm_assign (location, d->t1, d->t2);
+  tree t1 = d->t1;
+  tree t2 = d->t2;
+
+  gcc_assert (ARRAY_TYPE == TREE_CODE (t1));
+  gcc_assert (ARRAY_TYPE == TREE_CODE (t2));
+
+  tree as = TYPE_MAX_VALUE (TYPE_DOMAIN (t1));
+  tree bs = TYPE_MAX_VALUE (TYPE_DOMAIN (t2));
+
+  gcc_assert (as);
+  gcc_assert (bs);
+
+  as = fold_build2 (PLUS_EXPR, sizetype, as, size_one_node);
+  bs = fold_build2 (PLUS_EXPR, sizetype, bs, size_one_node);
+
+   

Re: [C PATCH 2/4] introduce ubsan checking for assigment of VM types 2/4

2023-05-29 Thread Martin Uecker via Gcc-patches



c: introduce ubsan checking for assigment of VM types 2/4

When checking compatibility of types during assignment, collect
all pairs of types where the outermost bound needs to match at
run-time.  This list is then processed to add UBSan checks for
each bound.

gcc/c-family:
* c-ubsan.cc (ubsan_instrument_vm_assign): New function.
* c-ubsan.h (ubsan_instrument_vm_assign: New function.

gcc/c:
* c-typeck.cc (struct instrument_data). New structure.
(comp_target_types_instr convert_for_assignment_instrument): New
interfaces for existing functions.
(struct comptypes_data): Add instrumentation.
(comptypes_check_enum_int_intr): New interface.
(comptypes_check_enum_int): Old interface (calls new).
(comptypes_internal): Collect VLA types needed for UBSan.
(comp_target_types_instr): New interface.
(comp_target_types): Old interface (calls new).
(function_types_compatible_p): No instrumentation for function
arguments.
(process_vm_constraints): New function.
(convert_for_assignment_instrument): New interface.
(convert_for_assignment): Instrument assignments.
* sanitizer.def: Add sanitizer builtins.

gcc/testsuite:
* gcc.dg/ubsan/vm-bounds-1.c: New test.
* gcc.dg/ubsan/vm-bounds-1b.c: New test.
* gcc.dg/ubsan/vm-bounds-2.c: New test.

libsanitizer/ubsan:
* ubsan_checks.inc: Add UBSan check.
* ubsan_handlers.cpp (handleVMBoundsMismatch): New function.
* ubsan_handlers.h (struct VMBoundsMismatchData): New structure.
(vm_bounds_mismatch): New handler.

diff --git a/gcc/c-family/c-ubsan.cc b/gcc/c-family/c-ubsan.cc
index 51aa83a378d..59ef9708188 100644
--- a/gcc/c-family/c-ubsan.cc
+++ b/gcc/c-family/c-ubsan.cc
@@ -334,6 +334,48 @@ ubsan_instrument_vla (location_t loc, tree size)
   return t;
 }
 
+/* Instrument assignment of variably modified types.  */
+
+tree
+ubsan_instrument_vm_assign (location_t loc, tree a, tree b)
+{
+  tree t, tt;
+
+  gcc_assert (TREE_CODE (a) == ARRAY_TYPE);
+  gcc_assert (TREE_CODE (b) == ARRAY_TYPE);
+
+  tree as = TYPE_MAX_VALUE (TYPE_DOMAIN (a));
+  tree bs = TYPE_MAX_VALUE (TYPE_DOMAIN (b));
+
+  as = fold_build2 (PLUS_EXPR, sizetype, as, size_one_node);
+  bs = fold_build2 (PLUS_EXPR, sizetype, bs, size_one_node);
+
+  t = build2 (NE_EXPR, boolean_type_node, as, bs);
+  if (flag_sanitize_trap & SANITIZE_VLA)
+tt = build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_TRAP), 0);
+  else
+{
+  tree data = ubsan_create_data ("__ubsan_vm_data", 1, &loc,
+ubsan_type_descriptor (a, 
UBSAN_PRINT_ARRAY),
+ubsan_type_descriptor (b, 
UBSAN_PRINT_ARRAY),
+ubsan_type_descriptor (sizetype),
+NULL_TREE, NULL_TREE);
+  data = build_fold_addr_expr_loc (loc, data);
+  enum built_in_function bcode
+   = (flag_sanitize_recover & SANITIZE_VLA)
+ ? BUILT_IN_UBSAN_HANDLE_VM_BOUNDS_MISMATCH
+ : BUILT_IN_UBSAN_HANDLE_VM_BOUNDS_MISMATCH_ABORT;
+  tt = builtin_decl_explicit (bcode);
+  tt = build_call_expr_loc (loc, tt, 3, data,
+   ubsan_encode_value (as),
+   ubsan_encode_value (bs));
+}
+  t = build3 (COND_EXPR, void_type_node, t, tt, void_node);
+
+  return t;
+}
+
+
 /* Instrument missing return in C++ functions returning non-void.  */
 
 tree
diff --git a/gcc/c-family/c-ubsan.h b/gcc/c-family/c-ubsan.h
index fef1033e1e4..1b07b0645f2 100644
--- a/gcc/c-family/c-ubsan.h
+++ b/gcc/c-family/c-ubsan.h
@@ -26,6 +26,7 @@ extern tree ubsan_instrument_shift (location_t, enum 
tree_code, tree, tree);
 extern tree ubsan_instrument_vla (location_t, tree);
 extern tree ubsan_instrument_return (location_t);
 extern tree ubsan_instrument_bounds (location_t, tree, tree *, bool);
+extern tree ubsan_instrument_vm_assign (location_t, tree, tree);
 extern bool ubsan_array_ref_instrumented_p (const_tree);
 extern void ubsan_maybe_instrument_array_ref (tree *, bool);
 extern void ubsan_maybe_instrument_reference (tree *);
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 2a1b7321b45..a8fccc6f6ed 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -94,6 +94,9 @@ struct comptypes_data;
 static int tagged_types_tu_compatible_p (const_tree, const_tree,
 struct comptypes_data *);
 static int comp_target_types (location_t, tree, tree);
+struct instrument_data;
+static int comp_target_types_instr (location_t, tree, tree,
+   vec *);
 static int function_types_compatible_p (const_tree, const_tree,
struct comptypes_data *);

Re: [C PATCH 4/4] introduce ubsan checking for assigment of VM types 4/4

2023-05-29 Thread Martin Uecker via Gcc-patches





c: introduce ubsan checking for assigment of VM types 4/4

Support instrumentation of functions called via pointers.  To do so,
record the declaration with the parameter types, so that it can be
retrieved later.

gcc/c:
c-decl.cc (get_parm_info): Record function declaration
for arguments.
c-type.cc (process_vm_constraints): Instrument functions
called via pointers.

gcc/testsuide/gcc.dg:
* ubsan/vm-bounds-2.c: Add warning.
* ubsan/vm-bounds-5.c: New test.

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 1af51c4acfc..c33adf7e5fe 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -8410,6 +8410,9 @@ get_parm_info (bool ellipsis, tree expr)
 declared types.  The back end may override this later.  */
  DECL_ARG_TYPE (decl) = type;
  types = tree_cons (0, type, types);
+
+ /* Record the decl for use of UBSan bounds checking.  */
+ TREE_PURPOSE (types) = decl;
}
  break;
 
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index aeddac315fc..43e7b96a55f 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -3601,9 +3601,20 @@ process_vm_constraints (location_t location,
}
   else
{
- /* Functions called via pointers are not yet supported.  */
- return void_node;
+ while (FUNCTION_TYPE != TREE_CODE (function))
+   function = TREE_TYPE (function);
+
+ args = TREE_PURPOSE (TYPE_ARG_TYPES (function));
+
+ if (!args)
+   {
+ /* FIXME: this can happen when forming composite types for the
+conditional operator.  */
+ warning_at (location, 0, "Function call not instrumented.");
+ return void_node;
+   }
}
+  gcc_assert (PARM_DECL == TREE_CODE (args));
 }
 
   FOR_EACH_VEC_SAFE_ELT (instr_vec, i, d)
diff --git a/gcc/testsuite/gcc.dg/ubsan/vm-bounds-2.c 
b/gcc/testsuite/gcc.dg/ubsan/vm-bounds-2.c
index 22f06231eaa..093cbddd2ea 100644
--- a/gcc/testsuite/gcc.dg/ubsan/vm-bounds-2.c
+++ b/gcc/testsuite/gcc.dg/ubsan/vm-bounds-2.c
@@ -31,7 +31,7 @@ void f(void)
 
int u = 3; int v = 4;
char a[u][v];
-   (1 ? f1 : f2)(u, v, a);
+   (1 ? f1 : f2)(u, v, a); /* { dg-warning "Function call not 
instrumented." } */
 }
 
 /* size expression in parameter */
diff --git a/gcc/testsuite/gcc.dg/ubsan/vm-bounds-5.c 
b/gcc/testsuite/gcc.dg/ubsan/vm-bounds-5.c
new file mode 100644
index 000..1a251e39deb
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ubsan/vm-bounds-5.c
@@ -0,0 +1,72 @@
+/* { dg-do run } */
+/* { dg-options "-fsanitize=vla-bound" } */
+
+
+void foo1(void (*p)(int n, char (*a)[n]))
+{
+   char A0[3];
+   (*p)(3, &A0);
+   (*p)(4, &A0);   /* */
+   /* { dg-output "bound 4 of type 'char \\\[\\\*\\\]' does not match 
bound 3 of type 'char \\\[3\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+}
+
+void b0(int n, char (*a)[n]) { }
+
+
+int n;
+
+void foo2(void (*p)(int n, char (*a)[n]))
+{
+   n = 4;
+   char A0[3];
+   (*p)(3, &A0);
+   (*p)(4, &A0);
+   /* { dg-output "\[^\n\r]*bound 4 of type 'char \\\[\\\*\\\]' does not 
match bound 3 of type 'char \\\[3\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+}
+
+void foo3(void (*p)(int n0, char (*a)[n]))
+{
+   n = 4;
+   char A0[3];
+   (*p)(3, &A0);   /* */
+   /* { dg-output "\[^\n\r]*bound 4 of type 'char \\\[\\\*\\\]' does not 
match bound 3 of type 'char \\\[3\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+   (*p)(4, &A0);   /* */
+   /* { dg-output "\[^\n\r]*bound 4 of type 'char \\\[\\\*\\\]' does not 
match bound 3 of type 'char \\\[3\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+}
+
+void foo4(void (*p)(int n, char (*a)[n]))
+{
+   n = 3;
+   char A0[3];
+   (*p)(3, &A0);
+   (*p)(4, &A0);   /* */
+   /* { dg-output "\[^\n\r]*bound 4 of type 'char \\\[\\\*\\\]' does not 
match bound 3 of type 'char \\\[3\\\]'" } */
+}
+
+
+void foo5(void (*p)(int n0, char (*a)[n]))
+{
+   n = 3;
+   char A0[3];
+   (*p)(3, &A0);
+   (*p)(4, &A0);
+}
+
+
+void b1(int n0, char (*a)[n]) { }
+
+
+
+int main()
+{
+   foo1(&b0);
+
+   foo2(&b1);
+   foo3(&b1); // we should diagnose mismatch and run-time discrepancies
+
+   foo4(&b1);
+   foo5(&b1); // we should diagnose mismatch and run-time discrepancies
+}
+
+
+




[C PATCH 1/4] introduce ubsan checking for assigment of VM types 1/4

2023-05-29 Thread Martin Uecker via Gcc-patches


Hi Joseph and Martin,

this series adds UBSan checking for assignment of variably-modified
types, i.e. it checks that size expressions on both sides of the 
assignment match.

1. no functional change, adds a structure argument to the
comptypes family functions in the C FE.

2. checking for all assignments except function arguments
including the libsanitizer changes (no upstream discussion so far)

3. checking for function arguments, but only when the function is
referenced using its declaration.

4. checking for functions called via a pointer


Q1: Should this be -fsanitize=vla-bound ? I used it because it is
related and does not have much functionality.

Q2: I now have warnings when a function can not be instrumented
because size expressions are too complicated or information was
lost before. Probably this needs to have a flag.

Martin



c: introduce ubsan checking for assigment of VM types 1/4

Reorganize recursive type checking to use a structure to
store information collected during the recursion and
returned to the caller (enum_and_init_p, different_types_p).

gcc/c:
* c-typeck.cc (struct comptypes_data): Add structure.
(tagged_types_tu_compatible_p,
function_types_compatible_p, type_lists_compatible_p,
comptyes_internal): Add structure to interface and
adapt calls.
(comptypes, comptypes_check_enum_int,
comptypes_check_different_types): Adapt calls.

diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 22e240a3c2a..2a1b7321b45 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -90,12 +90,14 @@ static bool require_constant_elements;
 static bool require_constexpr_value;
 
 static tree qualify_type (tree, tree);
-static int tagged_types_tu_compatible_p (const_tree, const_tree, bool *,
-bool *);
+struct comptypes_data;
+static int tagged_types_tu_compatible_p (const_tree, const_tree,
+struct comptypes_data *);
 static int comp_target_types (location_t, tree, tree);
-static int function_types_compatible_p (const_tree, const_tree, bool *,
-   bool *);
-static int type_lists_compatible_p (const_tree, const_tree, bool *, bool *);
+static int function_types_compatible_p (const_tree, const_tree,
+   struct comptypes_data *);
+static int type_lists_compatible_p (const_tree, const_tree,
+   struct comptypes_data *);
 static tree lookup_field (tree, tree);
 static int convert_arguments (location_t, vec, tree,
  vec *, vec *, tree,
@@ -125,7 +127,8 @@ static tree find_init_member (tree, struct obstack *);
 static void readonly_warning (tree, enum lvalue_use);
 static int lvalue_or_else (location_t, const_tree, enum lvalue_use);
 static void record_maybe_used_decl (tree);
-static int comptypes_internal (const_tree, const_tree, bool *, bool *);
+static int comptypes_internal (const_tree, const_tree,
+  struct comptypes_data *data);
 
 /* Return true if EXP is a null pointer constant, false otherwise.  */
 
@@ -1039,6 +1042,12 @@ common_type (tree t1, tree t2)
   return c_common_type (t1, t2);
 }
 
+struct comptypes_data {
+
+  bool enum_and_int_p;
+  bool different_types_p;
+};
+
 /* Return 1 if TYPE1 and TYPE2 are compatible types for assignment
or various other operations.  Return 2 if they are compatible
but a warning may be needed if you use them together.  */
@@ -1049,7 +1058,9 @@ comptypes (tree type1, tree type2)
   const struct tagged_tu_seen_cache * tagged_tu_seen_base1 = 
tagged_tu_seen_base;
   int val;
 
-  val = comptypes_internal (type1, type2, NULL, NULL);
+  struct comptypes_data data = { };
+  val = comptypes_internal (type1, type2, &data);
+
   free_all_tagged_tu_seen_up_to (tagged_tu_seen_base1);
 
   return val;
@@ -1064,7 +1075,10 @@ comptypes_check_enum_int (tree type1, tree type2, bool 
*enum_and_int_p)
   const struct tagged_tu_seen_cache * tagged_tu_seen_base1 = 
tagged_tu_seen_base;
   int val;
 
-  val = comptypes_internal (type1, type2, enum_and_int_p, NULL);
+  struct comptypes_data data = { };
+  val = comptypes_internal (type1, type2, &data);
+  *enum_and_int_p = data.enum_and_int_p;
+
   free_all_tagged_tu_seen_up_to (tagged_tu_seen_base1);
 
   return val;
@@ -1080,7 +1094,10 @@ comptypes_check_different_types (tree type1, tree type2,
   const struct tagged_tu_seen_cache * tagged_tu_seen_base1 = 
tagged_tu_seen_base;
   int val;
 
-  val = comptypes_internal (type1, type2, NULL, different_types_p);
+  struct comptypes_data data = { };
+  val = comptypes_internal (type1, type2, &data);
+  *different_types_p = data.different_types_p;
+
   free_all_tagged_tu_seen_up_to (tagged_tu_seen_base1);
 
   return val;
@@ -1089,19 +1106,18 @@ comptypes_check_different_types (tree type1, tree type2,
 /* Return 1 if TYPE1 and TYPE

Re: [V1][PATCH 2/3] Use the element_count atribute info in builtin object size [PR108896].

2023-05-27 Thread Martin Uecker via Gcc-patches


Thank you for working on this!


Here are a couple of comments:

How is the size for an object with FAM defined? 

There are at least three possible choices:

offset(..) + N * sizeof
sizeof(..) + N * sizeof
or the size of a struct with the replacement array.

Or is this not relevant here?


I would personally prefer an attribute which does
not use a string, but uses C expressions, so that
one could write something like this (although I would
limit it initially to the most simple case) 

struct {
  struct bar { int n; }* ptr;
  int buf[] [[element_count(.ptr->n + 3)]];
};

Of course, we could still support this later even
if we use a string now.

Martin




Am Donnerstag, dem 25.05.2023 um 16:14 + schrieb Qing Zhao:
> 2023-05-17 Qing Zhao 
> 
> gcc/ChangeLog:
> 
>   PR C/108896
>   * tree-object-size.cc (addr_object_size): Use the element_count
>   attribute info.
>   * tree.cc (component_ref_has_element_count_p): New function.
>   (component_ref_get_element_count): New function.
>   * tree.h (component_ref_has_element_count_p): New prototype.
>   (component_ref_get_element_count): New prototype.
> 
> gcc/testsuite/ChangeLog:
> 
>   PR C/108896
>   * gcc.dg/flex-array-element-count-2.c: New test.
> ---
>  .../gcc.dg/flex-array-element-count-2.c   | 56 +++
>  gcc/tree-object-size.cc   | 37 ++--
>  gcc/tree.cc   | 93 +++
>  gcc/tree.h| 10 ++
>  4 files changed, 189 insertions(+), 7 deletions(-)
>  create mode 100644 gcc/testsuite/gcc.dg/flex-array-element-count-2.c
> 
> diff --git a/gcc/testsuite/gcc.dg/flex-array-element-count-2.c 
> b/gcc/testsuite/gcc.dg/flex-array-element-count-2.c
> new file mode 100644
> index 000..5a280e8c731
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/flex-array-element-count-2.c
> @@ -0,0 +1,56 @@
> +/* test the attribute element_count and its usage in
> + * __builtin_dynamic_object_size.  */ 
> +/* { dg-do run } */
> +/* { dg-options "-O2" } */
> +
> +#include "builtin-object-size-common.h"
> +
> +#define expect(p, _v) do { \
> +size_t v = _v; \
> +if (p == v) \
> + __builtin_printf ("ok:  %s == %zd\n", #p, p); \
> +else \
> + {  \
> +   __builtin_printf ("WAT: %s == %zd (expected %zd)\n", #p, p, v); \
> +   FAIL (); \
> + } \
> +} while (0);
> +
> +struct flex {
> +  int b;
> +  int c[];
> +} *array_flex;
> +
> +struct annotated {
> +  int b;
> +  int c[] __attribute__ ((element_count ("b")));
> +} *array_annotated;
> +
> +void __attribute__((__noinline__)) setup (int normal_count, int attr_count)
> +{
> +  array_flex
> += (struct flex *)malloc (sizeof (struct flex)
> ++ normal_count *  sizeof (int));
> +  array_flex->b = normal_count;
> +
> +  array_annotated
> += (struct annotated *)malloc (sizeof (struct annotated)
> + + attr_count *  sizeof (int));
> +  array_annotated->b = attr_count;
> +
> +  return;
> +}
> +
> +void __attribute__((__noinline__)) test ()
> +{
> +expect(__builtin_dynamic_object_size(array_flex->c, 1), -1);
> +expect(__builtin_dynamic_object_size(array_annotated->c, 1),
> +array_annotated->b * sizeof (int));
> +}
> +
> +int main(int argc, char *argv[])
> +{
> +  setup (10,10);   
> +  test ();
> +  DONE ();
> +}
> diff --git a/gcc/tree-object-size.cc b/gcc/tree-object-size.cc
> index 9a936a91983..f9aadd59054 100644
> --- a/gcc/tree-object-size.cc
> +++ b/gcc/tree-object-size.cc
> @@ -585,6 +585,7 @@ addr_object_size (struct object_size_info *osi, 
> const_tree ptr,
>    if (pt_var != TREE_OPERAND (ptr, 0))
>  {
>    tree var;
> +  tree element_count_ref = NULL_TREE;
>  
> 
>    if (object_size_type & OST_SUBOBJECT)
>   {
> @@ -600,11 +601,12 @@ addr_object_size (struct object_size_info *osi, 
> const_tree ptr,
>   var = TREE_OPERAND (var, 0);
>     if (var != pt_var && TREE_CODE (var) == ARRAY_REF)
>   var = TREE_OPERAND (var, 0);
> -   if (! TYPE_SIZE_UNIT (TREE_TYPE (var))
> +   if (! component_ref_has_element_count_p (var)
> +  && ((! TYPE_SIZE_UNIT (TREE_TYPE (var))
>     || ! tree_fits_uhwi_p (TYPE_SIZE_UNIT (TREE_TYPE (var)))
>     || (pt_var_size && TREE_CODE (pt_var_size) == INTEGER_CST
>     && tree_int_cst_lt (pt_var_size,
> -   TYPE_SIZE_UNIT (TREE_TYPE (var)
> +   TYPE_SIZE_UNIT (TREE_TYPE (var)))
>   var = pt_var;
>     else if (var != pt_var && TREE_CODE (pt_var) == MEM_REF)
>   {
> @@ -612,6 +614,7 @@ addr_object_size (struct object_size_info *osi, 
> const_tree ptr,
>     /* For &X->fld, compute object size if fld isn't a flexible array
>    member.  */
>     bool is_flexible_array_mem_ref = false;
> +
>     while (v && v != pt_var)
>  

[C PATCH] -Wstringop-overflow for parameters with forward-declared sizes

2023-05-26 Thread Martin Uecker via Gcc-patches


This is a minor change so that parameter that have
forward declarations for with -Wstringop-overflow.


Bootstrapped and regression tested on x86_64. 



c: -Wstringop-overflow for parameters with forward-declared sizes

Warnings from -Wstringop-overflow do not appear for parameters declared
as VLAs when the bound refers to a parameter forward declaration. This
is fixed by splitting the loop that passes through parameters into two,
first only recording the positions of all possible size expressions
and then processing the parameters.

PR c/109970

gcc/c-family:

* c-attribs.cc (build_attr_access_from_parms): Split loop to first
record all parameters.

gcc/testsuite:

* gcc.dg/pr109970.c: New test.

diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc
index 072cfb69147..e2792ca6898 100644
--- a/gcc/c-family/c-attribs.cc
+++ b/gcc/c-family/c-attribs.cc
@@ -5278,6 +5278,15 @@ build_attr_access_from_parms (tree parms, bool 
skip_voidptr)
   tree argtype = TREE_TYPE (arg);
   if (DECL_NAME (arg) && INTEGRAL_TYPE_P (argtype))
arg2pos.put (arg, argpos);
+}
+
+  argpos = 0;
+  for (tree arg = parms; arg; arg = TREE_CHAIN (arg), ++argpos)
+{
+  if (!DECL_P (arg))
+   continue;
+
+  tree argtype = TREE_TYPE (arg);
 
   tree argspec = DECL_ATTRIBUTES (arg);
   if (!argspec)
diff --git a/gcc/testsuite/gcc.dg/pr109970.c b/gcc/testsuite/gcc.dg/pr109970.c
new file mode 100644
index 000..d234e10455f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr109970.c
@@ -0,0 +1,15 @@
+/* PR109970
+ * { dg-do compile }
+ * { dg-options "-Wstringop-overflow" }
+ * */
+
+void bar(int x, char buf[x]);
+void foo(int x; char buf[x], int x);
+
+int main()
+{
+   char buf[10];
+   bar(11, buf);   /* { dg-warning "accessing 11 bytes in a region of size 
10" } */
+   foo(buf, 11);   /* { dg-warning "accessing 11 bytes in a region of size 
10" } */
+}
+




Re: [committed] testsuite: Require trampolines for nestev-vla tests

2023-05-25 Thread Martin Uecker via Gcc-patches


Thanks! I will try to not forget this next time.

Am Donnerstag, dem 25.05.2023 um 21:20 +0300 schrieb Dimitar Dimitrov:
> Three recent test cases declare nested C functions, so they fail on
> targets lacking support for trampolines. Fix by adding the necessary
> filter.
> 
> Committed as obvious.
> 
> gcc/testsuite/ChangeLog:
> 
>   * gcc.dg/nested-vla-1.c: Require effective target trampolines.
>   * gcc.dg/nested-vla-2.c: Ditto.
>   * gcc.dg/nested-vla-3.c: Ditto.
> 
> CC: Martin Uecker 
> Signed-off-by: Dimitar Dimitrov 
> ---
>  gcc/testsuite/gcc.dg/nested-vla-1.c | 1 +
>  gcc/testsuite/gcc.dg/nested-vla-2.c | 1 +
>  gcc/testsuite/gcc.dg/nested-vla-3.c | 1 +
>  3 files changed, 3 insertions(+)
> 
> diff --git a/gcc/testsuite/gcc.dg/nested-vla-1.c 
> b/gcc/testsuite/gcc.dg/nested-vla-1.c
> index 5b62c2c213a..d1b3dc3c5f8 100644
> --- a/gcc/testsuite/gcc.dg/nested-vla-1.c
> +++ b/gcc/testsuite/gcc.dg/nested-vla-1.c
> @@ -1,5 +1,6 @@
>  /* { dg-do run } */
>  /* { dg-options "-std=gnu99" } */
> +/* { dg-require-effective-target trampolines } */
>  
> 
>  
> 
>  int main()
> diff --git a/gcc/testsuite/gcc.dg/nested-vla-2.c 
> b/gcc/testsuite/gcc.dg/nested-vla-2.c
> index d83c90a0b16..294b01d370e 100644
> --- a/gcc/testsuite/gcc.dg/nested-vla-2.c
> +++ b/gcc/testsuite/gcc.dg/nested-vla-2.c
> @@ -1,5 +1,6 @@
>  /* { dg-do run } */
>  /* { dg-options "-std=gnu99" } */
> +/* { dg-require-effective-target trampolines } */
>  
> 
>  
> 
>  int main()
> diff --git a/gcc/testsuite/gcc.dg/nested-vla-3.c 
> b/gcc/testsuite/gcc.dg/nested-vla-3.c
> index 1ffb482da3b..d2ba04adab8 100644
> --- a/gcc/testsuite/gcc.dg/nested-vla-3.c
> +++ b/gcc/testsuite/gcc.dg/nested-vla-3.c
> @@ -1,5 +1,6 @@
>  /* { dg-do run } */
>  /* { dg-options "-std=gnu99" } */
> +/* { dg-require-effective-target trampolines } */
>  
> 
>  
> 
>  int main()




Re: [C PATCH v3] Fix ICEs related to VM types in C 2/2

2023-05-23 Thread Martin Uecker via Gcc-patches
Am Dienstag, dem 23.05.2023 um 10:18 +0200 schrieb Richard Biener:
> On Tue, May 23, 2023 at 8:24 AM Martin Uecker 
> wrote:
> > 
> > Am Dienstag, dem 23.05.2023 um 08:13 +0200 schrieb Richard Biener:
> > > On Mon, May 22, 2023 at 7:24 PM Martin Uecker via Gcc-patches
> > >  wrote:
> > > > 
> > > > 
> > > > 
> > > > This version contains the middle-end changes for PR109450
> > > > and test cases as before.  The main middle-end change is that
> > > > we use gimplify_type_sizes also for parameters and remove
> > > > the special code that also walked into pointers (which is
> > > > incorrect).
> > > > 
> > > > In addition, in the C FE this patch now also adds DECL_EXPR
> > > > for vm-types which are pointed-to by parameters declared
> > > > as arrays.  The new function created contains the exact
> > > > code previously used only for regular pointers, and is
> > > > now also called for parameters declared as arrays.
> > > > 
> > > > 
> > > > Martin
> > > > 
> > > > 
> > > > 
> > > > 
> > > > 
> > > > 
> > > > 
> > > >     Fix ICEs related to VM types in C 2/2 [PR109450]
> > > > 
> > > >     Size expressions were sometimes lost and not gimplified
> > > > correctly,
> > > >     leading to ICEs and incorrect evaluation order.  Fix this
> > > > by 1) not
> > > >     recursing pointers when gimplifying parameters in the
> > > > middle-end
> > > >     (the code is merged with gimplify_type_sizes), which is
> > > > incorrect
> > > >     because it might access variables declared later for
> > > > incomplete
> > > >     structs, and 2) adding a decl expr for variably-modified
> > > > arrays
> > > >     that are pointed to by parameters declared as arrays.
> > > > 
> > > >     PR c/109450
> > > > 
> > > >     gcc/
> > > >     * c/c-decl.cc (add_decl_expr): New function.
> > > >     (grokdeclarator): Add decl expr for size expression
> > > > in
> > > >     types pointed to by parameters declared as arrays.
> > > >     * function.cc (gimplify_parm_type): Remove
> > > > function.
> > > >     (gimplify_parameters): Call gimplify_parm_sizes.
> > > >     * gimplify.cc (gimplify_type_sizes): Make function
> > > > static.
> > > >     (gimplify_parm_sizes): New function.
> > > > 
> > > >     gcc/testsuite/
> > > >     * gcc.dg/pr109450-1.c: New test.
> > > >     * gcc.dg/pr109450-2.c: New test.
> > > >     * gcc.dg/vla-26.c: New test.
> > > > 
> > > > diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
> > > > index 494d3cf1747..c35347734b2 100644
> > > > --- a/gcc/c/c-decl.cc
> > > > +++ b/gcc/c/c-decl.cc
> > > > @@ -6490,6 +6490,55 @@ smallest_type_quals_location (const
> > > > location_t *locations,
> > > >    return loc;
> > > >  }
> > > > 
> > > > +
> > > > +/* We attach an artificial TYPE_DECL to pointed-to type
> > > > +   and arrange for it to be included in a DECL_EXPR.  This
> > > > +   forces the sizes evaluation at a safe point and ensures it
> > > > +   is not deferred until e.g. within a deeper conditional
> > > > context.
> > > > +
> > > > +   PARM contexts have no enclosing statement list that
> > > > +   can hold the DECL_EXPR, so we need to use a BIND_EXPR
> > > > +   instead, and add it to the list of expressions that
> > > > +   need to be evaluated.
> > > > +
> > > > +   TYPENAME contexts do have an enclosing statement list,
> > > > +   but it would be incorrect to use it, as the size should
> > > > +   only be evaluated if the containing expression is
> > > > +   evaluated.  We might also be in the middle of an
> > > > +   expression with side effects on the pointed-to type size
> > > > +   "arguments" prior to the pointer declaration point and
> > > > +   the fake TYPE_DECL in the enclosing context would force
> > > > +   the size evaluation prior to the side effects.  We
> > > > therefore
> > &

Re: [C PATCH v3] Fix ICEs related to VM types in C 2/2

2023-05-22 Thread Martin Uecker via Gcc-patches
Am Dienstag, dem 23.05.2023 um 08:13 +0200 schrieb Richard Biener:
> On Mon, May 22, 2023 at 7:24 PM Martin Uecker via Gcc-patches
>  wrote:
> > 
> > 
> > 
> > This version contains the middle-end changes for PR109450
> > and test cases as before.  The main middle-end change is that
> > we use gimplify_type_sizes also for parameters and remove
> > the special code that also walked into pointers (which is
> > incorrect).
> > 
> > In addition, in the C FE this patch now also adds DECL_EXPR
> > for vm-types which are pointed-to by parameters declared
> > as arrays.  The new function created contains the exact
> > code previously used only for regular pointers, and is
> > now also called for parameters declared as arrays.
> > 
> > 
> > Martin
> > 
> > 
> > 
> > 
> > 
> > 
> > 
> > Fix ICEs related to VM types in C 2/2 [PR109450]
> > 
> > Size expressions were sometimes lost and not gimplified correctly,
> > leading to ICEs and incorrect evaluation order.  Fix this by 1) not
> > recursing pointers when gimplifying parameters in the middle-end
> > (the code is merged with gimplify_type_sizes), which is incorrect
> > because it might access variables declared later for incomplete
> > structs, and 2) adding a decl expr for variably-modified arrays
> > that are pointed to by parameters declared as arrays.
> > 
> > PR c/109450
> > 
> > gcc/
> > * c/c-decl.cc (add_decl_expr): New function.
> > (grokdeclarator): Add decl expr for size expression in
> > types pointed to by parameters declared as arrays.
> > * function.cc (gimplify_parm_type): Remove function.
> > (gimplify_parameters): Call gimplify_parm_sizes.
> > * gimplify.cc (gimplify_type_sizes): Make function static.
> > (gimplify_parm_sizes): New function.
> > 
> > gcc/testsuite/
> > * gcc.dg/pr109450-1.c: New test.
> > * gcc.dg/pr109450-2.c: New test.
> > * gcc.dg/vla-26.c: New test.
> > 
> > diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
> > index 494d3cf1747..c35347734b2 100644
> > --- a/gcc/c/c-decl.cc
> > +++ b/gcc/c/c-decl.cc
> > @@ -6490,6 +6490,55 @@ smallest_type_quals_location (const location_t 
> > *locations,
> >    return loc;
> >  }
> > 
> > +
> > +/* We attach an artificial TYPE_DECL to pointed-to type
> > +   and arrange for it to be included in a DECL_EXPR.  This
> > +   forces the sizes evaluation at a safe point and ensures it
> > +   is not deferred until e.g. within a deeper conditional context.
> > +
> > +   PARM contexts have no enclosing statement list that
> > +   can hold the DECL_EXPR, so we need to use a BIND_EXPR
> > +   instead, and add it to the list of expressions that
> > +   need to be evaluated.
> > +
> > +   TYPENAME contexts do have an enclosing statement list,
> > +   but it would be incorrect to use it, as the size should
> > +   only be evaluated if the containing expression is
> > +   evaluated.  We might also be in the middle of an
> > +   expression with side effects on the pointed-to type size
> > +   "arguments" prior to the pointer declaration point and
> > +   the fake TYPE_DECL in the enclosing context would force
> > +   the size evaluation prior to the side effects.  We therefore
> > +   use BIND_EXPRs in TYPENAME contexts too.  */
> > +static void
> > +add_decl_expr(location_t loc, enum decl_context decl_context, tree type, 
> > tree *expr)
> > +{
> > +  tree bind = NULL_TREE;
> > +  if (decl_context == TYPENAME || decl_context == PARM || decl_context == 
> > FIELD)
> > +{
> > +  bind = build3 (BIND_EXPR, void_type_node, NULL_TREE, NULL_TREE, 
> > NULL_TREE);
> > +  TREE_SIDE_EFFECTS (bind) = 1;
> > +  BIND_EXPR_BODY (bind) = push_stmt_list ();
> > +  push_scope ();
> > +}
> > +
> > +  tree decl = build_decl (loc, TYPE_DECL, NULL_TREE, type);
> > +  pushdecl (decl);
> > +  DECL_ARTIFICIAL (decl) = 1;
> > +  add_stmt (build_stmt (DECL_SOURCE_LOCATION (decl), DECL_EXPR, decl));
> > +  TYPE_NAME (type) = decl;
> > +
> > +  if (bind)
> > +{
> > +  pop_scope ();
> > +  BIND_EXPR_BODY (bind) = pop_stmt_list (BIND_EXPR_BODY (bind));
> > +  if (*expr)
> > +   *expr = build2 (COMPOUND_EXPR, void_type_node, *expr, bind);
> > +  else
> 

[C PATCH v3] Fix ICEs related to VM types in C 2/2

2023-05-22 Thread Martin Uecker via Gcc-patches



This version contains the middle-end changes for PR109450
and test cases as before.  The main middle-end change is that
we use gimplify_type_sizes also for parameters and remove
the special code that also walked into pointers (which is
incorrect).  

In addition, in the C FE this patch now also adds DECL_EXPR
for vm-types which are pointed-to by parameters declared
as arrays.  The new function created contains the exact
code previously used only for regular pointers, and is
now also called for parameters declared as arrays.


Martin







Fix ICEs related to VM types in C 2/2 [PR109450]

Size expressions were sometimes lost and not gimplified correctly,
leading to ICEs and incorrect evaluation order.  Fix this by 1) not
recursing pointers when gimplifying parameters in the middle-end
(the code is merged with gimplify_type_sizes), which is incorrect
because it might access variables declared later for incomplete
structs, and 2) adding a decl expr for variably-modified arrays
that are pointed to by parameters declared as arrays.

PR c/109450

gcc/
* c/c-decl.cc (add_decl_expr): New function.
(grokdeclarator): Add decl expr for size expression in
types pointed to by parameters declared as arrays.
* function.cc (gimplify_parm_type): Remove function.
(gimplify_parameters): Call gimplify_parm_sizes.
* gimplify.cc (gimplify_type_sizes): Make function static.
(gimplify_parm_sizes): New function.

gcc/testsuite/
* gcc.dg/pr109450-1.c: New test.
* gcc.dg/pr109450-2.c: New test.
* gcc.dg/vla-26.c: New test.

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 494d3cf1747..c35347734b2 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -6490,6 +6490,55 @@ smallest_type_quals_location (const location_t 
*locations,
   return loc;
 }
 
+
+/* We attach an artificial TYPE_DECL to pointed-to type
+   and arrange for it to be included in a DECL_EXPR.  This
+   forces the sizes evaluation at a safe point and ensures it
+   is not deferred until e.g. within a deeper conditional context.
+
+   PARM contexts have no enclosing statement list that
+   can hold the DECL_EXPR, so we need to use a BIND_EXPR
+   instead, and add it to the list of expressions that
+   need to be evaluated.
+
+   TYPENAME contexts do have an enclosing statement list,
+   but it would be incorrect to use it, as the size should
+   only be evaluated if the containing expression is
+   evaluated.  We might also be in the middle of an
+   expression with side effects on the pointed-to type size
+   "arguments" prior to the pointer declaration point and
+   the fake TYPE_DECL in the enclosing context would force
+   the size evaluation prior to the side effects.  We therefore
+   use BIND_EXPRs in TYPENAME contexts too.  */
+static void
+add_decl_expr(location_t loc, enum decl_context decl_context, tree type, tree 
*expr)
+{
+  tree bind = NULL_TREE;
+  if (decl_context == TYPENAME || decl_context == PARM || decl_context == 
FIELD)
+{
+  bind = build3 (BIND_EXPR, void_type_node, NULL_TREE, NULL_TREE, 
NULL_TREE);
+  TREE_SIDE_EFFECTS (bind) = 1;
+  BIND_EXPR_BODY (bind) = push_stmt_list ();
+  push_scope ();
+}
+
+  tree decl = build_decl (loc, TYPE_DECL, NULL_TREE, type);
+  pushdecl (decl);
+  DECL_ARTIFICIAL (decl) = 1;
+  add_stmt (build_stmt (DECL_SOURCE_LOCATION (decl), DECL_EXPR, decl));
+  TYPE_NAME (type) = decl;
+
+  if (bind)
+{
+  pop_scope ();
+  BIND_EXPR_BODY (bind) = pop_stmt_list (BIND_EXPR_BODY (bind));
+  if (*expr)
+   *expr = build2 (COMPOUND_EXPR, void_type_node, *expr, bind);
+  else
+   *expr = bind;
+}
+}
+
 /* Given declspecs and a declarator,
determine the name and type of the object declared
and construct a ..._DECL node for it.
@@ -7474,58 +7523,9 @@ grokdeclarator (const struct c_declarator *declarator,
 
   This is expected to happen automatically when the pointed-to
   type has a name/declaration of it's own, but special attention
-  is required if the type is anonymous.
-
-  We attach an artificial TYPE_DECL to such pointed-to type
-  and arrange for it to be included in a DECL_EXPR.  This
-  forces the sizes evaluation at a safe point and ensures it
-  is not deferred until e.g. within a deeper conditional context.
-
-  PARM contexts have no enclosing statement list that
-  can hold the DECL_EXPR, so we need to use a BIND_EXPR
-  instead, and add it to the list of expressions that
-  need to be evaluated.
-
-  TYPENAME contexts do have an enclosing statement list,
-  but it would be incorrect to use it, as the size should
-  only be evaluated if the containing expression is
-  

[C PATCH v3] Fix ICEs related to VM types in C 1/2

2023-05-22 Thread Martin Uecker via Gcc-patches


Hi Joseph,

I had to create another revision of the patch because of some
case I had overlooked (vm-types pointed-to by parameters
declared as I arrays).  I splitted the patch up in two parts
for easier reviewing.  The first part only has the FE changes
and most of the tests.  The only minor change is that I replaced
a bug number because there was a duplicate and that I added
the specific example from this bug report (PR70418) as another
test. Since this half of the patch was already reviewed, I will
commit it tomorrow if there are no comments.

The second part contains the middle-end changes and the new
FE fix you haven't seen.

Both patches bootstrapped and regression tested on x86. 


Martin







Fix ICEs related to VM types in C 1/2 [PR70418, PR107557, PR108423]

Size expressions were sometimes lost and not gimplified correctly, leading 
to
ICEs and incorrect evaluation order.  Fix this by 1) not recursing into
pointers when gimplifying parameters in the middle-end (the code is merged 
with
gimplify_type_sizes), which is incorrect because it might access variables
declared later for incomplete structs, and 2) tracking size expressions for
struct/union members correctly, 3) emitting code to evaluate size 
expressions
for missing cases (nested functions, empty declarations, and 
structs/unions).

PR c/70418
PR c/106465
PR c/107557
PR c/108423

gcc/
* c/c-decl.cc (start_decl): Make sure size expression are
evaluated only in correct context.
(grokdeclarator): Size expression in fields may need a bind
expression, make sure DECL_EXPR is always created.
(grokfield, declspecs_add_type): Pass along size expressions.
(finish_struct): Remove unneeded DECL_EXPR.
(start_function): Evaluate size expressions for nested functions.
* c/c-parser.cc (c_parser_struct_declarations,
c_parser_struct_or_union_specifier): Pass along size expressions.
(c_parser_declaration_or_fndef): Evaluate size expression.
(c_parser_objc_at_property_declaration,
c_parser_objc_class_instance_variables): Adapt.

gcc/testsuite/
* gcc.dg/nested-vla-1.c: New test.
* gcc.dg/nested-vla-2.c: New test.
* gcc.dg/nested-vla-3.c: New test.
* gcc.dg/pr70418.c: New test.
* gcc.dg/pr106465.c: New test.
* gcc.dg/pr107557-1.c: New test.
* gcc.dg/pr107557-2.c: New test.
* gcc.dg/pr108423-1.c: New test.
* gcc.dg/pr108423-2.c: New test.
* gcc.dg/pr108423-3.c: New test.
* gcc.dg/pr108423-4.c: New test.
* gcc.dg/pr108423-5.c: New test.
* gcc.dg/pr108423-6.c: New test.
* gcc.dg/typename-vla-2.c: New test.
* gcc.dg/typename-vla-3.c: New test.
* gcc.dg/typename-vla-4.c: New test.
* gcc.misc-tests/gcov-pr85350.c: Adapt.

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 94ce760b55e..494d3cf1747 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -5364,7 +5364,8 @@ start_decl (struct c_declarator *declarator, struct 
c_declspecs *declspecs,
 if (lastdecl != error_mark_node)
   *lastloc = DECL_SOURCE_LOCATION (lastdecl);
 
-  if (expr)
+  /* Make sure the size expression is evaluated at this point.  */
+  if (expr && !current_scope->parm_flag)
 add_stmt (fold_convert (void_type_node, expr));
 
   if (TREE_CODE (decl) != FUNCTION_DECL && MAIN_NAME_P (DECL_NAME (decl))
@@ -7498,7 +7499,8 @@ grokdeclarator (const struct c_declarator *declarator,
&& c_type_variably_modified_p (type))
  {
tree bind = NULL_TREE;
-   if (decl_context == TYPENAME || decl_context == PARM)
+   if (decl_context == TYPENAME || decl_context == PARM
+   || decl_context == FIELD)
  {
bind = build3 (BIND_EXPR, void_type_node, NULL_TREE,
   NULL_TREE, NULL_TREE);
@@ -7507,10 +7509,11 @@ grokdeclarator (const struct c_declarator *declarator,
push_scope ();
  }
tree decl = build_decl (loc, TYPE_DECL, NULL_TREE, type);
-   DECL_ARTIFICIAL (decl) = 1;
pushdecl (decl);
-   finish_decl (decl, loc, NULL_TREE, NULL_TREE, NULL_TREE);
+   DECL_ARTIFICIAL (decl) = 1;
+   add_stmt (build_stmt (DECL_SOURCE_LOCATION (decl), DECL_EXPR, 
decl));
TYPE_NAME (type) = decl;
+
if (bind)
  {
pop_scope ();
@@ -8709,7 +8712,7 @@ start_struct (location_t loc, enum tree_code code, tree 
name,
 tree
 grokfield (location_t loc,
   struct c_declarator *declarator, struct c_declspecs *declspecs,
-  tree wid

[C PATCH] Remove dead code related to type compatibility across TUs.

2023-05-19 Thread Martin Uecker via Gcc-patches


Repost for stage 1.


C: Remove dead code related to type compatibility across TUs.

Code to detect struct/unions across the same TU is not needed
anymore. Code for determining compatibility of tagged types is
preserved as it will be used for C2X. Some errors in the unused
code are fixed.

Bootstrapped with no regressions for x86_64-pc-linux-gnu.

gcc/c/
* c-decl.cc (set_type_context): Remove.
(pop_scope, diagnose_mismatched_decls, pushdecl):
Remove dead code.
* c-typeck.cc (comptypes_internal): Remove dead code.
(same_translation_unit_p): Remove.
(tagged_types_tu_compatible_p): Some fixes.

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index f63c1108ab5..70345b4b019 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -1155,16 +1155,6 @@ update_label_decls (struct c_scope *scope)
 }
 }
 
-/* Set the TYPE_CONTEXT of all of TYPE's variants to CONTEXT.  */
-
-static void
-set_type_context (tree type, tree context)
-{
-  for (type = TYPE_MAIN_VARIANT (type); type;
-   type = TYPE_NEXT_VARIANT (type))
-TYPE_CONTEXT (type) = context;
-}
-
 /* Exit a scope.  Restore the state of the identifier-decl mappings
that were in effect when this scope was entered.  Return a BLOCK
node containing all the DECLs in this scope that are of interest
@@ -1253,7 +1243,6 @@ pop_scope (void)
case ENUMERAL_TYPE:
case UNION_TYPE:
case RECORD_TYPE:
- set_type_context (p, context);
 
  /* Types may not have tag-names, in which case the type
 appears in the bindings list with b->id NULL.  */
@@ -1364,12 +1353,7 @@ pop_scope (void)
 the TRANSLATION_UNIT_DECL.  This makes same_translation_unit_p
 work.  */
  if (scope == file_scope)
-   {
  DECL_CONTEXT (p) = context;
- if (TREE_CODE (p) == TYPE_DECL
- && TREE_TYPE (p) != error_mark_node)
-   set_type_context (TREE_TYPE (p), context);
-   }
 
  gcc_fallthrough ();
  /* Parameters go in DECL_ARGUMENTS, not BLOCK_VARS, and have
@@ -2318,21 +2302,18 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
{
  if (DECL_INITIAL (olddecl))
{
- /* If both decls are in the same TU and the new declaration
-isn't overriding an extern inline reject the new decl.
-In c99, no overriding is allowed in the same translation
-unit.  */
- if ((!DECL_EXTERN_INLINE (olddecl)
-  || DECL_EXTERN_INLINE (newdecl)
-  || (!flag_gnu89_inline
-  && (!DECL_DECLARED_INLINE_P (olddecl)
-  || !lookup_attribute ("gnu_inline",
-DECL_ATTRIBUTES (olddecl)))
-  && (!DECL_DECLARED_INLINE_P (newdecl)
-  || !lookup_attribute ("gnu_inline",
-DECL_ATTRIBUTES (newdecl
- )
- && same_translation_unit_p (newdecl, olddecl))
+ /* If the new declaration isn't overriding an extern inline
+reject the new decl. In c99, no overriding is allowed
+in the same translation unit.  */
+ if (!DECL_EXTERN_INLINE (olddecl)
+ || DECL_EXTERN_INLINE (newdecl)
+ || (!flag_gnu89_inline
+ && (!DECL_DECLARED_INLINE_P (olddecl)
+ || !lookup_attribute ("gnu_inline",
+   DECL_ATTRIBUTES (olddecl)))
+ && (!DECL_DECLARED_INLINE_P (newdecl)
+ || !lookup_attribute ("gnu_inline",
+   DECL_ATTRIBUTES (newdecl)
{
  auto_diagnostic_group d;
  error ("redefinition of %q+D", newdecl);
@@ -3360,18 +3341,11 @@ pushdecl (tree x)
 type to the composite of all the types of that declaration.
 After the consistency checks, it will be reset to the
 composite of the visible types only.  */
-  if (b && (TREE_PUBLIC (x) || same_translation_unit_p (x, b->decl))
- && b->u.type)
+  if (b && b->u.type)
TREE_TYPE (b->decl) = b->u.type;
 
-  /* The point of the same_translation_unit_p check here is,
-we want to detect a duplicate decl for a construct like
-foo() { extern bar(); } ... static bar();  but not if
-they are in different translation units.  In any case,
-the static does not go in the externals scope.  */
-  if (b
- && (TREE_PUBLIC (x) || same_translation_unit_p (x, b->decl))
- && duplicate_decls (x, b->decl))
+  /* the static does not go in the externals scope.  */
+  if (b && duplicate_decls (x, b->decl))
   

[C PATCH v2] Fix ICEs related to VM types in C [PR106465, PR107557, PR108423, PR109450]

2023-05-19 Thread Martin Uecker via Gcc-patches


Thanks Joseph! 

Revised version attached. Ok?


But I wonder whether we generally need to do something 
about

  sizeof *x

when x is NULL or not initialized. This is quite commonly
used in C code and if the type is not of variable size,
it is also unproblematic.  So the UB for variable size is
unfortunate and certainly also affects existing code in
the wild.  In practice it does not seem to cause
problems because there is no lvalue conversion and this
then seems to work.  Maybe we document this as an 
extension?  (and make sure in the C FE that it
works)  This would also make this idiom valid:

char (*buf)[n] = malloc(sizeof *buf);

Or if we do not want to do this, then I think we should
add some warnings (and UBSan check for null pointer)
which currently do not exist:

https://godbolt.org/z/fhWMKvYc8

Martin




Am Donnerstag, dem 18.05.2023 um 21:46 + schrieb Joseph Myers:
> On Thu, 18 May 2023, Martin Uecker via Gcc-patches wrote:
> 
> > +  /* we still have to evaluate size expressions */
> 
> Comments should start with a capital letter and end with ".  ".
> 
> > diff --git a/gcc/testsuite/gcc.dg/nested-vla-1.c 
> > b/gcc/testsuite/gcc.dg/nested-vla-1.c
> > new file mode 100644
> > index 000..408a68524d8
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.dg/nested-vla-1.c
> > @@ -0,0 +1,37 @@
> > +/* { dg-do run } */
> > +/* { dg-options "-std=gnu99" } */
> 
> I'm concerned with various undefined behavior in this and other tests; 
> they look very fragile, relying on some optimizations and not others 
> taking place.  I think they should be adjusted to avoid undefined behavior 
> if all the evaluations from the abstract machine (in particular, of sizeof 
> operands with variable size) take place, and other undefined behavior from 
> calling functions through function pointers with incompatible type.
> 
> > +   struct bar { char x[++n]; } (*bar2)(void) = bar;/* { dg-warning 
> > "incompatible pointer type" } */
> > +
> > +   if (2 != n)
> > +   __builtin_abort();
> > +
> > +   if (2 != sizeof((*bar2)()))
> > +   __builtin_abort();
> 
> You're relying on the compiler not noticing that a function is being 
> called through an incompatible type and thus not turning the call (which 
> should be evaluated, because the operand of sizeof has a type with 
> variable size) into a call to abort.
> 
> > diff --git a/gcc/testsuite/gcc.dg/nested-vla-2.c 
> > b/gcc/testsuite/gcc.dg/nested-vla-2.c
> > new file mode 100644
> > index 000..504eec48c80
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.dg/nested-vla-2.c
> > @@ -0,0 +1,33 @@
> > +/* { dg-do run } */
> > +/* { dg-options "-std=gnu99" } */
> > +
> > +
> > +int main()
> > +{
> > +   int n = 1;
> > +
> > +   typeof(char (*)[++n]) bar(void) { }
> > +
> > +   if (2 != n)
> > +   __builtin_abort();
> > +
> > +   if (2 != sizeof(*bar()))
> > +   __builtin_abort();
> 
> In this test, *bar() is evaluated, i.e. an undefined pointer is 
> dereferenced; it would be better to return a valid pointer to a 
> sufficiently large array to avoid that undefined behavior.
> 
> > diff --git a/gcc/testsuite/gcc.dg/pr106465.c 
> > b/gcc/testsuite/gcc.dg/pr106465.c
> > new file mode 100644
> > index 000..b03e2442f12
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.dg/pr106465.c
> > @@ -0,0 +1,86 @@
> > +/* PR c/106465
> > + * { dg-do run }
> > + * { dg-options "-std=gnu99" }
> > + * */
> > +
> > +int main()
> > +{
> > +   int n = 3;
> > +   
> > +   void g1(int m, struct { char p[++m]; }* b)  /* { dg-warning 
> > "anonymous struct" } */
> > +   {
> > +   if (3 != m)
> > +   __builtin_abort();
> > +
> > +   if (3 != sizeof(b->p))
> > +   __builtin_abort();
> > +   }
> 
> > +   g1(2, (void*)0);
> 
> Similarly, this is dereferencing a null pointer in the evaluated operand 
> of sizeof.

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 90d7cd27cd5..f63c1108ab5 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -5378,7 +5378,8 @@ start_decl (struct c_declarator *declarator, struct 
c_declspecs *declspecs,
 if (lastdecl != error_mark_node)
   *lastloc = DECL_SOURCE_LOCATION (lastdecl);
 
-  if (expr)
+  /* Make sure the size expression is evaluated at this point.  */
+  if (expr && !current_scope->parm_flag)
 add_stmt (fold_convert (void_type_node, expr));
 
   if (TREE_CODE (decl) != FUNCTION_DECL &am

[PING] [C PATCH] Fix ICEs related to VM types in C [PR106465, PR107557, PR108423, PR109450]

2023-05-18 Thread Martin Uecker via Gcc-patches



Ping. Ok, for trunk?

Bootstrapped and tested on x86_64-linux-gnu with no regressions.



Fix ICEs related to VM types in C [PR106465, PR107557, PR108423, PR109450]

Size expressions were sometimes lost and not gimplified correctly, leading 
to
ICEs and incorrect evaluation order.  Fix this by 1) not recursing into
pointers when gimplifying parameters in the middle-end (the code is merged 
with
gimplify_type_sizes), which is incorrect because it might access variables
declared later for incomplete structs, and 2) tracking size expressions for
struct/union members correctly, 3) emitting code to evaluate size 
expressions
for missing cases (nested functions, empty declarations, and 
structs/unions).

PR c/106465
PR c/107557
PR c/108423
PR c/109450

gcc/
* c/c-decl.cc (start_decl): Make sure size expression are
evaluated only in correct context.
(grokdeclarator): Size expression in fields may need a bind
expression, make sure DECL_EXPR is always created.
(grokfield, declspecs_add_type): Pass along size expressions.
(finish_struct): Remove unneeded DECL_EXPR.
(start_function): Evaluate size expressions for nested functions.
* c/c-parser.cc (c_parser_struct_declarations,
c_parser_struct_or_union_specifier): Pass along size expressions.
(c_parser_declaration_or_fndef): Evaluate size expression.
(c_parser_objc_at_property_declaration,
c_parser_objc_class_instance_variables): Adapt.
* function.cc (gimplify_parm_type): Remove function.
(gimplify_parameters): Call gimplify_parm_sizes.
* gimplify.cc (gimplify_type_sizes): Make function static.
(gimplify_parm_sizes): New function.

gcc/testsuite/
* gcc.dg/nested-vla-1.c: New test.
* gcc.dg/nested-vla-2.c: New test.
* gcc.dg/nested-vla-3.c: New test.
* gcc.dg/pr106465.c: New test.
* gcc.dg/pr107557-1.c: New test.
* gcc.dg/pr107557-2.c: New test.
* gcc.dg/pr108423-1.c: New test.
* gcc.dg/pr108423-2.c: New test.
* gcc.dg/pr108423-3.c: New test.
* gcc.dg/pr108423-4.c: New test.
* gcc.dg/pr108423-5.c: New test.
* gcc.dg/pr108423-6.c: New test.
* gcc.dg/pr109450-1.c: New test.
* gcc.dg/pr109450-2.c: New test.
* gcc.dg/typename-vla-2.c: New test.
* gcc.dg/typename-vla-3.c: New test.
* gcc.dg/typename-vla-4.c: New test.
* gcc.misc-tests/gcov-pr85350.c: Adapt.

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 90d7cd27cd5..f63c1108ab5 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -5378,7 +5378,8 @@ start_decl (struct c_declarator *declarator, struct 
c_declspecs *declspecs,
 if (lastdecl != error_mark_node)
   *lastloc = DECL_SOURCE_LOCATION (lastdecl);
 
-  if (expr)
+  /* Make sure the size expression is evaluated at this point.  */
+  if (expr && !current_scope->parm_flag)
 add_stmt (fold_convert (void_type_node, expr));
 
   if (TREE_CODE (decl) != FUNCTION_DECL && MAIN_NAME_P (DECL_NAME (decl))
@@ -7510,7 +7511,8 @@ grokdeclarator (const struct c_declarator *declarator,
&& c_type_variably_modified_p (type))
  {
tree bind = NULL_TREE;
-   if (decl_context == TYPENAME || decl_context == PARM)
+   if (decl_context == TYPENAME || decl_context == PARM
+   || decl_context == FIELD)
  {
bind = build3 (BIND_EXPR, void_type_node, NULL_TREE,
   NULL_TREE, NULL_TREE);
@@ -7519,10 +7521,11 @@ grokdeclarator (const struct c_declarator *declarator,
push_scope ();
  }
tree decl = build_decl (loc, TYPE_DECL, NULL_TREE, type);
-   DECL_ARTIFICIAL (decl) = 1;
pushdecl (decl);
-   finish_decl (decl, loc, NULL_TREE, NULL_TREE, NULL_TREE);
+   DECL_ARTIFICIAL (decl) = 1;
+   add_stmt (build_stmt (DECL_SOURCE_LOCATION (decl), DECL_EXPR, 
decl));
TYPE_NAME (type) = decl;
+
if (bind)
  {
pop_scope ();
@@ -8721,7 +8724,7 @@ start_struct (location_t loc, enum tree_code code, tree 
name,
 tree
 grokfield (location_t loc,
   struct c_declarator *declarator, struct c_declspecs *declspecs,
-  tree width, tree *decl_attrs)
+  tree width, tree *decl_attrs, tree *expr)
 {
   tree value;
 
@@ -8778,7 +8781,7 @@ grokfield (location_t loc,
 }
 
   value = grokdeclarator (declarator, declspecs, FIELD, false,
- width ? &width : NULL, decl_attrs, NULL, NULL,
+ wi

[committed, gcc 12] Fix ICE related to implicit access attributes for VLA arguments [PR105660]

2023-05-08 Thread Martin Uecker via Gcc-patches



Bootstrapped and regression tested on x86-64.



Fix ICE related to implicit access attributes for VLA arguments [PR105660]

When constructing the specifier string when merging an access attribute
that encodes information about VLA arguments, the string was constructed
in random order by iterating through a hash table. Fix this by iterating
though the list of arguments.

PR c/105660

gcc/Changelog
* c-family/c-attribs.cc (append_access_attr): Use order
of arguments when construction string.
(append_access_attr_idxs): Rename and make static.
* c-familty/c-warn.cc (warn_parm_array_mismatch): Add assertion.

gcc/testsuite/ChangeLog:
* gcc.dg/pr105660-1.c: New test.
* gcc.dg/pr105660-2.c: New test.


diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc
index 4667f6de311..072cfb69147 100644
--- a/gcc/c-family/c-attribs.cc
+++ b/gcc/c-family/c-attribs.cc
@@ -4728,22 +4728,27 @@ append_access_attr (tree node[3], tree attrs, const 
char *attrstr,
   rdwr_map cur_idxs;
   init_attr_rdwr_indices (&cur_idxs, attrs);
 
+  tree args = TYPE_ARG_TYPES (node[0]);
+  int argpos = 0;
   std::string spec;
-  for (auto it = new_idxs.begin (); it != new_idxs.end (); ++it)
+  for (tree arg = args; arg; arg = TREE_CHAIN (arg), argpos++)
 {
-  const auto &newaxsref = *it;
+  const attr_access* const newa = new_idxs.get (argpos);
+
+  if (!newa)
+   continue;
 
   /* The map has two equal entries for each pointer argument that
 has an associated size argument.  Process just the entry for
 the former.  */
-  if ((unsigned)newaxsref.first != newaxsref.second.ptrarg)
+  if ((unsigned)argpos != newa->ptrarg)
continue;
 
-  const attr_access* const cura = cur_idxs.get (newaxsref.first);
+  const attr_access* const cura = cur_idxs.get (argpos);
   if (!cura)
{
  /* The new attribute needs to be added.  */
- tree str = newaxsref.second.to_internal_string ();
+ tree str = newa->to_internal_string ();
  spec += TREE_STRING_POINTER (str);
  continue;
}
@@ -4751,7 +4756,6 @@ append_access_attr (tree node[3], tree attrs, const char 
*attrstr,
   /* The new access spec refers to an array/pointer argument for
 which an access spec already exists.  Check and diagnose any
 conflicts.  If no conflicts are found, merge the two.  */
-  const attr_access* const newa = &newaxsref.second;
 
   if (!attrstr)
{
@@ -4886,7 +4890,7 @@ append_access_attr (tree node[3], tree attrs, const char 
*attrstr,
continue;
 
   /* Merge the CURA and NEWA.  */
-  attr_access merged = newaxsref.second;
+  attr_access merged = *newa;
 
   /* VLA seen in a declaration takes precedence.  */
   if (cura->minsize == HOST_WIDE_INT_M1U)
@@ -4912,9 +4916,9 @@ append_access_attr (tree node[3], tree attrs, const char 
*attrstr,
 
 /* Convenience wrapper for the above.  */
 
-tree
-append_access_attr (tree node[3], tree attrs, const char *attrstr,
-   char code, HOST_WIDE_INT idxs[2])
+static tree
+append_access_attr_idxs (tree node[3], tree attrs, const char *attrstr,
+char code, HOST_WIDE_INT idxs[2])
 {
   char attrspec[80];
   int n = sprintf (attrspec, "%c%u", code, (unsigned) idxs[0] - 1);
@@ -5204,7 +5208,7 @@ handle_access_attribute (tree node[3], tree name, tree 
args, int flags,
  attributes specified on previous declarations of the same type
  and if not, concatenate the two.  */
   const char code = attr_access::mode_chars[mode];
-  tree new_attrs = append_access_attr (node, attrs, attrstr, code, idxs);
+  tree new_attrs = append_access_attr_idxs (node, attrs, attrstr, code, idxs);
   if (!new_attrs)
 return NULL_TREE;
 
@@ -5217,7 +5221,7 @@ handle_access_attribute (tree node[3], tree name, tree 
args, int flags,
 {
   /* Repeat for the previously declared type.  */
   attrs = TYPE_ATTRIBUTES (TREE_TYPE (node[1]));
-  new_attrs = append_access_attr (node, attrs, attrstr, code, idxs);
+  new_attrs = append_access_attr_idxs (node, attrs, attrstr, code, idxs);
   if (!new_attrs)
return NULL_TREE;
 
diff --git a/gcc/c-family/c-warn.cc b/gcc/c-family/c-warn.cc
index 29efce3f2c0..a6fb95b1e80 100644
--- a/gcc/c-family/c-warn.cc
+++ b/gcc/c-family/c-warn.cc
@@ -3617,6 +3617,8 @@ warn_parm_array_mismatch (location_t origloc, tree 
fndecl, tree newparms)
   for (tree newvbl = newa->size, curvbl = cura->size; newvbl;
   newvbl = TREE_CHAIN (newvbl), curvbl = TREE_CHAIN (curvbl))
{
+ gcc_assert (curvbl);
+
  tree newpos = TREE_PURPOSE (newvbl);
  tree curpos = TREE_PURPOSE (curvbl);
 
diff --git a/gcc/testsuite/gcc.dg/pr105660-1.c 
b/gcc/testsuite/gcc.dg/pr105660-1.c
new file mode 100644
index 000..d4454f04c43
--- /dev/null
+++

Re: Re: GCC 12.2.1 Status Report (2023-05-02), branch frozen for release

2023-05-04 Thread Martin Uecker via Gcc-patches
Am Donnerstag, dem 04.05.2023 um 09:53 + schrieb Richard Biener:
> On Thu, 4 May 2023, Martin Uecker wrote:
> 
> > 
> > Can I please get permission for fixing this ICE?
> > 
> > https://gcc.gnu.org/pipermail/gcc-patches/2023-April/616221.html
> 
> Please wait until after the branch is unfrozen.  When patches were
> approved for trunk and they are regressions there's no further
> approval needed to backport them (but of course bootstrap & testing
> is required on the branches backported to).

Ok, thanks - good to know! Next time I just push important
fixes for regressions approved for trunk.   But does this mean
we need to wait for about a year to get this fix into 12? 
This would be a bit unfortunate for this problem I think.

Martin



Re: Re: GCC 12.2.1 Status Report (2023-05-02), branch frozen for release

2023-05-03 Thread Martin Uecker via Gcc-patches


Can I please get permission for fixing this ICE?

https://gcc.gnu.org/pipermail/gcc-patches/2023-April/616221.html



Martin





PING [C PATCH - backport 12] Fix ICE related to implicit access attributes for VLA arguments [PR105660]

2023-04-30 Thread Martin Uecker via Gcc-patches


Ok for 12.3 ? 

Am Mittwoch, dem 19.04.2023 um 18:39 +0200 schrieb Martin Uecker:
> Ok to cherrypick for 12?   It is in GCC 13 and fixes an
> annoying ICE.
> 
> Martin
> 
> 
> 
> Here is a fix for PR105660.
> 
> Bootstrapped and regression tested on x86-64.
> 
> 
> Fix ICE related to implicit access attributes for VLA arguments [PR105660]
> 
> 
> When constructing the specifier string when merging an access attribute
> that encodes information about VLA arguments, the string was constructed
> in random order by iterating through a hash table. Fix this by iterating
> though the list of arguments.
> 
> 
> PR c/105660
> 
> 
> gcc/Changelog
> * c-family/c-attribs.cc (append_access_attr): Use order
> of arguments when construction string.
> (append_access_attr_idxs): Rename and make static.
> * c-familty/c-warn.cc (warn_parm_array_mismatch): Add assertion.
> 
> 
> gcc/testsuite/ChangeLog:
> * gcc.dg/pr105660-1.c: New test.
> * gcc.dg/pr105660-2.c: New test.
> 
> 
> diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc
> index 4667f6de311..072cfb69147 100644
> --- a/gcc/c-family/c-attribs.cc
> +++ b/gcc/c-family/c-attribs.cc
> @@ -4728,22 +4728,27 @@ append_access_attr (tree node[3], tree attrs, const 
> char *attrstr,
>    rdwr_map cur_idxs;
>    init_attr_rdwr_indices (&cur_idxs, attrs);
>  
> 
> +  tree args = TYPE_ARG_TYPES (node[0]);
> +  int argpos = 0;
>    std::string spec;
> -  for (auto it = new_idxs.begin (); it != new_idxs.end (); ++it)
> +  for (tree arg = args; arg; arg = TREE_CHAIN (arg), argpos++)
>  {
> -  const auto &newaxsref = *it;
> +  const attr_access* const newa = new_idxs.get (argpos);
> +
> +  if (!newa)
> + continue;
>  
> 
>    /* The map has two equal entries for each pointer argument that
>    has an associated size argument.  Process just the entry for
>    the former.  */
> -  if ((unsigned)newaxsref.first != newaxsref.second.ptrarg)
> +  if ((unsigned)argpos != newa->ptrarg)
>   continue;
>  
> 
> -  const attr_access* const cura = cur_idxs.get (newaxsref.first);
> +  const attr_access* const cura = cur_idxs.get (argpos);
>    if (!cura)
>   {
>     /* The new attribute needs to be added.  */
> -   tree str = newaxsref.second.to_internal_string ();
> +   tree str = newa->to_internal_string ();
>     spec += TREE_STRING_POINTER (str);
>     continue;
>   }
> @@ -4751,7 +4756,6 @@ append_access_attr (tree node[3], tree attrs, const 
> char *attrstr,
>    /* The new access spec refers to an array/pointer argument for
>    which an access spec already exists.  Check and diagnose any
>    conflicts.  If no conflicts are found, merge the two.  */
> -  const attr_access* const newa = &newaxsref.second;
>  
> 
>    if (!attrstr)
>   {
> @@ -4886,7 +4890,7 @@ append_access_attr (tree node[3], tree attrs, const 
> char *attrstr,
>   continue;
>  
> 
>    /* Merge the CURA and NEWA.  */
> -  attr_access merged = newaxsref.second;
> +  attr_access merged = *newa;
>  
> 
>    /* VLA seen in a declaration takes precedence.  */
>    if (cura->minsize == HOST_WIDE_INT_M1U)
> @@ -4912,9 +4916,9 @@ append_access_attr (tree node[3], tree attrs, const 
> char *attrstr,
>  
> 
>  /* Convenience wrapper for the above.  */
>  
> 
> -tree
> -append_access_attr (tree node[3], tree attrs, const char *attrstr,
> - char code, HOST_WIDE_INT idxs[2])
> +static tree
> +append_access_attr_idxs (tree node[3], tree attrs, const char *attrstr,
> +  char code, HOST_WIDE_INT idxs[2])
>  {
>    char attrspec[80];
>    int n = sprintf (attrspec, "%c%u", code, (unsigned) idxs[0] - 1);
> @@ -5204,7 +5208,7 @@ handle_access_attribute (tree node[3], tree name, tree 
> args, int flags,
>   attributes specified on previous declarations of the same type
>   and if not, concatenate the two.  */
>    const char code = attr_access::mode_chars[mode];
> -  tree new_attrs = append_access_attr (node, attrs, attrstr, code, idxs);
> +  tree new_attrs = append_access_attr_idxs (node, attrs, attrstr, code, 
> idxs);
>    if (!new_attrs)
>  return NULL_TREE;
>  
> 
> @@ -5217,7 +5221,7 @@ handle_access_attribute (tree node[3], tree name, tree 
> args, int flags,
>  {
>    /* Repeat for the previously declared type.  */
>    attrs = TYPE_ATTRIBUTES (TREE_TYPE (node[1]));
> -  new_attrs

Re: [PATCH] Less warnings for parameters declared as arrays [PR98541, PR98536]

2023-04-20 Thread Martin Uecker via Gcc-patches
Am Dienstag, dem 04.04.2023 um 19:31 -0600 schrieb Jeff Law:
> 
> On 4/3/23 13:34, Martin Uecker via Gcc-patches wrote:
> > 
> > 
> > With the relatively new warnings (11..) affecting VLA bounds,
> > I now get a lot of false positives with -Wall. In general, I find
> > the new warnings very useful, but they seem a bit too
> > aggressive and some minor tweaks are needed, otherwise they are
> > too noisy.  This patch suggests two changes:
> > 
> > 1. For VLA bounds non-null is implied only when 'static' is
> > used (similar to clang) and not already when a bound > 0 is
> > specified:
> > 
> > int foo(int n, char buf[static n]);
> > 
> > int foo(10, 0); // warning with 'static' but not without.
> > 
> > 
> > (It also seems problematic to require a size of 0 to indicate
> > that the pointer may be null, because 0 is not allowed in
> > ISO C as a size. It is also inconsistent to how arrays with
> > static bound behave.)
> > 
> > There seems to be agreement about this change in PR98541.
> > 
> > 
> > 2. GCC always warns when the number of unspecified
> > bounds is different between two declarations:
> > 
> > int foo(int n, char buf[*]);
> > int foo(int n, char buf[n]);
> > 
> > or
> > 
> > int foo(int n, char buf[n]);
> > int foo(int n, char buf[*]);
> > 
> > But the first version is useful if the size expression
> > can not be specified in a header (e.g. because it uses
> > a macro or variable not available there) and there is
> > currently no easy way to avoid this.  The warning for
> > both cases was by design,  but I suggest to limit the
> > warning to the second case.
> > 
> > Note that the logic currently applied by GCC is too
> > simplistic anyway, as GCC does not warn for
> > 
> > int foo(int x, int y, double m[*][y]);
> > int foo(int x, int y, double m[x][*]);
> > 
> > because the number of specified / unspecified bounds
> > is the same.  So I suggest to go with the attached
> > patch now and add  more precise warnings later
> > if there is more experience with these warning
> > in gernal and if this then still seems desirable.
> > 
> > 
> > Martin
> > 
> > 
> >  Less warnings for parameters declared as arrays [PR98541, PR98536]
> >  
> > 
> > 
> > 
> >  To avoid false positivies, tune the warnings for parameters declared
> >  as arrays with size expressions.  Only warn about null arguments with
> >  'static'.  Also do not warn when more bounds are specified in the new
> >  declaration than before.
> >  
> > 
> > 
> > 
> >  PR c/98541
> >  PR c/98536
> >  
> > 
> > 
> > 
> >  c-family/
> >  * c-warn.cc (warn_parm_array_mismatch): Do not warn if more
> >  bounds are specified.
> >  
> > 
> > 
> > 
> >  gcc/
> >  * gimple-ssa-warn-access.cc
> >    (pass_waccess::maybe_check_access_sizes): For VLA bounds
> >  in parameters, only warn about null pointers with 'static'.
> >  
> > 
> > 
> > 
> >  gcc/testsuite:
> >  * gcc.dg/Wnonnull-4: Adapt test.
> >  * gcc.dg/Wstringop-overflow-40.c: Adapt test.
> >  * gcc.dg/Wvla-parameter-4.c: Adapt test.
> >  * gcc.dg/attr-access-2.c: Adapt test.
> Neither appears to be a regression.  Seems like it should defer to gcc-14.

Then ok for trunk now?

Martin






[C PATCH - backport 12] Fix ICE related to implicit access attributes for VLA arguments [PR105660]

2023-04-19 Thread Martin Uecker via Gcc-patches


Ok to cherrypick for 12?   It is in GCC 13 and fixes an
annoying ICE.

Martin



Here is a fix for PR105660.

Bootstrapped and regression tested on x86-64.


Fix ICE related to implicit access attributes for VLA arguments [PR105660]

When constructing the specifier string when merging an access attribute
that encodes information about VLA arguments, the string was constructed
in random order by iterating through a hash table. Fix this by iterating
though the list of arguments.

PR c/105660

gcc/Changelog
* c-family/c-attribs.cc (append_access_attr): Use order
of arguments when construction string.
(append_access_attr_idxs): Rename and make static.
* c-familty/c-warn.cc (warn_parm_array_mismatch): Add assertion.

gcc/testsuite/ChangeLog:
* gcc.dg/pr105660-1.c: New test.
* gcc.dg/pr105660-2.c: New test.


diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc
index 4667f6de311..072cfb69147 100644
--- a/gcc/c-family/c-attribs.cc
+++ b/gcc/c-family/c-attribs.cc
@@ -4728,22 +4728,27 @@ append_access_attr (tree node[3], tree attrs, const 
char *attrstr,
   rdwr_map cur_idxs;
   init_attr_rdwr_indices (&cur_idxs, attrs);
 
+  tree args = TYPE_ARG_TYPES (node[0]);
+  int argpos = 0;
   std::string spec;
-  for (auto it = new_idxs.begin (); it != new_idxs.end (); ++it)
+  for (tree arg = args; arg; arg = TREE_CHAIN (arg), argpos++)
 {
-  const auto &newaxsref = *it;
+  const attr_access* const newa = new_idxs.get (argpos);
+
+  if (!newa)
+   continue;
 
   /* The map has two equal entries for each pointer argument that
 has an associated size argument.  Process just the entry for
 the former.  */
-  if ((unsigned)newaxsref.first != newaxsref.second.ptrarg)
+  if ((unsigned)argpos != newa->ptrarg)
continue;
 
-  const attr_access* const cura = cur_idxs.get (newaxsref.first);
+  const attr_access* const cura = cur_idxs.get (argpos);
   if (!cura)
{
  /* The new attribute needs to be added.  */
- tree str = newaxsref.second.to_internal_string ();
+ tree str = newa->to_internal_string ();
  spec += TREE_STRING_POINTER (str);
  continue;
}
@@ -4751,7 +4756,6 @@ append_access_attr (tree node[3], tree attrs, const char 
*attrstr,
   /* The new access spec refers to an array/pointer argument for
 which an access spec already exists.  Check and diagnose any
 conflicts.  If no conflicts are found, merge the two.  */
-  const attr_access* const newa = &newaxsref.second;
 
   if (!attrstr)
{
@@ -4886,7 +4890,7 @@ append_access_attr (tree node[3], tree attrs, const char 
*attrstr,
continue;
 
   /* Merge the CURA and NEWA.  */
-  attr_access merged = newaxsref.second;
+  attr_access merged = *newa;
 
   /* VLA seen in a declaration takes precedence.  */
   if (cura->minsize == HOST_WIDE_INT_M1U)
@@ -4912,9 +4916,9 @@ append_access_attr (tree node[3], tree attrs, const char 
*attrstr,
 
 /* Convenience wrapper for the above.  */
 
-tree
-append_access_attr (tree node[3], tree attrs, const char *attrstr,
-   char code, HOST_WIDE_INT idxs[2])
+static tree
+append_access_attr_idxs (tree node[3], tree attrs, const char *attrstr,
+char code, HOST_WIDE_INT idxs[2])
 {
   char attrspec[80];
   int n = sprintf (attrspec, "%c%u", code, (unsigned) idxs[0] - 1);
@@ -5204,7 +5208,7 @@ handle_access_attribute (tree node[3], tree name, tree 
args, int flags,
  attributes specified on previous declarations of the same type
  and if not, concatenate the two.  */
   const char code = attr_access::mode_chars[mode];
-  tree new_attrs = append_access_attr (node, attrs, attrstr, code, idxs);
+  tree new_attrs = append_access_attr_idxs (node, attrs, attrstr, code, idxs);
   if (!new_attrs)
 return NULL_TREE;
 
@@ -5217,7 +5221,7 @@ handle_access_attribute (tree node[3], tree name, tree 
args, int flags,
 {
   /* Repeat for the previously declared type.  */
   attrs = TYPE_ATTRIBUTES (TREE_TYPE (node[1]));
-  new_attrs = append_access_attr (node, attrs, attrstr, code, idxs);
+  new_attrs = append_access_attr_idxs (node, attrs, attrstr, code, idxs);
   if (!new_attrs)
return NULL_TREE;
 
diff --git a/gcc/c-family/c-warn.cc b/gcc/c-family/c-warn.cc
index 29efce3f2c0..a6fb95b1e80 100644
--- a/gcc/c-family/c-warn.cc
+++ b/gcc/c-family/c-warn.cc
@@ -3617,6 +3617,8 @@ warn_parm_array_mismatch (location_t origloc, tree 
fndecl, tree newparms)
   for (tree newvbl = newa->size, curvbl = cura->size; newvbl;
   newvbl = TREE_CHAIN (newvbl), curvbl = TREE_CHAIN (curvbl))
{
+ gcc_assert (curvbl);
+
  tree newpos = TREE_PURPOSE (newvbl);
  tree curpos = TREE_PURPOSE (curvbl);
 
diff --git a/gcc/testsuite/gcc.dg/pr105660-1.

Re: Fix ICEs related to VM types in C [PR106465, PR107557, PR108424, PR109450]

2023-04-11 Thread Martin Uecker via Gcc-patches
Am Mittwoch, dem 12.04.2023 um 00:32 + schrieb Joseph Myers:
> On Tue, 11 Apr 2023, Martin Uecker via Gcc-patches wrote:
> 
> > Ok, here is another attempt on fixing issues with size expression.
> > Not all are regressions, but it does not make sense to try to split
> > it up.
> 
> This wording implies this is version 2 or later of the patch, could you 
> please give a reference to whatever previous patch posting / discussion 
> there may have been?

The previous one was the following for PR107557 and PR108423.

https://gcc.gnu.org/pipermail/gcc-patches/2023-February/611562.html

While revising it I realized that recursing for parameter
when gimplifying is incorrect for the same reason as recursing in
other cases (see the comment in gimplify_type_sizes). This lead
to PR109450.

> 
> > Fix ICEs related to VM types in C [PR106465, PR107557, PR108424, 
> > PR109450]
> 
> 108424 seems to be the wrong PR number.

This should be: PR108423


Martin





Fix ICEs related to VM types in C [PR106465, PR107557, PR108424, PR109450]

2023-04-11 Thread Martin Uecker via Gcc-patches



Ok, here is another attempt on fixing issues with size expression.
Not all are regressions, but it does not make sense to try to split
it up.

Martin



Fix ICEs related to VM types in C [PR106465, PR107557, PR108424, 
PR109450]

Size expressions were sometimes lost and not gimplified correctly, 
leading to
ICEs and incorrect evaluation order.  Fix this by 1) not recursing into
pointers when gimplifying parameters in the middle-end (the code is 
merged with
gimplify_type_sizes), which is incorrect because it might access 
variables
declared later for incomplete structs, and 2) tracking size expressions 
for
struct/union members correctly, 3) emitting code to evaluate size 
expressions
for missing cases (nested functions, empty declarations, and 
structs/unions).

PR c/106465
PR c/107557
PR c/108423
PR c/109450

gcc/
* c/c-decl.cc (start_decl): Make sure size expression are
evaluated only in correct context.
(grokdeclarator): Size expression in fields may need a bind
expression, make sure DECL_EXPR is always created.
(grokfield, declspecs_add_type): Pass along size expressions.
(finish_struct): Remove unneeded DECL_EXPR.
(start_function): Evaluate size expressions for nested functions.
* c/c-parser.cc (c_parser_struct_declarations,
c_parser_struct_or_union_specifier): Pass along size expressions.
(c_parser_declaration_or_fndef): Evaluate size expression.
(c_parser_objc_at_property_declaration,
c_parser_objc_class_instance_variables): Adapt.
* function.cc (gimplify_parm_type): Remove function.
(gimplify_parameters): Call gimplify_parm_sizes.
* gimplify.cc (gimplify_type_sizes): Make function static.
(gimplify_parm_sizes): New function.

gcc/testsuite/
* gcc.dg/nested-vla-1.c: New test.
* gcc.dg/nested-vla-2.c: New test.
* gcc.dg/nested-vla-3.c: New test.
* gcc.dg/pr106465.c: New test.
* gcc.dg/pr107557-1.c: New test.
* gcc.dg/pr107557-2.c: New test.
* gcc.dg/pr108423-1.c: New test.
* gcc.dg/pr108423-2.c: New test.
* gcc.dg/pr108423-3.c: New test.
* gcc.dg/pr108423-4.c: New test.
* gcc.dg/pr108423-5.c: New test.
* gcc.dg/pr108423-6.c: New test.
* gcc.dg/pr109450-1.c: New test.
* gcc.dg/pr109450-2.c: New test.
* gcc.dg/typename-vla-2.c: New test.
* gcc.dg/typename-vla-3.c: New test.
* gcc.dg/typename-vla-4.c: New test.
* gcc.misc-tests/gcov-pr85350.c: Adapt.

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index e537d33f398..c76cbb3115f 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -5371,7 +5371,8 @@ start_decl (struct c_declarator *declarator, struct 
c_declspecs *declspecs,
 if (lastdecl != error_mark_node)
   *lastloc = DECL_SOURCE_LOCATION (lastdecl);
 
-  if (expr)
+  /* Make sure the size expression is evaluated at this point.  */
+  if (expr && !current_scope->parm_flag)
 add_stmt (fold_convert (void_type_node, expr));
 
   if (TREE_CODE (decl) != FUNCTION_DECL && MAIN_NAME_P (DECL_NAME (decl))
@@ -7500,7 +7501,8 @@ grokdeclarator (const struct c_declarator *declarator,
&& c_type_variably_modified_p (type))
  {
tree bind = NULL_TREE;
-   if (decl_context == TYPENAME || decl_context == PARM)
+   if (decl_context == TYPENAME || decl_context == PARM
+   || decl_context == FIELD)
  {
bind = build3 (BIND_EXPR, void_type_node, NULL_TREE,
   NULL_TREE, NULL_TREE);
@@ -7509,10 +7511,9 @@ grokdeclarator (const struct c_declarator *declarator,
push_scope ();
  }
tree decl = build_decl (loc, TYPE_DECL, NULL_TREE, type);
-   DECL_ARTIFICIAL (decl) = 1;
-   pushdecl (decl);
-   finish_decl (decl, loc, NULL_TREE, NULL_TREE, NULL_TREE);
+   add_stmt (build_stmt (DECL_SOURCE_LOCATION (decl), DECL_EXPR, 
decl));
TYPE_NAME (type) = decl;
+
if (bind)
  {
pop_scope ();
@@ -8711,7 +8712,7 @@ start_struct (location_t loc, enum tree_code code, tree 
name,
 tree
 grokfield (location_t loc,
   struct c_declarator *declarator, struct c_declspecs *declspecs,
-  tree width, tree *decl_attrs)
+  tree width, tree *decl_attrs, tree *expr)
 {
   tree value;
 
@@ -8768,7 +8769,7 @@ grokfield (location_t loc,
 }
 
   value = grokdeclarator (declarator, declspecs, FIELD, false,
- width ? &width : NULL, decl_attrs, NULL, NULL,
+ width ? &width : NULL, decl_attrs, expr, NULL,
  DEPRECATED_NORMAL);
 
   finish_decl (value, loc, NU

Re: [PATCH] Less warnings for parameters declared as arrays [PR98541, PR98536]

2023-04-05 Thread Martin Uecker via Gcc-patches
Am Dienstag, dem 04.04.2023 um 19:31 -0600 schrieb Jeff Law:
> 
> On 4/3/23 13:34, Martin Uecker via Gcc-patches wrote:
> > 
> > 
> > With the relatively new warnings (11..) affecting VLA bounds,
> > I now get a lot of false positives with -Wall. In general, I find
> > the new warnings very useful, but they seem a bit too
> > aggressive and some minor tweaks are needed, otherwise they are
> > too noisy.  This patch suggests two changes:
> > 
> > 1. For VLA bounds non-null is implied only when 'static' is
> > used (similar to clang) and not already when a bound > 0 is
> > specified:
> > 
> > int foo(int n, char buf[static n]);
> > 
> > int foo(10, 0); // warning with 'static' but not without.
> > 
> > 
> > (It also seems problematic to require a size of 0 to indicate
> > that the pointer may be null, because 0 is not allowed in
> > ISO C as a size. It is also inconsistent to how arrays with
> > static bound behave.)
> > 
> > There seems to be agreement about this change in PR98541.
> > 
> > 
> > 2. GCC always warns when the number of unspecified
> > bounds is different between two declarations:
> > 
> > int foo(int n, char buf[*]);
> > int foo(int n, char buf[n]);
> > 
> > or
> > 
> > int foo(int n, char buf[n]);
> > int foo(int n, char buf[*]);
> > 
> > But the first version is useful if the size expression
> > can not be specified in a header (e.g. because it uses
> > a macro or variable not available there) and there is
> > currently no easy way to avoid this.  The warning for
> > both cases was by design,  but I suggest to limit the
> > warning to the second case.
> > 
> > Note that the logic currently applied by GCC is too
> > simplistic anyway, as GCC does not warn for
> > 
> > int foo(int x, int y, double m[*][y]);
> > int foo(int x, int y, double m[x][*]);
> > 
> > because the number of specified / unspecified bounds
> > is the same.  So I suggest to go with the attached
> > patch now and add  more precise warnings later
> > if there is more experience with these warning
> > in gernal and if this then still seems desirable.
> > 
> > 
> > Martin
> > 
> > 
> >  Less warnings for parameters declared as arrays [PR98541, PR98536]
> >  
> > 
> > 
> > 
> > 
> > 
> > 
> > 
> >  To avoid false positivies, tune the warnings for parameters declared
> >  as arrays with size expressions.  Only warn about null arguments with
> >  'static'.  Also do not warn when more bounds are specified in the new
> >  declaration than before.
> >  
> > 
> > 
> > 
> > 
> > 
> > 
> > 
> >  PR c/98541
> >  PR c/98536
> >  
> > 
> > 
> > 
> > 
> > 
> > 
> > 
> >  c-family/
> >  * c-warn.cc (warn_parm_array_mismatch): Do not warn if more
> >  bounds are specified.
> >  
> > 
> > 
> > 
> > 
> > 
> > 
> > 
> >  gcc/
> >  * gimple-ssa-warn-access.cc
> >    (pass_waccess::maybe_check_access_sizes): For VLA bounds
> >  in parameters, only warn about null pointers with 'static'.
> >  
> > 
> > 
> > 
> > 
> > 
> > 
> > 
> >  gcc/testsuite:
> >  * gcc.dg/Wnonnull-4: Adapt test.
> >  * gcc.dg/Wstringop-overflow-40.c: Adapt test.
> >  * gcc.dg/Wvla-parameter-4.c: Adapt test.
> >  * gcc.dg/attr-access-2.c: Adapt test.
> Neither appears to be a regression.  Seems like it should defer to gcc-14.

The false positives are a regression relative to earlier version of GCC
because the warnings are completely new (since GCC 11).   I could bring
this back later, but this means there is another version of GCC where 
one might need to turn off these warnings.  My concern is also that
an otherwise very useful feature that brings some safety benefits gets
underused. 

Martin






[PATCH] Less warnings for parameters declared as arrays [PR98541, PR98536]

2023-04-03 Thread Martin Uecker via Gcc-patches



With the relatively new warnings (11..) affecting VLA bounds,
I now get a lot of false positives with -Wall. In general, I find
the new warnings very useful, but they seem a bit too
aggressive and some minor tweaks are needed, otherwise they are
too noisy.  This patch suggests two changes:

1. For VLA bounds non-null is implied only when 'static' is
used (similar to clang) and not already when a bound > 0 is
specified:

int foo(int n, char buf[static n]);

int foo(10, 0); // warning with 'static' but not without.


(It also seems problematic to require a size of 0 to indicate 
that the pointer may be null, because 0 is not allowed in
ISO C as a size. It is also inconsistent to how arrays with
static bound behave.) 

There seems to be agreement about this change in PR98541.


2. GCC always warns when the number of unspecified
bounds is different between two declarations:

int foo(int n, char buf[*]);
int foo(int n, char buf[n]);

or

int foo(int n, char buf[n]);
int foo(int n, char buf[*]);

But the first version is useful if the size expression
can not be specified in a header (e.g. because it uses
a macro or variable not available there) and there is
currently no easy way to avoid this.  The warning for
both cases was by design,  but I suggest to limit the
warning to the second case. 

Note that the logic currently applied by GCC is too
simplistic anyway, as GCC does not warn for

int foo(int x, int y, double m[*][y]);
int foo(int x, int y, double m[x][*]);

because the number of specified / unspecified bounds
is the same.  So I suggest to go with the attached
patch now and add  more precise warnings later
if there is more experience with these warning 
in gernal and if this then still seems desirable.


Martin


Less warnings for parameters declared as arrays [PR98541, PR98536]

To avoid false positivies, tune the warnings for parameters declared
as arrays with size expressions.  Only warn about null arguments with
'static'.  Also do not warn when more bounds are specified in the new
declaration than before.

PR c/98541
PR c/98536

c-family/
* c-warn.cc (warn_parm_array_mismatch): Do not warn if more
bounds are specified.

gcc/
* gimple-ssa-warn-access.cc
  (pass_waccess::maybe_check_access_sizes): For VLA bounds
in parameters, only warn about null pointers with 'static'.

gcc/testsuite:
* gcc.dg/Wnonnull-4: Adapt test.
* gcc.dg/Wstringop-overflow-40.c: Adapt test.
* gcc.dg/Wvla-parameter-4.c: Adapt test.
* gcc.dg/attr-access-2.c: Adapt test.


diff --git a/gcc/c-family/c-warn.cc b/gcc/c-family/c-warn.cc
index 9ac43a1af6e..f79fb876142 100644
--- a/gcc/c-family/c-warn.cc
+++ b/gcc/c-family/c-warn.cc
@@ -3599,23 +3599,13 @@ warn_parm_array_mismatch (location_t origloc, tree 
fndecl, tree newparms)
  continue;
}
 
- if (newunspec != curunspec)
+ if (newunspec > curunspec)
{
  location_t warnloc = newloc, noteloc = origloc;
  const char *warnparmstr = newparmstr.c_str ();
  const char *noteparmstr = curparmstr.c_str ();
  unsigned warnunspec = newunspec, noteunspec = curunspec;
 
- if (newunspec < curunspec)
-   {
- /* If the new declaration has fewer unspecified bounds
-point the warning to the previous declaration to make
-it clear that that's the one to change.  Otherwise,
-point it to the new decl.  */
- std::swap (warnloc, noteloc);
- std::swap (warnparmstr, noteparmstr);
- std::swap (warnunspec, noteunspec);
-   }
  if (warning_n (warnloc, OPT_Wvla_parameter, warnunspec,
 "argument %u of type %s declared with "
 "%u unspecified variable bound",
@@ -3641,16 +3631,11 @@ warn_parm_array_mismatch (location_t origloc, tree 
fndecl, tree newparms)
  continue;
}
}
-
   /* Iterate over the lists of VLA variable bounds, comparing each
-pair for equality, and diagnosing mismatches.  The case of
-the lists having different lengths is handled above so at
-this point they do .  */
-  for (tree newvbl = newa->size, curvbl = cura->size; newvbl;
+pair for equality, and diagnosing mismatches.  */
+  for (tree newvbl = newa->size, curvbl = cura->size; newvbl && curvbl;
   newvbl = TREE_CHAIN (newvbl), curvbl = TREE_CHAIN (curvbl))
{
- gcc_assert (curvbl);
-
  tree newpos = TREE_PURPOSE (newvbl);
  tree curpos = TREE_PURPOSE (curvbl);
 
@@ -3663,7 +3648,6 @@ warn_parm_array_mismatch (location_t origloc, tree 
fndecl, tree newparms)
   and both are the same expression

Re: [PATCH] gimplify size expressions in parameters for all types [PR107557] [PR108423]

2023-02-21 Thread Martin Uecker via Gcc-patches
Am Dienstag, dem 21.02.2023 um 14:21 + schrieb Richard Biener:
> On Tue, 21 Feb 2023, Martin Uecker wrote:
> 
> > 
> > 
> > Hi Richard,
> > 
> > can you look at this middle-end patch? It fixes two regressions.
> 
> But gimplify_type_sizes recurses itself, but in particular _not_
> for pointer types.  Iff recursing in parameter context is
> necessary and safe I'd rather have gimplify_type_sizes know that
> (bool for_param_p?) and do the recursion?
> 

I just want to point out that without the patch
gimplify_parm_sizes already does the recursion
into pointers  types. But other types are also
not reached. But maybe there was never a good
reason for this split?

I will try merging this all into gimplify_type_sizes.

Martin


> Richard.
> 
> > Martin
> > 
> > 
> > PS: I happy to do something about at variably_modified_type_p 
> > in the middle-end, if you have a recommendation.
> > 
> > 
> > 
> > 
> > Am Mittwoch, dem 08.02.2023 um 13:02 +0100 schrieb Martin Uecker:
> > > 
> > > Here is a fix for PR107557 and PR108423.
> > > 
> > > 
> > > Bootstrapped and regression tested on x86-64.
> > > 
> > > 
> > > 
> > > Gimplify more size expression in parameters [PR107557] and [PR108234]
> > > 
> > > 
> > > gimplify_parm_type only recursives into pointer type and
> > > size expressions in other types (e.g. function types) were
> > > not reached.
> > > 
> > > 
> > > PR c/107557
> > > PR c/108234
> > > 
> > > 
> > > gcc/Changelog
> > > * gcc/function.cc (gimplify_parm_type): Also recursive into
> > > non-pointer types.
> > > 
> > > 
> > > gcc/testsuite/ChangeLog:
> > > * gcc.dg/pr107557-1.c: New test.
> > > * gcc.dg/pr107557-2.c: New test.
> > > * gcc.dg/pr108423-1.c: New test.
> > > * gcc.dg/pr108423-2.c: New test.
> > > * gcc.dg/pr108423-3.c: New test.
> > > * gcc.dg/pr108423-4.c: New test.
> > > * gcc.dg/pr108423-5.c: New test.
> > > 
> > > 
> > > 
> > > 
> > > diff --git a/gcc/function.cc b/gcc/function.cc
> > > index cfc4d2f74af..d777348aeb4 100644
> > > --- a/gcc/function.cc
> > > +++ b/gcc/function.cc
> > > @@ -3880,20 +3880,15 @@ static tree
> > >  gimplify_parm_type (tree *tp, int *walk_subtrees, void *data)
> > >  {
> > >    tree t = *tp;
> > > -
> > >    *walk_subtrees = 0;
> > >    if (TYPE_P (t))
> > >  {
> > > -  if (POINTER_TYPE_P (t))
> > > - *walk_subtrees = 1;
> > > -  else if (TYPE_SIZE (t) && !TREE_CONSTANT (TYPE_SIZE (t))
> > > +  if (TYPE_SIZE (t) && !TREE_CONSTANT (TYPE_SIZE (t))
> > >  && !TYPE_SIZES_GIMPLIFIED (t))
> > > - {
> > > -   gimplify_type_sizes (t, (gimple_seq *) data);
> > > -   *walk_subtrees = 1;
> > > - }
> > > -}
> > > + gimplify_type_sizes (t, (gimple_seq *) data);
> > >  
> > > 
> > > +  *walk_subtrees = 1;
> > > +}
> > >    return NULL;
> > >  }
> > >  
> > > 
> > > diff --git a/gcc/testsuite/gcc.dg/pr107557-1.c 
> > > b/gcc/testsuite/gcc.dg/pr107557-1.c
> > > new file mode 100644
> > > index 000..88c248b6564
> > > --- /dev/null
> > > +++ b/gcc/testsuite/gcc.dg/pr107557-1.c
> > > @@ -0,0 +1,24 @@
> > > +/* PR107557
> > > + * { dg-do compile }
> > > + * { dg-options "-flto -fsanitize=undefined -fexceptions 
> > > -Wno-incompatible-pointer-types" }
> > > + */
> > > +
> > > +
> > > +int c[1][3*2];
> > > +int f(int * const m, int (**v)[*m * 2])
> > > +{
> > > + return &(c[0][*m]) == &((*v)[0][*m]);
> > > +}
> > > +int test(int n, int (*(*fn)(void))[n])
> > > +{
> > > + return (*fn())[0];
> > > +}
> > > +int main()
> > > +{
> > > + int m = 3;
> > > + int (*d)[3*2] = c;
> > > + int (*fn[m])(void);
> > > + return f(&m, &d) + test(m, &fn);
> > > +}
> > > +
> > > +
> > > diff --git a/gcc/testsuite/gcc.dg/pr107557-2.c 
> > > b/gcc/testsuite/gcc.dg/pr107557-2.c
> > > new file mode 100644
> > >

Re: [PATCH] gimplify size expressions in parameters for all types [PR107557] [PR108423]

2023-02-21 Thread Martin Uecker via Gcc-patches



Hi Richard,

can you look at this middle-end patch? It fixes two regressions.

Martin


PS: I happy to do something about at variably_modified_type_p 
in the middle-end, if you have a recommendation.




Am Mittwoch, dem 08.02.2023 um 13:02 +0100 schrieb Martin Uecker:
> 
> Here is a fix for PR107557 and PR108423.
> 
> 
> Bootstrapped and regression tested on x86-64.
> 
> 
> 
> Gimplify more size expression in parameters [PR107557] and [PR108234]
> 
> 
> gimplify_parm_type only recursives into pointer type and
> size expressions in other types (e.g. function types) were
> not reached.
> 
> 
> PR c/107557
> PR c/108234
> 
> 
> gcc/Changelog
> * gcc/function.cc (gimplify_parm_type): Also recursive into
> non-pointer types.
> 
> 
> gcc/testsuite/ChangeLog:
> * gcc.dg/pr107557-1.c: New test.
> * gcc.dg/pr107557-2.c: New test.
> * gcc.dg/pr108423-1.c: New test.
> * gcc.dg/pr108423-2.c: New test.
> * gcc.dg/pr108423-3.c: New test.
> * gcc.dg/pr108423-4.c: New test.
> * gcc.dg/pr108423-5.c: New test.
> 
> 
> 
> 
> diff --git a/gcc/function.cc b/gcc/function.cc
> index cfc4d2f74af..d777348aeb4 100644
> --- a/gcc/function.cc
> +++ b/gcc/function.cc
> @@ -3880,20 +3880,15 @@ static tree
>  gimplify_parm_type (tree *tp, int *walk_subtrees, void *data)
>  {
>    tree t = *tp;
> -
>    *walk_subtrees = 0;
>    if (TYPE_P (t))
>  {
> -  if (POINTER_TYPE_P (t))
> - *walk_subtrees = 1;
> -  else if (TYPE_SIZE (t) && !TREE_CONSTANT (TYPE_SIZE (t))
> +  if (TYPE_SIZE (t) && !TREE_CONSTANT (TYPE_SIZE (t))
>  && !TYPE_SIZES_GIMPLIFIED (t))
> - {
> -   gimplify_type_sizes (t, (gimple_seq *) data);
> -   *walk_subtrees = 1;
> - }
> -}
> + gimplify_type_sizes (t, (gimple_seq *) data);
>  
> 
> +  *walk_subtrees = 1;
> +}
>    return NULL;
>  }
>  
> 
> diff --git a/gcc/testsuite/gcc.dg/pr107557-1.c 
> b/gcc/testsuite/gcc.dg/pr107557-1.c
> new file mode 100644
> index 000..88c248b6564
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/pr107557-1.c
> @@ -0,0 +1,24 @@
> +/* PR107557
> + * { dg-do compile }
> + * { dg-options "-flto -fsanitize=undefined -fexceptions 
> -Wno-incompatible-pointer-types" }
> + */
> +
> +
> +int c[1][3*2];
> +int f(int * const m, int (**v)[*m * 2])
> +{
> + return &(c[0][*m]) == &((*v)[0][*m]);
> +}
> +int test(int n, int (*(*fn)(void))[n])
> +{
> + return (*fn())[0];
> +}
> +int main()
> +{
> + int m = 3;
> + int (*d)[3*2] = c;
> + int (*fn[m])(void);
> + return f(&m, &d) + test(m, &fn);
> +}
> +
> +
> diff --git a/gcc/testsuite/gcc.dg/pr107557-2.c 
> b/gcc/testsuite/gcc.dg/pr107557-2.c
> new file mode 100644
> index 000..2d26bb0b16a
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/pr107557-2.c
> @@ -0,0 +1,23 @@
> +/* PR107557
> + * { dg-do compile }
> + * { dg-options "-flto -fsanitize=undefined -fexceptions 
> -Wno-incompatible-pointer-types" }
> + */
> +
> +
> +int c[1][3*2];
> +int f(int * const m, int (**(*v))[*m * 2])
> +{
> + return &(c[0][*m]) == &((*v)[0][*m]);   /* { dg-warning "lacks a cast" 
> } */
> +}
> +int test(int n, int (*(*(*fn))(void))[n])
> +{
> + return (*(*fn)())[0];
> +}
> +int main()
> +{
> + int m = 3;
> + int (*d)[3*2] = c;
> + int (*fn[m])(void);
> + return f(&m, &d) + test(m, &fn);
> +}
> +
> diff --git a/gcc/testsuite/gcc.dg/pr108423-1.c 
> b/gcc/testsuite/gcc.dg/pr108423-1.c
> new file mode 100644
> index 000..0c98d1d46b9
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/pr108423-1.c
> @@ -0,0 +1,16 @@
> +/* PR108423
> + * { dg-do compile }
> + * { dg-options "-O2 -Wno-int-conversion -Wno-incompatible-pointer-types" }
> + */
> +int f (int n, int (**(*a)(void))[n])
> +{
> + return (*a())[0];
> +}
> +int g ()
> +{
> + int m = 3;
> + int (*a[m])(void);
> + return f(m, &a);
> +}
> +
> +
> diff --git a/gcc/testsuite/gcc.dg/pr108423-2.c 
> b/gcc/testsuite/gcc.dg/pr108423-2.c
> new file mode 100644
> index 000..006e45a9629
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/pr108423-2.c
> @@ -0,0 +1,16 @@
> +/* PR108423
> + * { dg-do compile }
> + * { dg-options "-O2" }
> + */
> +
> +void f(int n, int (*a(void))[n])
> +{
> + (a())[0];
> +}
> +
> +void g

[C PATCH] Detect all variably modified types [PR108375]

2023-02-17 Thread Martin Uecker via Gcc-patches



Here is a patch for PR108375.

Bootstrapped and regession tested on x86_64-linux-gnu


Also there is a middle-end patch for PR107557 and PR108423:
https://gcc.gnu.org/pipermail/gcc-patches/2023-February/611562.html
and another C FE patch for PR105660:
https://gcc.gnu.org/pipermail/gcc-patches/2023-February/611817.html

All regressions.



C: Detect all variably modified types [PR108375]

Some variably modified types were not detected correctly.
Define C_TYPE_VARIABLY_MODIFIED via TYPE_LANG_FLAG 6 in the CFE.
This flag records whether a type is variably modified and is
set for all such types including arrays with variably modified
element type or structures and unions with variably modified
members. This is then used to detect such types in the C FE
and middle-end (via the existing language hook).

PR 108375

gcc/c/

* c/c-decl.c (decl_jump_unsafe): Use c_type_variably_modified_p.
(diagnose_mismatched_decl): Dito.
(warn_about_goto): Dito:
(c_check_switch_jump_warnings): Dito.
(finish_decl): Dito.
(finish_struct): Dito.
(grokdeclarator): Set C_TYPE_VARIABLY_MODIFIED.
(finish_struct): Set C_TYPE_VARIABLY_MODIFIED.
* c/c-objc-common.cc (c_var_mod_p): New function.
(c_var_unspec_p): Remove.
* c/c-objc-common.h: Set lang hook.
* c/c-parser.cc (c_parser_declararion_or_fndef): Use 
c_type_variably_modified_p.
(c_parser_typeof_specifier): Dito.
(c_parser_has_attribute_expression): Dito.
(c_parser_generic_selection): Dito.
* c/c-tree.h: Define C_TYPE_VARIABLY_MODIFIED and define 
c_var_mode_p.
* c/c-typeck.h: Remove c_vla_mod_p and use C_TYPE_VARIABLY_MODIFIED.

gcc/testsuite/

* gcc.dg/pr108375-1.c: New test.
* gcc.dg/pr108375-2.c: New test.


diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 20e7d1855bf..08078eadeb8 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -683,7 +683,7 @@ decl_jump_unsafe (tree decl)
 
   /* Always warn about crossing variably modified types.  */
   if ((VAR_P (decl) || TREE_CODE (decl) == TYPE_DECL)
-  && variably_modified_type_p (TREE_TYPE (decl), NULL_TREE))
+  && c_type_variably_modified_p (TREE_TYPE (decl)))
 return true;
 
   /* Otherwise, only warn if -Wgoto-misses-init and this is an
@@ -2247,7 +2247,7 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
  || warning_suppressed_p (olddecl, OPT_Wpedantic))
return true;  /* Allow OLDDECL to continue in use.  */
 
-  if (variably_modified_type_p (newtype, NULL))
+  if (c_type_variably_modified_p (newtype))
{
  error ("redefinition of typedef %q+D with variably modified type",
 newdecl);
@@ -3975,7 +3975,7 @@ static void
 warn_about_goto (location_t goto_loc, tree label, tree decl)
 {
   auto_diagnostic_group d;
-  if (variably_modified_type_p (TREE_TYPE (decl), NULL_TREE))
+  if (c_type_variably_modified_p (TREE_TYPE (decl)))
 error_at (goto_loc,
  "jump into scope of identifier with variably modified type");
   else
@@ -4249,7 +4249,7 @@ c_check_switch_jump_warnings (struct c_spot_bindings 
*switch_bindings,
{
  auto_diagnostic_group d;
  bool emitted;
- if (variably_modified_type_p (TREE_TYPE (b->decl), NULL_TREE))
+ if (c_type_variably_modified_p (TREE_TYPE (b->decl)))
{
  saw_error = true;
  error_at (case_loc,
@@ -5862,7 +5862,7 @@ finish_decl (tree decl, location_t init_loc, tree init,
   if (TREE_CODE (decl) == TYPE_DECL)
 {
   if (!DECL_FILE_SCOPE_P (decl)
- && variably_modified_type_p (TREE_TYPE (decl), NULL_TREE))
+ && c_type_variably_modified_p (TREE_TYPE (decl)))
add_stmt (build_stmt (DECL_SOURCE_LOCATION (decl), DECL_EXPR, decl));
 
   rest_of_decl_compilation (decl, DECL_FILE_SCOPE_P (decl), 0);
@@ -6682,7 +6682,7 @@ grokdeclarator (const struct c_declarator *declarator,
 
   if ((decl_context == NORMAL || decl_context == FIELD)
   && current_scope == file_scope
-  && variably_modified_type_p (type, NULL_TREE))
+  && c_type_variably_modified_p (type))
 {
   if (name)
error_at (loc, "variably modified %qE at file scope", name);
@@ -6928,6 +6928,8 @@ grokdeclarator (const struct c_declarator *declarator,
  array_parm_static = false;
}
 
+  bool varmod = C_TYPE_VARIABLY_MODIFIED (type);
+
   switch (declarator->kind)
{
case cdk_attrs:
@@ -7282,8 +7284,7 @@ grokdeclarator (const struct c_declarator *declarator,
   variable size, so the enclosing shared array type
   must too.  */
if (size && TREE_CODE (size) == INTEGER_CST)
- type
- 

[C PATCH] Fix ICE related to implicit access attributes for VLA arguments [PR105660]

2023-02-12 Thread Martin Uecker via Gcc-patches


Here is a fix for PR105660.

Bootstrapped and regression tested on x86-64.


Fix ICE related to implicit access attributes for VLA arguments [PR105660]

When constructing the specifier string when merging an access attribute
that encodes information about VLA arguments, the string was constructed
in random order by iterating through a hash table. Fix this by iterating
though the list of arguments.

PR c/105660

gcc/Changelog
* c-family/c-attribs.cc (append_access_attr): Use order
of arguments when construction string.
(append_access_attr_idxs): Rename and make static.
* c-familty/c-warn.cc (warn_parm_array_mismatch): Add assertion.

gcc/testsuite/ChangeLog:
* gcc.dg/pr105660-1.c: New test.
* gcc.dg/pr105660-2.c: New test.


diff --git a/gcc/c-family/c-attribs.cc b/gcc/c-family/c-attribs.cc
index 4667f6de311..072cfb69147 100644
--- a/gcc/c-family/c-attribs.cc
+++ b/gcc/c-family/c-attribs.cc
@@ -4728,22 +4728,27 @@ append_access_attr (tree node[3], tree attrs, const 
char *attrstr,
   rdwr_map cur_idxs;
   init_attr_rdwr_indices (&cur_idxs, attrs);
 
+  tree args = TYPE_ARG_TYPES (node[0]);
+  int argpos = 0;
   std::string spec;
-  for (auto it = new_idxs.begin (); it != new_idxs.end (); ++it)
+  for (tree arg = args; arg; arg = TREE_CHAIN (arg), argpos++)
 {
-  const auto &newaxsref = *it;
+  const attr_access* const newa = new_idxs.get (argpos);
+
+  if (!newa)
+   continue;
 
   /* The map has two equal entries for each pointer argument that
 has an associated size argument.  Process just the entry for
 the former.  */
-  if ((unsigned)newaxsref.first != newaxsref.second.ptrarg)
+  if ((unsigned)argpos != newa->ptrarg)
continue;
 
-  const attr_access* const cura = cur_idxs.get (newaxsref.first);
+  const attr_access* const cura = cur_idxs.get (argpos);
   if (!cura)
{
  /* The new attribute needs to be added.  */
- tree str = newaxsref.second.to_internal_string ();
+ tree str = newa->to_internal_string ();
  spec += TREE_STRING_POINTER (str);
  continue;
}
@@ -4751,7 +4756,6 @@ append_access_attr (tree node[3], tree attrs, const char 
*attrstr,
   /* The new access spec refers to an array/pointer argument for
 which an access spec already exists.  Check and diagnose any
 conflicts.  If no conflicts are found, merge the two.  */
-  const attr_access* const newa = &newaxsref.second;
 
   if (!attrstr)
{
@@ -4886,7 +4890,7 @@ append_access_attr (tree node[3], tree attrs, const char 
*attrstr,
continue;
 
   /* Merge the CURA and NEWA.  */
-  attr_access merged = newaxsref.second;
+  attr_access merged = *newa;
 
   /* VLA seen in a declaration takes precedence.  */
   if (cura->minsize == HOST_WIDE_INT_M1U)
@@ -4912,9 +4916,9 @@ append_access_attr (tree node[3], tree attrs, const char 
*attrstr,
 
 /* Convenience wrapper for the above.  */
 
-tree
-append_access_attr (tree node[3], tree attrs, const char *attrstr,
-   char code, HOST_WIDE_INT idxs[2])
+static tree
+append_access_attr_idxs (tree node[3], tree attrs, const char *attrstr,
+char code, HOST_WIDE_INT idxs[2])
 {
   char attrspec[80];
   int n = sprintf (attrspec, "%c%u", code, (unsigned) idxs[0] - 1);
@@ -5204,7 +5208,7 @@ handle_access_attribute (tree node[3], tree name, tree 
args, int flags,
  attributes specified on previous declarations of the same type
  and if not, concatenate the two.  */
   const char code = attr_access::mode_chars[mode];
-  tree new_attrs = append_access_attr (node, attrs, attrstr, code, idxs);
+  tree new_attrs = append_access_attr_idxs (node, attrs, attrstr, code, idxs);
   if (!new_attrs)
 return NULL_TREE;
 
@@ -5217,7 +5221,7 @@ handle_access_attribute (tree node[3], tree name, tree 
args, int flags,
 {
   /* Repeat for the previously declared type.  */
   attrs = TYPE_ATTRIBUTES (TREE_TYPE (node[1]));
-  new_attrs = append_access_attr (node, attrs, attrstr, code, idxs);
+  new_attrs = append_access_attr_idxs (node, attrs, attrstr, code, idxs);
   if (!new_attrs)
return NULL_TREE;
 
diff --git a/gcc/c-family/c-warn.cc b/gcc/c-family/c-warn.cc
index 29efce3f2c0..a6fb95b1e80 100644
--- a/gcc/c-family/c-warn.cc
+++ b/gcc/c-family/c-warn.cc
@@ -3617,6 +3617,8 @@ warn_parm_array_mismatch (location_t origloc, tree 
fndecl, tree newparms)
   for (tree newvbl = newa->size, curvbl = cura->size; newvbl;
   newvbl = TREE_CHAIN (newvbl), curvbl = TREE_CHAIN (curvbl))
{
+ gcc_assert (curvbl);
+
  tree newpos = TREE_PURPOSE (newvbl);
  tree curpos = TREE_PURPOSE (curvbl);
 
diff --git a/gcc/testsuite/gcc.dg/pr105660-1.c 
b/gcc/testsuite/gcc.dg/pr105660-1.c
new file mode 100644
index 000..d4

[PATCH] gimplify size expressions in parameters for all types [PR107557] [PR108423]

2023-02-08 Thread Martin Uecker via Gcc-patches



Here is a fix for PR107557 and PR108423.


Bootstrapped and regression tested on x86-64.



Gimplify more size expression in parameters [PR107557] and [PR108234]

gimplify_parm_type only recursives into pointer type and
size expressions in other types (e.g. function types) were
not reached.

PR c/107557
PR c/108234

gcc/Changelog
* gcc/function.cc (gimplify_parm_type): Also recursive into
non-pointer types.

gcc/testsuite/ChangeLog:
* gcc.dg/pr107557-1.c: New test.
* gcc.dg/pr107557-2.c: New test.
* gcc.dg/pr108423-1.c: New test.
* gcc.dg/pr108423-2.c: New test.
* gcc.dg/pr108423-3.c: New test.
* gcc.dg/pr108423-4.c: New test.
* gcc.dg/pr108423-5.c: New test.




diff --git a/gcc/function.cc b/gcc/function.cc
index cfc4d2f74af..d777348aeb4 100644
--- a/gcc/function.cc
+++ b/gcc/function.cc
@@ -3880,20 +3880,15 @@ static tree
 gimplify_parm_type (tree *tp, int *walk_subtrees, void *data)
 {
   tree t = *tp;
-
   *walk_subtrees = 0;
   if (TYPE_P (t))
 {
-  if (POINTER_TYPE_P (t))
-   *walk_subtrees = 1;
-  else if (TYPE_SIZE (t) && !TREE_CONSTANT (TYPE_SIZE (t))
+  if (TYPE_SIZE (t) && !TREE_CONSTANT (TYPE_SIZE (t))
   && !TYPE_SIZES_GIMPLIFIED (t))
-   {
- gimplify_type_sizes (t, (gimple_seq *) data);
- *walk_subtrees = 1;
-   }
-}
+   gimplify_type_sizes (t, (gimple_seq *) data);
 
+  *walk_subtrees = 1;
+}
   return NULL;
 }
 
diff --git a/gcc/testsuite/gcc.dg/pr107557-1.c 
b/gcc/testsuite/gcc.dg/pr107557-1.c
new file mode 100644
index 000..88c248b6564
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr107557-1.c
@@ -0,0 +1,24 @@
+/* PR107557
+ * { dg-do compile }
+ * { dg-options "-flto -fsanitize=undefined -fexceptions 
-Wno-incompatible-pointer-types" }
+ */
+
+
+int c[1][3*2];
+int f(int * const m, int (**v)[*m * 2])
+{
+   return &(c[0][*m]) == &((*v)[0][*m]);
+}
+int test(int n, int (*(*fn)(void))[n])
+{
+   return (*fn())[0];
+}
+int main()
+{
+   int m = 3;
+   int (*d)[3*2] = c;
+   int (*fn[m])(void);
+   return f(&m, &d) + test(m, &fn);
+}
+
+
diff --git a/gcc/testsuite/gcc.dg/pr107557-2.c 
b/gcc/testsuite/gcc.dg/pr107557-2.c
new file mode 100644
index 000..2d26bb0b16a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr107557-2.c
@@ -0,0 +1,23 @@
+/* PR107557
+ * { dg-do compile }
+ * { dg-options "-flto -fsanitize=undefined -fexceptions 
-Wno-incompatible-pointer-types" }
+ */
+
+
+int c[1][3*2];
+int f(int * const m, int (**(*v))[*m * 2])
+{
+   return &(c[0][*m]) == &((*v)[0][*m]);   /* { dg-warning "lacks a cast" 
} */
+}
+int test(int n, int (*(*(*fn))(void))[n])
+{
+   return (*(*fn)())[0];
+}
+int main()
+{
+   int m = 3;
+   int (*d)[3*2] = c;
+   int (*fn[m])(void);
+   return f(&m, &d) + test(m, &fn);
+}
+
diff --git a/gcc/testsuite/gcc.dg/pr108423-1.c 
b/gcc/testsuite/gcc.dg/pr108423-1.c
new file mode 100644
index 000..0c98d1d46b9
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr108423-1.c
@@ -0,0 +1,16 @@
+/* PR108423
+ * { dg-do compile }
+ * { dg-options "-O2 -Wno-int-conversion -Wno-incompatible-pointer-types" }
+ */
+int f (int n, int (**(*a)(void))[n])
+{
+   return (*a())[0];
+}
+int g ()
+{
+   int m = 3;
+   int (*a[m])(void);
+   return f(m, &a);
+}
+
+
diff --git a/gcc/testsuite/gcc.dg/pr108423-2.c 
b/gcc/testsuite/gcc.dg/pr108423-2.c
new file mode 100644
index 000..006e45a9629
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr108423-2.c
@@ -0,0 +1,16 @@
+/* PR108423
+ * { dg-do compile }
+ * { dg-options "-O2" }
+ */
+
+void f(int n, int (*a(void))[n])
+{
+   (a())[0];
+}
+
+void g(void)
+{
+   int (*a(void))[1];
+   f(1, a);
+}
+
diff --git a/gcc/testsuite/gcc.dg/pr108423-3.c 
b/gcc/testsuite/gcc.dg/pr108423-3.c
new file mode 100644
index 000..c1987c42b40
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr108423-3.c
@@ -0,0 +1,17 @@
+/* PR108423
+ * { dg-do compile }
+ * { dg-options "-O2" }
+ */
+
+void f(int n, int (*(*b)(void))[n])
+{
+sizeof (*(*b)());
+}
+
+int (*a(void))[1];
+
+void g(void)
+{
+   f(1, &a);
+}
+
diff --git a/gcc/testsuite/gcc.dg/pr108423-4.c 
b/gcc/testsuite/gcc.dg/pr108423-4.c
new file mode 100644
index 000..91336f3f283
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr108423-4.c
@@ -0,0 +1,17 @@
+/* PR108423
+ * { dg-do compile }
+ * { dg-options "-O2" }
+ */
+
+void f(int n, int (*a(void))[n])
+{
+sizeof (*a());
+}
+
+int (*a(void))[1];
+
+void g(void)
+{
+   f(1, a);
+}
+
diff --git a/gcc/testsuite/gcc.dg/pr108423-5.c 
b/gcc/testsuite/gcc.dg/pr108423-5.c
new file mode 100644
index 000..7e4fffb2870
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr108423-5.c
@@ -0,0 +1,17 @@
+/* PR108423
+ * { dg-do compile }
+ * { dg-options "-O2" }
+ */
+
+void f(int n, int (*(*a)(void))[n])
+{
+sizeof ((*a)());
+}
+
+int (*a

[PATCH] regression tests for 103770 fixed on trunk

2022-12-22 Thread Martin Uecker via Gcc-patches


This adds regression tests for an ICE on valid code that
seems gone on trunk, but the cause is still unclear.

https://gcc.gnu.org/bugzilla/show_bug.cgi?id=103770



regressions tests for PR103770

This adds tests from bugzilla for PR103770 and duplicates.

testsuite/gcc.dg/
* pr103770.c: New test.
* pr103859.c: New test.
* pr105065.c: New test.


diff --git a/gcc/testsuite/gcc.dg/pr103770.c b/gcc/testsuite/gcc.dg/pr103770.c
new file mode 100644
index 000..f7867d1284c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr103770.c
@@ -0,0 +1,27 @@
+/* PR middle-end/103770 */
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+struct struct_s {
+   void* ptr;
+   void* ptr2;
+   void* ptr3;
+};
+
+struct struct_s struct_create(int N, const long vla[N]);
+
+void fun(int N)
+{
+   long vla[N];
+   struct struct_s st = struct_create(N, vla);
+}
+
+
+extern _Complex float g(int N, int dims[N]);
+
+void f(void)
+{
+   int dims[1];
+   _Complex float val = g(1, dims);
+}
+
diff --git a/gcc/testsuite/gcc.dg/pr103859.c b/gcc/testsuite/gcc.dg/pr103859.c
new file mode 100644
index 000..c58be5c15af
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr103859.c
@@ -0,0 +1,23 @@
+/* PR middle-end/103859 */
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+typedef struct dcmplx dcmplx;
+
+struct dcmplx {
+  double re;
+  double im;
+};
+
+dcmplx horner(int n, dcmplx p[n], dcmplx x);
+
+int main(void)
+{
+  int i, n;
+  dcmplx x[n + 1], f[n + 1];
+
+  horner(n + 1, f, x[i]);
+
+  return 0;
+}
+
diff --git a/gcc/testsuite/gcc.dg/pr105065.c b/gcc/testsuite/gcc.dg/pr105065.c
new file mode 100644
index 000..da46d2bb4d8
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr105065.c
@@ -0,0 +1,16 @@
+/* PR middle-end/105065 */
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+typedef struct
+{
+   char filler[17];
+} big_struct;
+
+big_struct dummy(int size, char array[size]);
+
+int main()
+{
+   dummy(0, 0);
+}
+




[C PATCH] (for STAGE 1) UBSan instrumentation for assignment of VM types

2022-12-22 Thread Martin Uecker via Gcc-patches


Here is a first patch to add UBSan instrumentation to
assignment, return, initialization of pointers
to variably modified types. This is based on the
other patch I just sent. Separating these should make
reviewing easier.

Here, I did not add tests for function arguments as
this is more complicated, but this will follow...




c: UBSan instrumentation for assignment of VM types

This adds instrumentation that checks that corresponding
size expression in variably modified types evaluate to
the same value in assignment, function return, and
initialization.

gcc/c-family/
* c-ubsan.cc (ubsan_instrument_vm_assign): New.

gcc/c/
* c-typeck.cc (comptypes_check_enum_int_instr,
comptypes_check_enum_int): New interface for
instrumentation.
(comptypes_internal,convert_for_assignment):
Add instrumentation.
(comp_target_types_instr,comp_target_types): Add
new interface for instrumentation.

gcc/testsuite/gcc.dg/ubsan/
* vm-bounds-1.c: New test.
* vm-bounds-2.c: New test.

 

diff --git a/gcc/c-family/c-ubsan.cc b/gcc/c-family/c-ubsan.cc
index 360ba82250c..7de4e6e7057 100644
--- a/gcc/c-family/c-ubsan.cc
+++ b/gcc/c-family/c-ubsan.cc
@@ -334,6 +334,48 @@ ubsan_instrument_vla (location_t loc, tree size)
   return t;
 }
 
+/* Instrument assignment of variably modified types.  */
+
+tree
+ubsan_instrument_vm_assign (location_t loc, tree a, tree b)
+{
+  tree t, tt;
+
+  gcc_assert (TREE_CODE (a) == ARRAY_TYPE);
+  gcc_assert (TREE_CODE (b) == ARRAY_TYPE);
+
+  tree as = TYPE_MAX_VALUE (TYPE_DOMAIN (a));
+  tree bs = TYPE_MAX_VALUE (TYPE_DOMAIN (b));
+
+  as = fold_build2 (PLUS_EXPR, sizetype, as, size_one_node);
+  bs = fold_build2 (PLUS_EXPR, sizetype, bs, size_one_node);
+
+  t = build2 (NE_EXPR, boolean_type_node, as, bs);
+  if (flag_sanitize_trap & SANITIZE_VLA)
+tt = build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_TRAP), 0);
+  else
+{
+  tree data = ubsan_create_data ("__ubsan_vm_data", 1, &loc,
+ubsan_type_descriptor (a, 
UBSAN_PRINT_ARRAY),
+ubsan_type_descriptor (b, 
UBSAN_PRINT_ARRAY),
+ubsan_type_descriptor (sizetype),
+NULL_TREE, NULL_TREE);
+  data = build_fold_addr_expr_loc (loc, data);
+  enum built_in_function bcode
+   = (flag_sanitize_recover & SANITIZE_VLA)
+ ? BUILT_IN_UBSAN_HANDLE_VM_BOUNDS_MISMATCH
+ : BUILT_IN_UBSAN_HANDLE_VM_BOUNDS_MISMATCH_ABORT;
+  tt = builtin_decl_explicit (bcode);
+  tt = build_call_expr_loc (loc, tt, 3, data,
+   ubsan_encode_value (as),
+   ubsan_encode_value (bs));
+}
+  t = build3 (COND_EXPR, void_type_node, t, tt, void_node);
+
+  return t;
+}
+
+
 /* Instrument missing return in C++ functions returning non-void.  */
 
 tree
diff --git a/gcc/c-family/c-ubsan.h b/gcc/c-family/c-ubsan.h
index 2f31ba36df4..327313c6684 100644
--- a/gcc/c-family/c-ubsan.h
+++ b/gcc/c-family/c-ubsan.h
@@ -26,6 +26,7 @@ extern tree ubsan_instrument_shift (location_t, enum 
tree_code, tree, tree);
 extern tree ubsan_instrument_vla (location_t, tree);
 extern tree ubsan_instrument_return (location_t);
 extern tree ubsan_instrument_bounds (location_t, tree, tree *, bool);
+extern tree ubsan_instrument_vm_assign (location_t, tree, tree);
 extern bool ubsan_array_ref_instrumented_p (const_tree);
 extern void ubsan_maybe_instrument_array_ref (tree *, bool);
 extern void ubsan_maybe_instrument_reference (tree *);
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index ebc9ba88afe..a58b96083e9 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -93,6 +93,7 @@ static tree qualify_type (tree, tree);
 struct comptypes_data;
 static int tagged_types_compatible_p (const_tree, const_tree, struct 
comptypes_data *);
 static int comp_target_types (location_t, tree, tree);
+static int comp_target_types_instr (location_t, tree, tree, tree *);
 static int function_types_compatible_p (const_tree, const_tree, struct 
comptypes_data *);
 static int type_lists_compatible_p (const_tree, const_tree, struct 
comptypes_data *);
 static tree lookup_field (tree, tree);
@@ -1053,6 +1054,9 @@ struct comptypes_data {
 
   bool enum_and_int_p;
   bool different_types_p;
+
+  location_t loc;
+  tree instrument_expr;
 };
 
 /* Return 1 if TYPE1 and TYPE2 are compatible types for assignment
@@ -1075,20 +1079,35 @@ comptypes (tree type1, tree type2)
 /* Like comptypes, but if it returns non-zero because enum and int are
compatible, it sets *ENUM_AND_INT_P to true.  */
 
-int
-comptypes_check_enum_int (tree type1, tree type2, bool *enum_and_int_p)
+static int
+comptypes_check_enum_int_instr (tree type1, tree type2, bool *enum_and_int_p, 
location_t loc, tree *instrument_expr)
 {
   int val;
 
   struct comptypes_data data = { };
+
+  data.loc = loc;
+
+  if (NULL != instrument_expr)

[C PATCH] (for STAGE 1) Reorganize comptypes and related functions

2022-12-22 Thread Martin Uecker via Gcc-patches




Because I want to add another argument to comptypes
and co. for UBSan instrumentation and this then
starts to become a bit unwiedly, here is a patch to
reorganize and simplify this a bit. This can wait
until stage 1. (The cache can be simplified further
by allocating it on the stack, but this can be done
later).



c: Reorganize comptypes and related functions.

Move common arguments and a global variable (the
cache for type compatibility) used by comptypes
and childen into a single structure and pass a
pointer to it.

gcc/c/ 
* c/c-typeck.cc: (comptypes,comptypes_check_enum_int,
comptypes_check_different_types,comptypes_internal,
tagged_types_tu_compatible_p,function_types_compatible_p,
type_lists_compatible_p): Introduce a structure argument.
(alloc_tagged_tu_seen_cache,free_all_tagged_tu_seen_up_to):
Reorganize cache and remove tu from function names.



diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 47fa36f4ec8..ebc9ba88afe 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -90,12 +90,11 @@ static bool require_constexpr_value;
 
 static bool null_pointer_constant_p (const_tree);
 static tree qualify_type (tree, tree);
-static int tagged_types_tu_compatible_p (const_tree, const_tree, bool *,
-bool *);
+struct comptypes_data;
+static int tagged_types_compatible_p (const_tree, const_tree, struct 
comptypes_data *);
 static int comp_target_types (location_t, tree, tree);
-static int function_types_compatible_p (const_tree, const_tree, bool *,
-   bool *);
-static int type_lists_compatible_p (const_tree, const_tree, bool *, bool *);
+static int function_types_compatible_p (const_tree, const_tree, struct 
comptypes_data *);
+static int type_lists_compatible_p (const_tree, const_tree, struct 
comptypes_data *);
 static tree lookup_field (tree, tree);
 static int convert_arguments (location_t, vec, tree,
  vec *, vec *, tree,
@@ -125,7 +124,7 @@ static tree find_init_member (tree, struct obstack *);
 static void readonly_warning (tree, enum lvalue_use);
 static int lvalue_or_else (location_t, const_tree, enum lvalue_use);
 static void record_maybe_used_decl (tree);
-static int comptypes_internal (const_tree, const_tree, bool *, bool *);
+static int comptypes_internal (const_tree, const_tree, struct comptypes_data 
*data);
 
 /* Return true if EXP is a null pointer constant, false otherwise.  */
 
@@ -189,17 +188,16 @@ remove_c_maybe_const_expr (tree expr)
 
 /* This is a cache to hold if two types are compatible or not.  */
 
-struct tagged_tu_seen_cache {
-  const struct tagged_tu_seen_cache * next;
+struct tagged_seen_cache {
+  const struct tagged_seen_cache * next;
   const_tree t1;
   const_tree t2;
-  /* The return value of tagged_types_tu_compatible_p if we had seen
+  /* The return value of tagged_types_compatible_p if we had seen
  these two types already.  */
   int val;
 };
 
-static const struct tagged_tu_seen_cache * tagged_tu_seen_base;
-static void free_all_tagged_tu_seen_up_to (const struct tagged_tu_seen_cache 
*);
+static void free_all_tagged_seen (const struct tagged_seen_cache *);
 
 /* Do `exp = require_complete_type (loc, exp);' to make sure exp
does not have an incomplete type.  (That includes void types.)
@@ -1049,6 +1047,14 @@ common_type (tree t1, tree t2)
   return c_common_type (t1, t2);
 }
 
+struct comptypes_data {
+
+  const struct tagged_seen_cache *seen_base;
+
+  bool enum_and_int_p;
+  bool different_types_p;
+};
+
 /* Return 1 if TYPE1 and TYPE2 are compatible types for assignment
or various other operations.  Return 2 if they are compatible
but a warning may be needed if you use them together.  */
@@ -1056,11 +1062,12 @@ common_type (tree t1, tree t2)
 int
 comptypes (tree type1, tree type2)
 {
-  const struct tagged_tu_seen_cache * tagged_tu_seen_base1 = 
tagged_tu_seen_base;
   int val;
 
-  val = comptypes_internal (type1, type2, NULL, NULL);
-  free_all_tagged_tu_seen_up_to (tagged_tu_seen_base1);
+  struct comptypes_data data = { };
+  val = comptypes_internal (type1, type2, &data);
+
+  free_all_tagged_seen (data.seen_base);
 
   return val;
 }
@@ -1071,11 +1078,13 @@ comptypes (tree type1, tree type2)
 int
 comptypes_check_enum_int (tree type1, tree type2, bool *enum_and_int_p)
 {
-  const struct tagged_tu_seen_cache * tagged_tu_seen_base1 = 
tagged_tu_seen_base;
   int val;
 
-  val = comptypes_internal (type1, type2, enum_and_int_p, NULL);
-  free_all_tagged_tu_seen_up_to (tagged_tu_seen_base1);
+  struct comptypes_data data = { };
+  val = comptypes_internal (type1, type2, &data);
+  *enum_and_int_p = data.enum_and_int_p;
+
+  free_all_tagged_seen (data.seen_base);
 
   return val;
 }
@@ -1087,31 +1096,33 @@ int
 comptypes_check_different_types (tree type1, tree type2,
 bool *different_types_p)
 {
-  const struct tagged_tu_seen_cache * tagged_tu_seen_base1 = 
tagged_tu_seen_base;
   int val;

Re: [C PATCH] remove same_translation_unit_p

2022-12-21 Thread Martin Uecker via Gcc-patches
Am Dienstag, dem 20.12.2022 um 20:04 + schrieb Joseph Myers:
> On Tue, 20 Dec 2022, Martin Uecker via Gcc-patches wrote:
> 
> > Here is a patch to remove the unused function
> > same_translation_unit_p and related code. The
> > code to check for structural equivalency of
> > structs / unions is kept (with some fixes)
> > because it will be needed for C2X.
> 
> Could you repost this in development stage 1, since this is not a bug
> fix?

Sure, I will repost for stage 1.

I plan to send some other similar patches with
no functional change (with no expectation that they
get reviewed now) because I like to get some early
feedback rom Martin Liška on some UBsan changes
which are layered on top of them.


Martin






[C PATCH] remove same_translation_unit_p

2022-12-20 Thread Martin Uecker via Gcc-patches


Here is a patch to remove the unused function
same_translation_unit_p and related code. The
code to check for structural equivalency of
structs / unions is kept (with some fixes)
because it will be needed for C2X.



c: Remove dead code related to type compatibility across TUs. 

Code to detect struct/unions across the same TU is not needed
anymore. Code for determining compatibility of tagged types is
preserved as it will be used for C2X. Some errors in the unused
code are fixed.

Bootstrapped with no regressions for x86_64-pc-linux-gnu.

gcc/c/
* c-decl.cc (set_type_context): Remove.
(pop_scope, diagnose_mismatched_decls, pushdecl):
Remove dead code.
* c-typeck.cc (comptypes_internal): Remove dead code.
(same_translation_unit_p): Remove.
(tagged_types_tu_compatible_p): Some fixes.




diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index e47ca6718b3..307f7a09f5a 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -1155,16 +1155,6 @@ update_label_decls (struct c_scope *scope)
 }
 }
 
-/* Set the TYPE_CONTEXT of all of TYPE's variants to CONTEXT.  */
-
-static void
-set_type_context (tree type, tree context)
-{
-  for (type = TYPE_MAIN_VARIANT (type); type;
-   type = TYPE_NEXT_VARIANT (type))
-TYPE_CONTEXT (type) = context;
-}
-
 /* Exit a scope.  Restore the state of the identifier-decl mappings
that were in effect when this scope was entered.  Return a BLOCK
node containing all the DECLs in this scope that are of interest
@@ -1253,7 +1243,6 @@ pop_scope (void)
case ENUMERAL_TYPE:
case UNION_TYPE:
case RECORD_TYPE:
- set_type_context (p, context);
 
  /* Types may not have tag-names, in which case the type
 appears in the bindings list with b->id NULL.  */
@@ -1361,12 +1350,7 @@ pop_scope (void)
 the TRANSLATION_UNIT_DECL.  This makes
same_translation_unit_p
 work.  */
  if (scope == file_scope)
-   {
  DECL_CONTEXT (p) = context;
- if (TREE_CODE (p) == TYPE_DECL
- && TREE_TYPE (p) != error_mark_node)
-   set_type_context (TREE_TYPE (p), context);
-   }
 
  gcc_fallthrough ();
  /* Parameters go in DECL_ARGUMENTS, not BLOCK_VARS, and have
@@ -2308,21 +2292,18 @@ diagnose_mismatched_decls (tree newdecl, tree
olddecl,
{
  if (DECL_INITIAL (olddecl))
{
- /* If both decls are in the same TU and the new
declaration
-isn't overriding an extern inline reject the new
decl.
-In c99, no overriding is allowed in the same
translation
-unit.  */
- if ((!DECL_EXTERN_INLINE (olddecl)
-  || DECL_EXTERN_INLINE (newdecl)
-  || (!flag_gnu89_inline
-  && (!DECL_DECLARED_INLINE_P (olddecl)
-  || !lookup_attribute ("gnu_inline",
-DECL_ATTRIBUTES
(olddecl)))
-  && (!DECL_DECLARED_INLINE_P (newdecl)
-  || !lookup_attribute ("gnu_inline",
-DECL_ATTRIBUTES
(newdecl
- )
- && same_translation_unit_p (newdecl, olddecl))
+ /* If the new declaration isn't overriding an extern
inline
+reject the new decl. In c99, no overriding is allowed
+in the same translation unit.  */
+ if (!DECL_EXTERN_INLINE (olddecl)
+ || DECL_EXTERN_INLINE (newdecl)
+ || (!flag_gnu89_inline
+ && (!DECL_DECLARED_INLINE_P (olddecl)
+ || !lookup_attribute ("gnu_inline",
+   DECL_ATTRIBUTES
(olddecl)))
+ && (!DECL_DECLARED_INLINE_P (newdecl)
+ || !lookup_attribute ("gnu_inline",
+   DECL_ATTRIBUTES
(newdecl)
{
  auto_diagnostic_group d;
  error ("redefinition of %q+D", newdecl);
@@ -3350,18 +3331,11 @@ pushdecl (tree x)
 type to the composite of all the types of that declaration.
 After the consistency checks, it will be reset to the
 composite of the visible types only.  */
-  if (b && (TREE_PUBLIC (x) || same_translation_unit_p (x, b-
>decl))
- && b->u.type)
+  if (b && b->u.type)
TREE_TYPE (b->decl) = b->u.type;
 
-  /* The point of the same_translation_unit_p check here is,
-we want to detect a duplicate decl for a construct like
-foo() { extern bar(); } ... static bar();  but not if
-they are in different translation units.  In any case,
-the static does not go in the externals scope.  */
-  if (b
- && (TREE_PUBLIC (x) || sam

Re: [PATCH] middle-end IFN_ASSUME support [PR106654]

2022-10-16 Thread Martin Uecker via Gcc-patches
Am Samstag, den 15.10.2022, 10:53 +0200 schrieb Jakub Jelinek:
> On Sat, Oct 15, 2022 at 10:07:46AM +0200, Martin Uecker wrote:
> > But why? Do we really want to encourage people to
> > write such code?
> 
> Of course these ++ cases inside of expressions are just obfuscation.
> But the point is to support using predicates that can be inlined and
> simplified into something really simple the optimizers can understand.

This makes sense,.

> The paper shows as useful e.g. being able to assert something is finite:
> [[assume (std::isfinite (x)]];
> and with the recent changes on the GCC side it is now or shortly will be
> possible to take advantage of such predicates.
> It is true that
> [[assume (__builtin_isfinite (x)]];
> could work if we check TREE_SIDE_EFFECTS on the GCC side because
> it is a const function, but that is a GNU extension, so the standard
> can't count with that.  std::isfinite isn't even marked const in libstdc++
> and one can figure that out during IPA propagation only.

Hm, that already seems to work with

if (!std::isfinite(x))
  __builtin_unreachable();

https://godbolt.org/z/hj3WrEhjb


> There are many similar predicates, or user could have some that are useful
> to his program.  And either in the end it wouldn't have side-effects
> but the compiler doesn't know, or would but those side-effects would be
> unimportant to the optimizations the compiler can derive from those.

I still have the feeling that relying on something
such as the pure and const attributes might then
be a better approach for this.

>From the standards point of view, this is OK
as GCC can just set its own rules as long as it is
a subset of what the standard allows.

> As the spec defines it well what happens with the side-effects and it
> is an attribute, not a function and the languages have non-evaluated
> contexts in other places, I don't see where a user confusion could come.

The user confusion might come when somebody writes
something such as [[assume(1 == ++i)]] and I expect
that people will start doing this once this works.


But I am also a a bit worried about the slipperly slope
of exploiting this more because what "would evaluate to true"
implies in case of I/O, atomic accesses, volatile accesses 
etc.  does not seem clear to me.   But maybe I am worrying
too much.


> We don't warn for sizeof (i++) and similar either.

Which is also confusing and clang does indeed
warn about it outside of macros and I think GCC
should too.

> __builtin_assume (i++) is a bad choice because it looks like a function
> call (after all, the compilers have many similar builtins) and its argument
> looks like normal argument to the function, so it is certainly unexpected
> that the side-effects aren't evaluated.

I agree.

Best
Martin




Re: [PATCH] middle-end IFN_ASSUME support [PR106654]

2022-10-15 Thread Martin Uecker via Gcc-patches
Am Freitag, den 14.10.2022, 23:20 +0200 schrieb Jakub Jelinek:
> On Fri, Oct 14, 2022 at 10:43:16PM +0200, Martin Uecker wrote:
> > Am Montag, den 10.10.2022, 10:54 +0200 schrieb Jakub Jelinek:
> > > Hi!
> > > 
> > > My earlier patches gimplify the simplest non-side-effects assumptions
> > > into if (cond) ; else __builtin_unreachable (); and throw the rest
> > > on the floor.
> > > The following patch attempts to do something with the rest too.
> > 
> > My recommendation would be to only process side-effect-free
> > assumptions and warn about the rest (clang does this for
> > __builtin_assume).   I do not think this is worth the
> 
> I think that is bad choice and makes it useless.

I think

[[assume(10 == i + 1)]]

could be useful as it is nicer syntax than

if (10 != i + 1)
  unreachable();

 but

[[assume(10 == i++)]]

is confusing / untestable and therefor seems a bit
dangerous. 

But we do not have to agree, I just stating my opinion
here. I would personally then suggest to have an
option for warning about side effects in assume.

> > complexity and I am not so sure the semantics of a
> > hypothetical evaluation are terribly well defined.
> 
> I think the C++23 paper is quite clear.  Yes, you can't verify it
> in debug mode, but there are many other UBs that are hard to verify
> through runtime instrumentation.

And none are good. Some are very useful though
(or even required in the context of C/C++). But I think
there should be a very good reason for adding more.

Personally, I do not see [[assume]] how side effects
is useful enough to justify adding another kind of
untestable UB.

Especially also because it has somewhat vaguely 
defined semantics. I don't know any formalization the
proposed semantics and the normative wording
"the converted expression would evaluate to true"
is probably good starting point for a PhD thesis.


> And, OpenMP has a similar feature (though, in that case it is even
> a stronger guarantee where something is guaranteed to hold across
> a whole region rather than just on its entry.
>
> > That you can not verify this properly by turning it
> > into traps in debug mode (as this would execute the
> > side effects) also makes this a terrible feature IMHO.
> > 
> > MSVC which this feature was based does not seem to make
> > much to sense to me: https://godbolt.org/z/4Ebar3G9b
> 
> So maybe their feature is different from what is in C++23,
> or is badly implemented?

The paper says as the first sentence in the abstract:

"We propose a standard facility providing the semantics
of existing compiler built-ins such as
__builtin_assume (Clang) and __assume (MSVC, ICC)."

But Clang does not support side effects and MSVC
is broken.  But yes, the paper then describes these
extended semantics for expression with side effects. 
According to the author this was based on discussions
with MSVC developers, but - to me - the fact that MSVC
still implements something else which does not seem
to make sense speaks against this feature.


> I think with what we have in the works for GCC we'll be able to optimize
> in
> int f(int i)
> {
>   [[assume(1 == i++)]];
>   return (1 == i++);
> }
> 
> int g(int i)
> {
>   [[assume(1 == ++i)]];
>   return (1 == ++i);
> }
> 
> extern int i;
> 
> int h(void) 
> {
>   [[assume(1 == ++i)]];
>   return (1 == ++i);
> }
> 
> 
> int k(int i)
> {
>   [[assume(42 == ++i)]];
>   return i;
> }
> at least f/g to return 1; and k to return 41;
> The h case might take a while to take advantage of.

But why? Do we really want to encourage people to
write such code?


Martin





Re: [PATCH] middle-end IFN_ASSUME support [PR106654]

2022-10-14 Thread Martin Uecker via Gcc-patches
Am Montag, den 10.10.2022, 10:54 +0200 schrieb Jakub Jelinek:
> Hi!
> 
> My earlier patches gimplify the simplest non-side-effects assumptions
> into if (cond) ; else __builtin_unreachable (); and throw the rest
> on the floor.
> The following patch attempts to do something with the rest too.

My recommendation would be to only process side-effect-free
assumptions and warn about the rest (clang does this for
__builtin_assume).   I do not think this is worth the
complexity and I am not so sure the semantics of a
hypothetical evaluation are terribly well defined.
That you can not verify this properly by turning it
into traps in debug mode (as this would execute the
side effects) also makes this a terrible feature IMHO.

MSVC which this feature was based does not seem to make
much to sense to me: https://godbolt.org/z/4Ebar3G9b


Martin



> For -O0, it actually throws even the simplest assumptions on the floor,
> we don't expect optimizations and the assumptions are there to allow
> optimizations.  Otherwise, it keeps the handling of the simplest
> assumptions as is, and otherwise arranges for the assumptions to be
> visible in the IL as
>   .ASSUME (_Z2f4i._assume.0, i_1(D));
> call where there is an artificial function like:
> bool _Z2f4i._assume.0 (int i)
> {
>   bool _2;
> 
>[local count: 1073741824]:
>   _2 = i_1(D) == 43;
>   return _2;
> 
> }
> with the semantics that there is UB unless the assumption function
> would return true.
> 
> Aldy, could ranger handle this?  If it sees .ASSUME call,
> walk the body of such function from the edge(s) to exit with the
> assumption that the function returns true, so above set _2 [true, true]
> and from there derive that i_1(D) [43, 43] and then map the argument
> in the assumption function to argument passed to IFN_ASSUME (note,
> args there are shifted by 1)?
> 
> During gimplification it actually gimplifies it into
>   D.2591 = .ASSUME ();
>   if (D.2591 != 0) goto ; else goto ;
>   :
>   {
> i = i + 1;
> D.2591 = i == 44;
>   }
>   :
>   .ASSUME (D.2591);
> with the condition wrapped into a GIMPLE_BIND (I admit the above isn't
> extra clean but it is just something to hold it from gimplifier until
> gimple low pass; it reassembles if (condition_never_true) { cond; };
> an alternative would be introduce GOMP_ASSUME statement that would have
> the guard var as operand and the GIMPLE_BIND as body, but for the
> few passes (tree-nested and omp lowering) in between that looked like
> an overkill to me) which is then pattern matched during gimple lowering
> and outlined into a separate function.  Variables declared inside of the
> condition (both static and automatic) just change context, automatic
> variables from the caller are turned into parameters (note, as the code
> is never executed, I handle this way even non-POD types, we don't need to
> bother pretending there would be user copy constructors etc. involved).
> 
> The assume_function artificial functions are then optimized until RTL
> expansion, which isn't done for them nor any later pass, on the other
> side bodies are not freed when done.
> 
> Earlier version of the patch has been successfully bootstrapped/regtested
> on x86_64-linux and i686-linux and all assume tests have passed even with
> this version.  Ok for trunk if it succeeds on another bootstrap/regtest?
> 
> There are a few further changes I'd like to do, like ignoring the
> .ASSUME calls in inlining size estimations (but haven't figured out where
> it is done), or for LTO arrange for the assume functions to be emitted
> in all partitions that reference those (usually there will be just one,
> unless code with the assumption got inlined, versioned etc.).
> 
> 2022-10-10  Jakub Jelinek  
> 
>   PR c++/106654
> gcc/
>   * function.h (struct function): Add assume_function bitfield.
>   * gimplify.cc (gimplify_call_expr): For -O0, always throw
>   away assumptions on the floor immediately.  Otherwise if the
>   assumption isn't simple enough, expand it into IFN_ASSUME
>   guarded block.
>   * gimple-low.cc (create_assumption_fn): New function.
>   (struct lower_assumption_data): New type.
>   (find_assumption_locals_r, assumption_copy_decl,
>   adjust_assumption_stmt_r, adjust_assumption_stmt_op,
>   lower_assumption): New functions.
>   (lower_stmt): Handle IFN_ASSUME guarded block.
>   * tree-ssa-ccp.cc (pass_fold_builtins::execute): Remove
>   IFN_ASSUME calls.
>   * lto-streamer-out.cc (output_struct_function_base): Pack
>   assume_function bit.
>   * lto-streamer-in.cc (input_struct_function_base): And unpack it.
>   * cgraphunit.cc (cgraph_node::expand): Don't verify assume_function
>   has TREE_ASM_WRITTEN set and don't release its body.
>   * cfgexpand.cc (pass_expand::execute): Don't expand assume_function
>   into RTL, just destroy loops and exit.
>   * internal-fn.cc (expand_ASSUME): Remove gcc_unreachable.
>   * passes.cc (pass_rest

Re: [PATCH, CFE] N2863: Improved Rules for Tag Compatibility

2022-06-07 Thread Martin Uecker
Am Dienstag, den 07.06.2022, 14:22 + schrieb Joseph Myers:
> On Tue, 7 Jun 2022, Martin Uecker wrote:
> 
> > here is a preliminary patch the implements the proposed
> > tag compatibility rules for C23 in GCC (N2863). It works
> 
> I don't see any response on the reflector to my comments on that proposal 
> (message 21374, Fri, 14 Jan 2022 23:32:47 +).  Nor do I see any tests 
> in this patch dealing with the questions of exactly when struct and union 
> types are complete or incomplete, as in my first comment there (if there 
> are any tests concerning that, it's not apparent for lack of comments 
> explaining what exactly the tests are trying to test).  I think we'll need 
> a version of the proposal without known issues before the patch is fully 
> reviewable.

Thanks Joseph! I will revisit the wording next and then resend
the patch with the corresponing tests.

Martin


> 
> > - the feature has a flag (-ftag-compat) which is now turned
> > on by default in all language modes to facilitate testing
> > and to identify backwards compatibility problems. Turned on,
> > it survives bootstrapping and regression testing with
> > only a few cases that test for diagnostics that go
> > away changed to turn it off.
> 
> Turning on by default in past language modes seems questionable other than 
> for this sort of preliminary testing (in any case, incompatible with 
> previous standard requirements so can't be enabled for strict conformance 
> modes). 
> (And in general I'd discourage adding options for individual 
> language feature like that, with the resulting proliferation of dialects 
> with different combinations of features - again, it may be useful for 
> testing purposes, especially before we know whether the feature gets into 
> C23, and it may be useful within the compiler sources to distinguish in 
> some way which places are checking for this feature rather than just 
> testing flag_isoc2x, but actually releasing with a command-line option for 
> it is more problematic.)
> 
> > diff --git a/gcc/testsuite/gcc.dg/tag-compat2.c
> > b/gcc/testsuite/gcc.dg/tag-compat2.c
> > new file mode 100644
> > index 000..20dc1a9c894
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.dg/tag-compat2.c
> > @@ -0,0 +1,47 @@
> > +/*
> > + * { dg-do compile }
> > + * { dg-options "-ftag-compat" }
> > + */
> > +
> > +typedef struct bar { int x; } X;
> > +typedef struct bar { float x; } Y; /* { dg-warning "redefinition of
> > struct or union" } */
> 
> I'd expect conflicting definitions of a type in the same scope to remain 
> errors, not warnings, regardless of this feature.
> 



[PATCH, CFE] N2863: Improved Rules for Tag Compatibility

2022-06-07 Thread Martin Uecker


Hello Joseph and all,


here is a preliminary patch the implements the proposed
tag compatibility rules for C23 in GCC (N2863). It works
by tweaking the diagnostics in the FE and by recording
structs/union types to be able to set TYPE_CANONICAL to
a canonical definition (as per previous discussions).

 
Overall, this seems to work very well when testing
on my own projects. There are still some issues
left that I want to point out:

- at the moment, all struct/union types are collected
in a vector. This needs to be replaced by a hash table.

- the feature has a flag (-ftag-compat) which is now turned
on by default in all language modes to facilitate testing
and to identify backwards compatibility problems. Turned on,
it survives bootstrapping and regression testing with
only a few cases that test for diagnostics that go
away changed to turn it off.

- The new rules are not applied to structs with variable
sized members (which are a GNU extension).

- In contrast to the published proposal, structs without
tags are now treated as incompatible as requested by WG14.

- There is still one assertion in ipa-free-lang-data I had
to conditionally turn off and did not have time to 
investigate.  Otherwise, there are only C FE changes.
LTO may still need some more testing.

- It fixes some bugs in (formerly) unused FE code
and removes some other dead code. This could be
moved into its own patch.

- If adopted into C, I assume we need some
compatibility warnings. From testing, I could
not identify any backwards compatibility problems.

- There are certainly some issues I may have
overlooked.


Martin


gcc/
* c-family/c.opt: Add -ftag-compat flag.
* c/c-decl.cc (pop_scope): Remove dead code. 
(diagnose_mismatched_decls): Support for 
new tag compatibility rules.
(start_struct): Dito.
(finish_struct): Dito.
(start_enum): Dito.
(finish_enum): Dito.
(build_enumerator): Pass enumtype to build_decl.
(c_simulate_enum_decl): Pass enumtype to 
build_enumerator.
* c/c-parser.cc (c_parser_enum_specifier): Dito.
* c/c-tree.h (build_enumerator): Add enumtype 
argument.
* c/c-typeck.cc (comptypes_internal): Support
for new tag compatibility rules.
(same_translation_unit_p): Removed.
(tagged_types_tu_compatible_p): Bug fixes and
support for new tag compatibility rules.
(convert_for_assignment): Support for new tag
compatibility rules
(digest_init): Dito.
* ipa-free-lang-data.cc (fld_incomplete_type_of):
Conditionally turn of assertion related to
TYPE_CANONICAL if -ftag-compat is on.
doc/
* invoke.texi: Document -ftag-compat flag.
testsuite/
* gcc.dg/asan/pr81460.c: Add -fno-tag-compat.
* gcc.dg/c99-tag-1.c: Add -fno-tag-compat.
* gcc.dg/c99-tag-2.c: Add -fno-tag-compat. 
* gcc.dg/decl-3.c: Add -fno-tag-compat.
* gcc.dg/enum-redef-1.c: Add -fno-tag-compat.
* gcc.dg/parm-incomplete-1.c: Add -fno-tag-compat.
* gcc.dg/pr17188-1.c: Add -fno-tag-compat.
* gcc.dg/pr18809-1.c: Add -pedantic-errors and
-fno-tag-compat.
* gcc.dg/pr27953.c: Add -fno-tag-compat.
* gcc.dg/pr39084.c: Add -fno-tag-compat.
* gcc.dg/pr68533.c: Add -fno-tag-compat.
* gcc.dg/pr79983.c: Add -fno-tag-compat.
* gcc.dg/pr89211.c: Add -fno-tag-compat.
* gcc.dg/tag-compat.c: New test.
* gcc.dg/tag-compat10.c: New test.
* gcc.dg/tag-compat11.c: New test.
* gcc.dg/tag-compat12.c: New test.
* gcc.dg/tag-compat2.c: New test.
* gcc.dg/tag-compat3.c: New test.
* gcc.dg/tag-compat4.c: New test.
* gcc.dg/tag-compat5.c: New test.
* gcc.dg/tag-compat6.c: New test.
* gcc.dg/tag-compat7.c: New test.
* gcc.dg/tag-compat8.c: New test.
* gcc.dg/tag-compat9.c: New test.
* gcc.dg/vla-11.c: Add -fno-tag-compat.
* gcc.dg/vla-stexp-2.c: Add -fno-tag-compat.



diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 41a20bc625e..cd3164018f2 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -2108,6 +2108,9 @@ Enum(strong_eval_order) String(some) Value(1)
 EnumValue
 Enum(strong_eval_order) String(all) Value(2)
 
+ftag-compat
+C Var(flag_tag_compat) Init(1)
+
 ftemplate-backtrace-limit=
 C++ ObjC++ Joined RejectNegative UInteger
Var(template_backtrace_limit) Init(10)
 Set the maximum number of template instantiation notes for a single
warning or error.
diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 5266a61b859..df208a310f9 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -599,6 +599,10 @@ public:
   auto_vec typedefs_seen;
 };
 
+
+/* All tagged typed so that TYPE_CANONICAL can be set correctly.  */
+static auto_vec all_structs;
+
 /* Information for the struct or union currently being parsed, or
NULL if not parsing a struct or union.  */
 static class c_struct_parse_info *struct_parse_info;
@@ -1354,8 +1358,8 @@ pop_scope (void)
  BLOCK_VARS (block) = extp;
}
  /* If this is the file scope set DECL_CONTEXT of each decl
to
-the TRANSLATION_UNIT_DECL.  This makes
same_translation_unit_p
-work.  */
+the TRANSLATION_UNIT_DECL.  */
+
  if (scope == file_scope)
{
  DECL_CON

Re: [PATCH 0/2] tree-optimization/104530 - proposed re-evaluation.

2022-02-23 Thread Martin Uecker via Gcc-patches
> 
> On 2/22/2022 10:57 AM, Jakub Jelinek via Gcc-patches wrote:
> > On Tue, Feb 22, 2022 at 12:39:28PM -0500, Andrew MacLeod wrote:
> >>> That is EH, then there are calls that might not return because they leave
> >>> in some other way (e.g. longjmp), or might loop forever, might exit, might
> >>> abort, trap etc.
> >> Generally speaking, calls which do not return should not now be a 
> >> problem...
> >> as long as they do not transfer control to somewhere else in the current
> >> function.
> > I thought all of those cases are very relevant to PR104530.
> > If we have:
> >_1 = ptr_2(D) == 0;
> >// unrelated code in the same bb
> >_3 = *ptr_2(D);
> > then in light of PR104288, we can optimize ptr_2(D) == 0 into true only if
> > there are no calls inside of "// unrelated code in the same bb"
> > or if all calls in "// unrelated code in the same bb" are guaranteed to
> > return exactly once.  Because, if there is a call in there which could
> > exit (that is the PR104288 testcase), or abort, or trap, or loop forever,
> > or throw externally, or longjmp or in any other non-UB way
> > cause the _1 = ptr_2(D) == 0; stmt to be invoked at runtime but
> > _3 = *ptr_2(D) not being invoked, then we can't optimize the earlier
> > comparison because ptr_2(D) could be NULL in a valid program.
> > While if there are no calls (and no problematic inline asms) and no trapping
> > insns in between, we can and PR104530 is asking that we continue to optimize
> > that.
> Right.  This is similar to some of the restrictions we deal with in the 
> path isolation pass.  Essentially we have a path, when traversed, would 
> result in a *0.  We would like to be able to find the edge upon-which 
> the *0 is control dependent and optimize the test so that it always went 
> to the valid path rather than the *0 path.
> 
> The problem is there may be observable side effects on the *0 path 
> between the test and the actual *0 -- including calls to nonreturning 
> functions, setjmp/longjmp, things that could trap, etc.  This case is 
> similar.  We can't back-propagate the non-null status through any 
> statements with observable side effects.

There are cases with volatile accesses where
this is currently not the case.

Also there is a proposal for C++ to require
an explicit std::observable fence to make sure
observable side effects are not undone by
later UB. (see the discussion about "reordering
of trapping operations and volatile" in
Janunary on the gcc list)

In my opinion it is much better if a compiler
makes sure to preserve observable side effects
even in code path with later UB (because the
behavior may otherwise be surprising and existing
code may be broken in a subtle way).  If I
understand you correctly, GCC intends to do
this.

Can we then also agree that the remaining volatile
cases used be fixed?


Martin







[C PATCH] Evaluate argument of sizeof that are structs of variable size.

2021-08-12 Thread Martin Uecker



Joseph,

here is the patch for c_expr_sizeof_type you had suggested.


Best,
Martin



Evaluate type arguments of sizeof that are structs of variable size [PR101838]

Evaluate type arguments of sizeof for all types of variable size
and not just for VLAs. This fixes PR101838 and some issues related 
to PR29970 where statement expressions need to be evaluated so that
the size is well defined.

2021-08-12  Martin Uecker  

gcc/c/
PR c/101838
PR c/29970
* c-typeck.c (c_expr_sizeof_type): Evaluate
size expressions for structs of variable size.

gcc/testsuite/
PR c/101838
* gcc.dg/vla-stexp-2.c: New test.
   




diff --git a/gcc/c/c-typeck.c b/gcc/c/c-typeck.c
index c5bf3372321..eb5c87dc57a 100644
--- a/gcc/c/c-typeck.c
+++ b/gcc/c/c-typeck.c
@@ -3022,8 +3022,14 @@ c_expr_sizeof_type (location_t loc, struct c_type_name 
*t)
   c_last_sizeof_loc = loc;
   ret.original_code = SIZEOF_EXPR;
   ret.original_type = NULL;
+  if (type == error_mark_node)
+{
+  ret.value = error_mark_node;
+  ret.original_code = ERROR_MARK;
+}
+  else
   if ((type_expr || TREE_CODE (ret.value) == INTEGER_CST)
-  && c_vla_type_p (type))
+  && C_TYPE_VARIABLE_SIZE (type))
 {
   /* If the type is a [*] array, it is a VLA but is represented as
 having a size of zero.  In such a case we must ensure that
diff --git a/gcc/testsuite/gcc.dg/vla-stexp-2.c 
b/gcc/testsuite/gcc.dg/vla-stexp-2.c
new file mode 100644
index 000..4d4a15d34a6
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vla-stexp-2.c
@@ -0,0 +1,33 @@
+/* PR101838-*/
+/* { dg-do run } */
+/* { dg-options "-Wpedantic -O0" } */
+
+
+int bar0(
+   int (*a)[*],
+   int (*b)[sizeof(*a)]
+);
+
+
+int bar(
+   struct f {  /* { dg-warning "will not be visible outside of 
this definition" } */
+   int a[*]; } v,  /* { dg-warning "variably modified type" } */
+   int (*b)[sizeof(struct f)]  // should not warn about zero size
+);
+
+int foo(void)
+{
+   int n = 0;
+   return sizeof(typeof(*({ n = 10; struct foo {   /* { dg-warning 
"braced-groups" } */
+   int x[n];   /* { dg-warning 
"variably modified type" } */
+   } x; &x; })));
+}
+
+
+int main()
+{
+   if (sizeof(struct foo { int x[10]; }) != foo())
+   __builtin_abort();
+
+   return 0;
+}



Re: [PATCH] Fix ICE when mixing VLAs and statement expressions [PR91038]

2021-08-09 Thread Martin Uecker



Am Montag, den 09.08.2021, 15:52 +0200 schrieb Eric Botcazou:
> > I think the patch makes sense but the comment says
> > 
> >  Java requires that we elaborated nodes in source order.  That
> >  means we must gimplify the inner expression followed by each
> > of
> >  the indices, in order.  But we can't gimplify the inner
> >  expression until we deal with any variable bounds, sizes, or
> >  positions in order to deal with PLACEHOLDER_EXPRs.
> > 
> > and I don't really understand that (not to say Java is no longer
> > supported
> > by GCC, but Ada does use PLACEHOLDER_EXPRs).  In fact the comment
> > suggests that we _should_ gimplify the inner expression first ...
> > at least
> > it seems to after your explanations ;)
> 
> We already gimplify the inner expression first, i.e. before indices
> and  operands, but we gimplify the "annotations" (special operands)
> before.
> 
> > Eric - do you know anything about this?
> 
> If the comment is right, then Martin's patch should break Ada indeed.
> 

Yes, it breaks Ada. I already found this out 
in the meanwhile.

But I do not understand how this works with the
PLACEHOLDER_EXPR.

My understanding of this is that this is for referring 
to some field of an outer struct which is then used in the
size expression, e.g. something like this (using
C syntax):

struct foo {
  int len;
  float (*x)[3][len];
};

And then for

struct foo* p;

p->x[1][1];  

we use the field 'len' of the struct pointed to by 'p'
the size expression.

But then why would you gimplify the size expression before
the base expression?  I would assume that you also want
to process the base expression first, because it is the
source of the struct which we access in the size expression.

Best,
Martin



















Re: Re: [PATCH] Fix ICE when mixing VLAs and statement expressions [PR91038]

2021-08-03 Thread Martin Uecker
Am Dienstag, den 03.08.2021, 11:26 +0200 schrieb Richard Biener:
> On Tue, Aug 3, 2021 at 10:28 AM Martin Uecker  wrote:


> 
> Does the same issue arise with writing the testcases as
> 
>  ({ ... }) + i;
> 
> ?  How can we fix it then if you also need to support
> 
>  i + ({ ...});
> 
> ?

Here, the FE always moves the pointer to the right and
then produces something like:

*((int *) TARGET_EXPR  + ((sizetype) SAVE_EXPR  + 1) * 20);


So these are the cases which already work without
the path, although maybe it is wrong to have
the n in the SAVE_EXPR?

It gets gimplified to something like this,
which works:

  int[0:D.1959][0:D.1955] * D.1952;
  int n.0;
  sizetype D.1955;
  sizetype D.1959;
 
  {
int n;
int[0:D.1959][0:D.1955] * x;

n = 10;
n.0 = n;

...

_32 = (sizetype) n.0;
_33 = (sizetype) n.1;
_34 = _32 * _33;
_35 = _34 * 4;
x = __builtin_malloc (_35);
D.1952 = x;
  }
  _36 = (sizetype) n.0;
  _37 = _36 + 1;
  _38 = _37 * 20;
  _39 = D.1952 + _38;
 

For the array ref, the FE produces:


  (*TARGET_EXPR )[5][5];


With the patch, we get something like
the following in GIMPLE, which seems correct:

  int[0:D.1958][0:D.1954] * D.1951;
  int n.0;
  sizetype D.1954;

  {
int n;
int[0:D.1958][0:D.1954] * x;

n = 10;
n.0 = n;
 
_7 = (sizetype) n.0;
_8 = _7 * 4;
D.1956 = _8;

n.1 = n
 
_22 = (sizetype) n.0;
_23 = (sizetype) n.1;
_24 = _22 * _23;
_25 = _24 * 4;
x = __builtin_malloc (_25);
D.1951 = x;
  }
  _26 = D.1956 /[ex] 4;
  c = (*D.1951)[5]{lb: 0 sz: _26 * 4}[5];
 

MArtin



Re: Re: [PATCH] Fix ICE when mixing VLAs and statement expressions [PR91038]

2021-08-03 Thread Martin Uecker



Am Dienstag, den 03.08.2021, 11:26 +0200 schrieb Richard Biener:
> On Tue, Aug 3, 2021 at 10:28 AM Martin Uecker 
> wrote:
> > 
> > Hi
> > Am Dienstag, den 03.08.2021, 10:10 +0200 schrieb Richard Biener:
> > > On Tue, Aug 3, 2021 at 7:32 AM Martin Uecker 
> > > wrote:
> > > > 
> > > > (resending from a different account, as emails seem to do not
> > > > go out from my other account at this time)
> > > > 
> > > > Am Montag, den 02.08.2021, 16:05 +0200 schrieb Martin Uecker:
> > > > > > On Sun, Aug 1, 2021 at 7:37 PM Uecker, Martin
> > > > > >  wrote:
> > > > > > > Here is an attempt to fix some old and annoying bugs
> > > > > > > related
> > > > > > > to VLAs and statement expressions. In particulary, this
> > > > > > > seems
> > > > > > > to fix the issues with variably-modified types which are
> > > > > > > returned from statement expressions (which works on
> > > > > > > clang),
> > > > > > > but there are still bugs remaining related to structs
> > > > > > > with VLA members (which seems to be a FE bug).
> > > > > > > 
> > > > > > > Of course, I might be doing something stupid...
> > > > > > 
> > > > > > How's evaluation order of (f())[g()] defined (with f
> > > > > > returning
> > > > > > a
> > > > > > pointer)?
> > > > > > Isn't that just f() + g()*sizeof(int) and thus undefined?
> > > > > 
> > > > > Yes, in C it is
> > > > > 
> > > > > f() + g()
> > > > > 
> > > > > and it is unsequenced. But the order of 'f' and 'g'
> > > > > is not relevant here and also the patch does not change
> > > > > it (the base expression is gimplified before the index).
> > > > > 
> > > > > Essentially, we have
> > > > > 
> > > > > ({ ... }) + g() * sizeof(X)
> > > > > 
> > > > > where X refers to a declaration in the statement expression.
> > > > > Without the patch the size expressions are gimplified before
> > > > > the base expression and also before the index expression.
> > > > > With the patch the ({ ... }) is gimplified also before the
> > > > > size expression.
> > > > > 
> > > > > > If it's undefined then I think the incoming GENERIC is ill-
> > > > > > defined.
> > > > > 
> > > > > I think it is OK because the arguments are evaluated
> > > > > before the operation.  Without the patch, parts of the
> > > > > operation (the size expressions) are gimplified before
> > > > > the arguments and this seems wrong to me.
> > > 
> > > But you said the evaluation order is undefined.
> > 
> > The evaluation order of the two arguments (base
> > and index) is undefined.  But the operation itself has
> > to happen after the arguments are evaluated like
> > the call to a is sequenced before f and g:
> > 
> > a(f(), g())
> > 
> > 
> > Computing the correct step size in the pointer
> > arithmetic is part of the operation itself and not
> > part of the evaluation of the arguments.
> > 
> > The problem here is that this part of the operation
> > is done before the arguments are evaluated, which
> > is a compiler bug.
> 
> Yes, but the bug is IMHO in the C frontend which inserts the
> DECL_EXPR at a wrong spot, not making sure it is evaluated before it
> is used.  Working around this deficiency in the gimplifier sounds
> incorrect.

The size if part of the type of the value which is 
returned from the compound  expression. 

So that there is a declaration involved was maybe
misleading in my example and explanation.  

So let me try again:

The size *expression* needs be be computed inside the 
statement expression (also because of side effects)
and then the result of this computation needs to 
returned together (as part of) the value returned 
by the statement expression. 

But the compilers tries to gimplify the size expression 
that  comes with the value already before the statement 
expression is evaluated. This can not work, no matter
what the front end does.

> 
> Does the same issue arise with writing the testcases as
> 
>  ({ ... }) + i;
> 
> ?  How can we fix it then if you also need to support
> 
>  i + ({ ...});
> 
> 
> ?

This already works correctly. I assume that here
the gimplifcation is  already  done in the right 
order.

But ARRAY_REF is handled as a separate case and
there it is wrong.

Martin

> 
> > > So IMHO the GENERIC is undefined in evaluating the size of sth
> > > that's not live?
> > > 
> > >  That said, given the statement expression
> > > result undergoes array to pointer decay doesn't this pointer
> > > refer to an object that ended its lifetime?
> > > "In a statement expression, any temporaries created within a
> > > statement are destroyed at that statement's end."
> > > That is, don't the testcases all invoke undefined behavior at
> > > runtime?
> > 
> > This is true for one of the test cases (where not having
> > an ICE is then
> > a QoI issue), but not for the others
> > where the object is allocated by
> > malloc and a pointer
> > to the object is returned from the statement
> > expression.
> > This is supposed to work.
> > 
> > 
> > Martin
> > 
> > 
> > 



Re: Re: [PATCH] Fix ICE when mixing VLAs and statement expressions [PR91038]

2021-08-03 Thread Martin Uecker


Hi 
Am Dienstag, den 03.08.2021, 10:10 +0200 schrieb Richard Biener:
> On Tue, Aug 3, 2021 at 7:32 AM Martin Uecker  wrote:
> > 
> > 
> > (resending from a different account, as emails seem to do not
> > go out from my other account at this time)
> > 
> > Am Montag, den 02.08.2021, 16:05 +0200 schrieb Martin Uecker:
> > > > On Sun, Aug 1, 2021 at 7:37 PM Uecker, Martin
> > > >  wrote:
> > > > > 
> > > > > Here is an attempt to fix some old and annoying bugs related
> > > > > to VLAs and statement expressions. In particulary, this seems
> > > > > to fix the issues with variably-modified types which are
> > > > > returned from statement expressions (which works on clang),
> > > > > but there are still bugs remaining related to structs
> > > > > with VLA members (which seems to be a FE bug).
> > > > > 
> > > > > Of course, I might be doing something stupid...
> > > > 
> > > > How's evaluation order of (f())[g()] defined (with f returning
> > > > a
> > > > pointer)?
> > > > Isn't that just f() + g()*sizeof(int) and thus undefined?
> > > 
> > > Yes, in C it is
> > > 
> > > f() + g()
> > > 
> > > and it is unsequenced. But the order of 'f' and 'g'
> > > is not relevant here and also the patch does not change
> > > it (the base expression is gimplified before the index).
> > > 
> > > Essentially, we have
> > > 
> > > ({ ... }) + g() * sizeof(X)
> > > 
> > > where X refers to a declaration in the statement expression.
> > > Without the patch the size expressions are gimplified before
> > > the base expression and also before the index expression.
> > > With the patch the ({ ... }) is gimplified also before the
> > > size expression.
> > > 
> > > > If it's undefined then I think the incoming GENERIC is ill-
> > > > defined.
> > > 
> > > I think it is OK because the arguments are evaluated
> > > before the operation.  Without the patch, parts of the
> > > operation (the size expressions) are gimplified before
> > > the arguments and this seems wrong to me.
> 
> But you said the evaluation order is undefined.

The evaluation order of the two arguments (base
and index) is undefined.  But the operation itself has
to happen after the arguments are evaluated like
the call to a is sequenced before f and g:

a(f(), g())


Computing the correct step size in the pointer
arithmetic is part of the operation itself and not
part of the evaluation of the arguments.

The problem here is that this part of the operation
is done before the arguments are evaluated, which
is a compiler bug.

> So IMHO the GENERIC is undefined in evaluating the size of sth
> that's not live? 
>
>  That said, given the statement expression
> result undergoes array to pointer decay doesn't this pointer
> refer to an object that ended its lifetime?

> "In a statement expression, any temporaries created within a
> statement are destroyed at that statement's end."

> That is, don't the testcases all invoke undefined behavior at
> runtime?

This is true for one of the test cases (where not having
an ICE is then
a QoI issue), but not for the others
where the object is allocated by
malloc and a pointer
to the object is returned from the statement
expression.
This is supposed to work.


Martin





Re: Re: [PATCH] Fix ICE when mixing VLAs and statement expressions [PR91038]

2021-08-02 Thread Martin Uecker



(resending from a different account, as emails seem to do not
go out from my other account at this time)

Am Montag, den 02.08.2021, 16:05 +0200 schrieb Martin Uecker:
> > On Sun, Aug 1, 2021 at 7:37 PM Uecker, Martin
> >  wrote:
> > > 
> > > 
> > > Here is an attempt to fix some old and annoying bugs related
> > > to VLAs and statement expressions. In particulary, this seems
> > > to fix the issues with variably-modified types which are
> > > returned from statement expressions (which works on clang),
> > > but there are still bugs remaining related to structs
> > > with VLA members (which seems to be a FE bug).
> > > 
> > > Of course, I might be doing something stupid...
> > 
> > How's evaluation order of (f())[g()] defined (with f returning a
> > pointer)?
> > Isn't that just f() + g()*sizeof(int) and thus undefined?
> 
> Yes, in C it is
> 
> f() + g()
> 
> and it is unsequenced. But the order of 'f' and 'g'
> is not relevant here and also the patch does not change 
> it (the base expression is gimplified before the index).
> 
> Essentially, we have
> 
> ({ ... }) + g() * sizeof(X) 
> 
> where X refers to a declaration in the statement expression.
> Without the patch the size expressions are gimplified before
> the base expression and also before the index expression. 
> With the patch the ({ ... }) is gimplified also before the
> size expression.
> 
> > If it's undefined then I think the incoming GENERIC is ill-defined.
> 
> I think it is OK because the arguments are evaluated 
> before the operation.  Without the patch, parts of the 
> operation (the size expressions) are gimplified before
> the arguments and this seems wrong to me.
> 
> 
> Martin
> 
> 
> 
> 



Re: [PATCH] Document that -fno-trampolines is for Ada only [PR100735]

2021-06-11 Thread Martin Uecker via Gcc-patches



> 
> Jeff et. al.
> 
> > On 9 Jun 2021, at 17:23, Jeff Law via Gcc-patches  
> > wrote:
> > On 5/25/2021 2:23 PM, Paul Eggert wrote:
> >> The GCC manual's documentation of -fno-trampolines was apparently
> >> written from an Ada point of view. However, when I read it I
> >> understandably mistook it to say that -fno-trampolines also works for
> >> C, C++, etc. It doesn't: it is silently ignored for these languages,
> >> and I assume for any language other than Ada.
> >> 
> >> This confusion caused me to go in the wrong direction in a Gnulib
> >> dicussion, as I mistakenly thought that entire C apps with nested
> >> functions could be compiled with -fno-trampolines and then use nested
> >> C functions in stack overflow handlers where the alternate stack
> >> is allocated via malloc. I was wrong, as this won't work on common
> >> platforms like x86-64 where malloc yields non-executable storage.
> >> 
> >> gcc/
> >> * doc/invoke.texi (Code Gen Options):
> >> * doc/tm.texi.in (Trampolines):
> >> Document that -fno-trampolines and -ftrampolines work
> >> only with Ada.
> > So Martin Uecker probably has the most state on this.  IIRC when we last 
> > discussed -fno-
> trampolines the belief was that it could be easily made to work independent 
> of the language, but
> that it was ultimately an ABI change.   That ultimately derailed plans to use 
> -fno-trampolines for
> other languages in the immediate term.
> 
> This is correct, it’s not technically too hard to make it work for another 
> language (I have a hack
> in my arm64-darwin branch that does this for gfortran).  As noted for most 
> ports it is an ABI
> break and thus not usable outside a such a work-around.
> 
> For the record (for the arm64-darwin port in the first instance), together 
> with some of my friends
> at embecosm we plan to implement a solution to the trampoline that does not 
> require executable
> stack and does not require an ABI break.  Perhaps such a solution will be of 
> interest to other
> ports that do not want executable stack.
> 
> We’re not quite ready to post the design yet - but will do so in the next few 
> weeks (all being
> well).
> 

For reference the discussion and PATCH for C can be found here:

https://gcc.gnu.org/legacy-ml/gcc-patches/2018-12/msg01532.html


FWIW: There is a proposal discussed in WG14 to add lambdas.

In this context a more general and portable solution to this
problem would also be useful. 

One related idea is to add a wider function pointer type
to C that includes a data pointer.  A regular function
pointer could be converted to the wider pointer but
back conversion only works if it originally was a
regular function pointer.  This pointer type could then
also be used for interoperablity with other languages
that have callable objects or closures.

If GCC could add something like this and there is then
implementation experience, we could later try to
standardize it. (there was also positive feedback
to this idea from some C++ people I spoke to)


Martin

 









Re: [RFC, PATCH] nonzero attribute, static array parameter

2015-07-23 Thread Martin Uecker

Hi Marek,

sorry for taking so long to respond.

Fri, 15 May 2015 15:38:43 +0200
Marek Polacek :

> On Sat, May 09, 2015 at 09:42:23AM -0700, Martin Uecker wrote:
> > here is a tentative patch to implement a new attribute nonzero,
> > which is similar to nonnull, but is not a function attribute
> > but a type attribute.
> > 
> > One reason is that nonnull is awkward to use. For this reason,
> > clang allows the use of nonnull in function parameters, but this
> > is incompatible with old and current use of this attribute in gcc
> > (though in a rather obscure use case).
> > See: https://gcc.gnu.org/ml/gcc/2015-05/msg00077.html
>  
> Sorry, I quite fail to see how such an attribute would be useful.

First of all, it makes it much simpler to implement the desired warnings
and ubsan checks when passing NULL as an array parameters with 'static'.
It avoids implementing all this argument walking code which is needed
for nonnull. If we do not want a nonzero attribute, could we then
consider an internal attribute (e.g. "non zero")?

> It seems that the nonzero warning can only ever trigger when used
> on function parameters or on a return value, much as the nonnull / 
> returns_nonnull attributes. 

So far. But in the future this could be extended to other
cases where it makes sense.

> The difference is that you can use
> the nonzero attribute on a particular function parameter, but the
> nonnull attribute has this ability as well:
> 
> __attribute__ ((nonnull (1))) void foo (int *, int *);
> void
> bar (void)
> {
>   foo (0, 0);
> }

I know. But this is ugly, cumbersome, and fragile, and some uses
are incompatible with clang. That nonnull is mis-designed
has been pointed out before:

https://gcc.gnu.org/ml/gcc/2006-04/msg00551.html

> Unlike nonnull, nonzero attribute can be attached to a typedef, but
> it doesn't seem to buy you anything you couldn't do with the nonnull /
> returns_nonnull attributes.

It is much more expressive. A nonnull pointer _type_ seems really
useful to me. Many programming languages have something like this.

> The nonzero attribute can appertain even to integer types, not only
> pointer types.  Can you give an example where this would come in handy?
> It doesn't seem too useful to me.

One example:

void assert(__attribute__((nonzero)) int i);

would give a warning if it is already known at compile time
that the expression is zero.

> 
> +void foo1(int x[__attribute__((nonzero))]);
> 
> This looks weird, 

It does look weird. But this is already documented in this way:
https://gcc.gnu.org/onlinedocs/gcc/Attribute-Syntax.html#Attribute-Syntax

The use of 'const' and 'static' in an array declarator as
defined by ISO C99 is already weird.

> the placement of the nonzero attribute here suggests
> that the array should have at least zero elements (the same that
> int x[static 0] does), but in fact it checks that the pointer passed
> to foo1 is non-NULL, i.e. something that could be easily achieved
> with the nonnull attribute.

In many case it would be much nicer to be able to declare a 
nonzero type and use it in interfaces instead of having to
add __attribute__((nonnull(1,2,5,8))) with exactly the right
numbers to a lot of prototypes.

> > The other reason is that a nonzero type attribute is conceptually
> > much simpler and at the same time more general than the existing
> > nonnull and nonnull_return function attributes (and could replace
> > both), e.g. we can define non-zero types and diagnose all stores
> > of known constant 0 to variables of this type, use this for 
> > computing better value ranges, etc.
>  
> Why would that be useful?  What makes integer 0 special?

0 is special in many ways. In particular it represents false
in an if clause. Also, why artificially restrict it to pointers
when it is trivial to make it work for integers too?


Martin





[RFC, PATCH] nonzero attribute, static array parameter

2015-05-09 Thread Martin Uecker

Hi,

here is a tentative patch to implement a new attribute nonzero,
which is similar to nonnull, but is not a function attribute
but a type attribute.

One reason is that nonnull is awkward to use. For this reason,
clang allows the use of nonnull in function parameters, but this
is incompatible with old and current use of this attribute in gcc
(though in a rather obscure use case).
See: https://gcc.gnu.org/ml/gcc/2015-05/msg00077.html

The other reason is that a nonzero type attribute is conceptually
much simpler and at the same time more general than the existing
nonnull and nonnull_return function attributes (and could replace
both), e.g. we can define non-zero types and diagnose all stores
of known constant 0 to variables of this type, use this for 
computing better value ranges, etc.

This patch implements the attribute and adds a warning if a 
zero constant is passed as argument with nonzero type attribute.
Also infer_nonnull_range in gcc/gimple.c is extended to make use 
of the attribute (which in turn is used by ubsan).

In addition, in C the attribute is automatically added to
pointers declared as array parameters with static, e.g:

void foo(int a[static 5]);


Martin

(tested on x86_64-unknown-linux-gnu)






diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 77d9352..2f79344 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,8 @@
+2015-05-09  Martin Uecker  
+
+	* gcc/gimple.c (infer_nonnull_range): Process nonzero attribute.
+	* doc/invoki.texi
+
 2015-05-08  Jim Wilson  
 
 	* doc/install.texi (--enable-languages): Add missing jit and lto info.
diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog
index 57f83c9..809ecf1 100644
--- a/gcc/c-family/ChangeLog
+++ b/gcc/c-family/ChangeLog
@@ -1,3 +1,9 @@
+2015-05-09  Martin Uecker  
+
+	* c-common.c (handle_nonzero_attribute): New.
+	(check_function_nonzero): New.
+	(check_nonzero_arg): New.
+
 2015-05-08  Marek Polacek  
 
 	PR c/64918
diff --git a/gcc/c-family/c-common.c b/gcc/c-family/c-common.c
index 378f237..46fe749 100644
--- a/gcc/c-family/c-common.c
+++ b/gcc/c-family/c-common.c
@@ -380,6 +380,7 @@ static tree handle_deprecated_attribute (tree *, tree, tree, int,
 static tree handle_vector_size_attribute (tree *, tree, tree, int,
 	  bool *);
 static tree handle_nonnull_attribute (tree *, tree, tree, int, bool *);
+static tree handle_nonzero_attribute (tree *, tree, tree, int, bool *);
 static tree handle_nothrow_attribute (tree *, tree, tree, int, bool *);
 static tree handle_cleanup_attribute (tree *, tree, tree, int, bool *);
 static tree handle_warn_unused_result_attribute (tree *, tree, tree, int,
@@ -407,6 +408,7 @@ static tree handle_bnd_instrument (tree *, tree, tree, int, bool *);
 
 static void check_function_nonnull (tree, int, tree *);
 static void check_nonnull_arg (void *, tree, unsigned HOST_WIDE_INT);
+static void check_nonzero_arg (void *, tree, unsigned HOST_WIDE_INT);
 static bool nonnull_check_p (tree, unsigned HOST_WIDE_INT);
 static bool get_nonnull_operand (tree, unsigned HOST_WIDE_INT *);
 static int resort_field_decl_cmp (const void *, const void *);
@@ -751,6 +753,8 @@ const struct attribute_spec c_common_attribute_table[] =
 			  handle_tls_model_attribute, false },
   { "nonnull",0, -1, false, true, true,
 			  handle_nonnull_attribute, false },
+  { "nonzero",0, -1, false, true, false,
+  handle_nonzero_attribute, false },
   { "nothrow",0, 0, true,  false, false,
 			  handle_nothrow_attribute, false },
   { "may_alias",	  0, 0, false, true, false, NULL, false },
@@ -8940,6 +8944,26 @@ handle_vector_size_attribute (tree *node, tree name, tree args,
   return NULL_TREE;
 }
 
+
+/* Handle the "nonzero" attribute.  */
+static tree
+handle_nonzero_attribute (tree *node, tree ARG_UNUSED (name),
+			  tree ARG_UNUSED (args), int ARG_UNUSED (flags),
+			  bool *no_add_attrs)
+{
+  tree n = *node;
+
+  if ((TREE_CODE (n) != POINTER_TYPE)
+  && (TREE_CODE (n) != INTEGER_TYPE))
+{
+  warning (OPT_Wattributes, "%qE attribute ignored", name);
+  *no_add_attrs = true;
+}
+
+  return NULL_TREE;
+}
+
+
 /* Handle the "nonnull" attribute.  */
 static tree
 handle_nonnull_attribute (tree *node, tree ARG_UNUSED (name),
@@ -9016,6 +9040,34 @@ handle_nonnull_attribute (tree *node, tree ARG_UNUSED (name),
   return NULL_TREE;
 }
 
+
+static void
+check_function_nonzero (const_tree fntype, int nargs, tree *argarray)
+{
+  if (TREE_CODE (fntype) != FUNCTION_TYPE) // C++ lambdas
+return;
+
+  function_args_iterator iter;
+  tree type;
+  int i = 0;
+
+  FOREACH_FUNCTION_ARGS (fntype, type, iter)
+{
+  if (i == nargs)
+	break;
+
+  tree a = lookup_attribute ("nonzero", TYPE_ATTRIBUTES (type));
+
+  if (a != NULL_TREE)
+check_function_arguments_recurse (check_nonzero_arg, NULL,
+	  argarray

Re: [PATCH] ubsan: improve bounds checking, add -fsanitize=bounds-strict

2015-03-02 Thread Martin Uecker

Marek Polacek :
> On Fri, Feb 27, 2015 at 11:53:14AM -0800, Martin Uecker wrote:
> > 
> > I tested Marek's proposed change and it works correctly,
> > i.e. arrays which are not part of a struct are now
> > instrumented when accessed through a pointer. This also
> > means that the following case is diagnosed (correctly)
> > as undefined behaviour as pointed out by Richard:
> > 
> > int
> > main (void)
> > {
> >   int *t = (int *) __builtin_malloc (sizeof (int) * 9);
> >   int (*a)[3][3] = (int (*)[3][3])t;
> >   (*a)[0][9] = 1;
> > }
> > 
> > 
> > I also wanted arrays which are the last elements of a
> > struct which are not flexible-array members instrumented 
> > correctly. So I added -fsantitize=bounds-strict which does
> > this. It seems to do instrumentation similar to clang 
> > with -fsanitize=bounds.
> > 
> > Comments?
>  
> Thanks for working on it.  So I think we should split this patch in
> two; one part is a bug fix (I've opened
> <https://gcc.gnu.org/bugzilla/show_bug.cgi?id=65280>) that could go
> into gcc 5 - that is, apply my fix along with test cases covering the
> new cases, and the second part is an addition of a new option for
> strict bounds checking - I'm afraid this part has to wait for gcc 6.
> 
> I can take care of the first part and let you do the second part, which I
> could review.  Does that sound ok to you?

Thank you Marek! Sounds good to me.

Martin



Re: [PATCH] ubsan: improve bounds checking, add -fsanitize=bounds-strict

2015-03-01 Thread Martin Uecker

Bootstrap and regression tested on x86_64.

A ubsan-bootstrap for C and C++ works too (although there
are other unrelated runtime errors). 

I tried a bootstrap with -fsanitize=bounds-strict and 
there are indeed many additional runtime errors due the
struct hack with last array element of size 1 (or even 2). 
So Jakub and Richard were right and putting this into a 
separate option was the right thing to do.


Code-wise it seems to come just from a couple of places
such as  (rtl.h, tree.h, vec.h, sbitmap.h, ...).

Just to see how hard it would be to make this work with
strict bounds checking, I started doing this in my tree 
using a macro:

#define CAST_TO_POINTER(x) ((__typeof(x[0])*)(x))

For example,

#define RTL_CHECK1(RTX, N, C1) ((RTX)->u.fld[N])

then becomes

#define RTL_CHECK1(RTX, N, C1) \
(CAST_TO_POINTER((RTX)->u.fld)[N])

Doing this in a few places gets rid of most of the
errors rather quickly (getting rid of all errors would
be a bit more work).

If one allows VLAs one could also cast to an array of
the correct length:

#defined CAST_TO_VLA(x, len) (*(__typeof(x[0])(*)[len])&x)

For example:

#define RTL_CHECK1(RTX, N, C1) \
(CAST_TO_VLA((RTX)->u.fld, GET_RTX_LENGTH( ... ))[N])

and have ubsan auto-generate the bound checking which
are now often manually added.

Martin





Martin Uecker :
> 
> I tested Marek's proposed change and it works correctly,
> i.e. arrays which are not part of a struct are now
> instrumented when accessed through a pointer. This also
> means that the following case is diagnosed (correctly)
> as undefined behaviour as pointed out by Richard:
> 
> int
> main (void)
> {
>   int *t = (int *) __builtin_malloc (sizeof (int) * 9);
>   int (*a)[3][3] = (int (*)[3][3])t;
>   (*a)[0][9] = 1;
> }
> 
> 
> I also wanted arrays which are the last elements of a
> struct which are not flexible-array members instrumented 
> correctly. So I added -fsantitize=bounds-strict which does
> this. It seems to do instrumentation similar to clang 
> with -fsanitize=bounds.
> 
> Comments?
> 
> (regression testing in progress, but ubsan-related
> tests all pass)
> 
> diff --git a/gcc/ChangeLog b/gcc/ChangeLog
> index ec2cb69..cb6df20 100644
> --- a/gcc/ChangeLog
> +++ b/gcc/ChangeLog
> @@ -1,3 +1,11 @@
> +2015-02-27  Martin Uecker 
> +
> + * opts.c(common_handle_option): Add option for
> + -fsanitize=bounds-strict
> + * flag-types.h: Add SANITIZE_BOUNDS_STRICT
> + * doc/invoke.texi: Improve description for
> + -fsanitize=bounds and document -fsanitize=bounds-strict
> +
> diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog
> index ffa01c6..44a1761 100644
> --- a/gcc/c-family/ChangeLog
> +++ b/gcc/c-family/ChangeLog
> @@ -1,3 +1,9 @@
> +2015-02-27  Martin Uecker 
> +
> + * c-ubsan.c (ubsan_instrument_bounds): Instrument
> + arrays which are accessed directly through a pointer.
> + For strict checking, instrument last elements of a struct.
> +
> diff --git a/gcc/c-family/c-ubsan.c b/gcc/c-family/c-ubsan.c
> index 90d59c0..1a0e2da 100644
> --- a/gcc/c-family/c-ubsan.c
> +++ b/gcc/c-family/c-ubsan.c
> @@ -293,6 +293,7 @@ ubsan_instrument_bounds (location_t loc, tree array, tree 
> *index,
>tree type = TREE_TYPE (array);
>tree domain = TYPE_DOMAIN (type);
>  
> +  /* This also takes care of flexible array members. */
>if (domain == NULL_TREE || TYPE_MAX_VALUE (domain) == NULL_TREE)
>  return NULL_TREE;
>  
> @@ -301,10 +302,13 @@ ubsan_instrument_bounds (location_t loc, tree array, 
> tree *index,
>  bound = fold_build2 (PLUS_EXPR, TREE_TYPE (bound), bound,
>build_int_cst (TREE_TYPE (bound), 1));
>  
> -  /* Detect flexible array members and suchlike.  */
> +  /* Don't instrument arrays which are the last element of
> + a struct. */
>tree base = get_base_address (array);
> -  if (base && (TREE_CODE (base) == INDIRECT_REF
> -|| TREE_CODE (base) == MEM_REF))
> +  if (!(flag_sanitize & SANITIZE_BOUNDS_STRICT)
> +  && (TREE_CODE (array) == COMPONENT_REF)
> +  && base && (TREE_CODE (base) == INDIRECT_REF
> + || TREE_CODE (base) == MEM_REF))
>  {
>tree next = NULL_TREE;
>tree cref = array;
> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> index ef4cc75..5a93757 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -5704,8 +5704,15 @@ a++;
>  @item -fsanitize=bounds
>  @opindex fsanitize=bounds
>  This option enables instrumentation of array bounds.  Various out of bounds
> -accesses are detected.  Flexible array members and initializers of variables
> -with static storage are not instrumented.
&g

[PATCH] ubsan: improve bounds checking, add -fsanitize=bounds-strict

2015-02-27 Thread Martin Uecker

I tested Marek's proposed change and it works correctly,
i.e. arrays which are not part of a struct are now
instrumented when accessed through a pointer. This also
means that the following case is diagnosed (correctly)
as undefined behaviour as pointed out by Richard:

int
main (void)
{
  int *t = (int *) __builtin_malloc (sizeof (int) * 9);
  int (*a)[3][3] = (int (*)[3][3])t;
  (*a)[0][9] = 1;
}


I also wanted arrays which are the last elements of a
struct which are not flexible-array members instrumented 
correctly. So I added -fsantitize=bounds-strict which does
this. It seems to do instrumentation similar to clang 
with -fsanitize=bounds.

Comments?

(regression testing in progress, but ubsan-related
tests all pass)

diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index ec2cb69..cb6df20 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,11 @@
+2015-02-27  Martin Uecker 
+
+   * opts.c(common_handle_option): Add option for
+   -fsanitize=bounds-strict
+   * flag-types.h: Add SANITIZE_BOUNDS_STRICT
+   * doc/invoke.texi: Improve description for
+   -fsanitize=bounds and document -fsanitize=bounds-strict
+
diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog
index ffa01c6..44a1761 100644
--- a/gcc/c-family/ChangeLog
+++ b/gcc/c-family/ChangeLog
@@ -1,3 +1,9 @@
+2015-02-27  Martin Uecker 
+
+   * c-ubsan.c (ubsan_instrument_bounds): Instrument
+   arrays which are accessed directly through a pointer.
+   For strict checking, instrument last elements of a struct.
+
diff --git a/gcc/c-family/c-ubsan.c b/gcc/c-family/c-ubsan.c
index 90d59c0..1a0e2da 100644
--- a/gcc/c-family/c-ubsan.c
+++ b/gcc/c-family/c-ubsan.c
@@ -293,6 +293,7 @@ ubsan_instrument_bounds (location_t loc, tree array, tree 
*index,
   tree type = TREE_TYPE (array);
   tree domain = TYPE_DOMAIN (type);
 
+  /* This also takes care of flexible array members. */
   if (domain == NULL_TREE || TYPE_MAX_VALUE (domain) == NULL_TREE)
 return NULL_TREE;
 
@@ -301,10 +302,13 @@ ubsan_instrument_bounds (location_t loc, tree array, tree 
*index,
 bound = fold_build2 (PLUS_EXPR, TREE_TYPE (bound), bound,
 build_int_cst (TREE_TYPE (bound), 1));
 
-  /* Detect flexible array members and suchlike.  */
+  /* Don't instrument arrays which are the last element of
+ a struct. */
   tree base = get_base_address (array);
-  if (base && (TREE_CODE (base) == INDIRECT_REF
-  || TREE_CODE (base) == MEM_REF))
+  if (!(flag_sanitize & SANITIZE_BOUNDS_STRICT)
+  && (TREE_CODE (array) == COMPONENT_REF)
+  && base && (TREE_CODE (base) == INDIRECT_REF
+ || TREE_CODE (base) == MEM_REF))
 {
   tree next = NULL_TREE;
   tree cref = array;
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index ef4cc75..5a93757 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -5704,8 +5704,15 @@ a++;
 @item -fsanitize=bounds
 @opindex fsanitize=bounds
 This option enables instrumentation of array bounds.  Various out of bounds
-accesses are detected.  Flexible array members and initializers of variables
-with static storage are not instrumented.
+accesses are detected.  Accesses to arrays which are the last member of a
+struct and initializers of variables with static storage are not instrumented.
+
+@item -fsanitize=bounds-strict
+@opindex fsanitize=bounds-strict
+This option enables strict instrumentation of array bounds.  Most out of bounds
+accesses are detected including accesses to arrays which are the last member 
of a
+struct. Initializers of variables with static storage are not instrumented.
+
 
 @item -fsanitize=alignment
 @opindex fsanitize=alignment
diff --git a/gcc/flag-types.h b/gcc/flag-types.h
index bfdce44..c9ad4df 100644
--- a/gcc/flag-types.h
+++ b/gcc/flag-types.h
@@ -238,6 +238,7 @@ enum sanitize_code {
   SANITIZE_RETURNS_NONNULL_ATTRIBUTE = 1UL << 19,
   SANITIZE_OBJECT_SIZE = 1UL << 20,
   SANITIZE_VPTR = 1UL << 21,
+  SANITIZE_BOUNDS_STRICT = 1UL << 22,
   SANITIZE_UNDEFINED = SANITIZE_SHIFT | SANITIZE_DIVIDE | SANITIZE_UNREACHABLE
   | SANITIZE_VLA | SANITIZE_NULL | SANITIZE_RETURN
   | SANITIZE_SI_OVERFLOW | SANITIZE_BOOL | SANITIZE_ENUM
@@ -245,7 +246,7 @@ enum sanitize_code {
   | SANITIZE_NONNULL_ATTRIBUTE
   | SANITIZE_RETURNS_NONNULL_ATTRIBUTE
   | SANITIZE_OBJECT_SIZE | SANITIZE_VPTR,
-  SANITIZE_NONDEFAULT = SANITIZE_FLOAT_DIVIDE | SANITIZE_FLOAT_CAST
+  SANITIZE_NONDEFAULT = SANITIZE_FLOAT_DIVIDE | SANITIZE_FLOAT_CAST | 
SANITIZE_BOUNDS_STRICT
 };
 
 /* flag_vtable_verify initialization levels. */
diff --git a/gcc/opts.c b/gcc/opts.c
index 39c190d..7fe77fa 100644
--- a/gcc/opts.c
+++ b/gcc/opts.c
@@ -1584,6 +1584,7 @@ common_handle_option (struct gcc_options *opts,
  { "float-cast-overflow", SANITIZE_FLOAT_CAST,
 

Re: [PATCH] ubsan: remove bogus check for flexible array members

2015-02-26 Thread Martin Uecker
Am Thu, 26 Feb 2015 10:05:14 +0100
Jakub Jelinek :

> On Thu, Feb 26, 2015 at 12:59:08AM -0800, Martin Uecker wrote:
> > > No, it is not bogus nor unnecessary.
> > > This isn't about just real flexible arrays, but similar constructs,
> > > C++ doesn't have flexible array members, nor C89, so people use the
> > > GNU extension of struct S { ... ; char a[0]; } instead, or
> > 
> > The GNU extension is still allowed, i.e. not instrumented with
> > the patch.
> > 
> > > use char a[1]; as the last member and still expect to be able to access
> > > s->a[i] for i > 0 say on heap allocations etc.
> > 
> > And this is broken code. I would argue that a user who uses the
> > ubsan *expects* this to be diagnosed. Atleast I was surprised
> > that it didn't catch more out-of-bounds accesses.
> 
> So can you explain what a C++ programmer can do portably? 

Using broken code is not really portable either, because other
compilers diagnose this. Also, we are not talking about breaking
that code - they can simply continue to use that code. They could
just not expect ubsan to not diagnose it. This would make
them aware of the fact that their code is problematic - which is
exactly what I would expect from ubsan.

> It has neither
> flexible array members, nor without GNU extensions zero sized arrays.
> If the array size is constant, perhaps turn the struct into a template,
> but if it is variable?  Ditto for C89 code.
> The amount of code that uses this idiom in the wild is huge.

Ok, I will add an option then. Or should this be language dependent?

Maritn


Re: [PATCH] ubsan: remove bogus check for flexible array members

2015-02-26 Thread Martin Uecker
Marek Polacek :

(Hi Marek and Jakub, I really appreciate your work on GCC and 
ubsan. I just want to add the minor enhancements necessary 
to make it really useful for me).

> > And this is broken code. I would argue that a user who uses the
> > ubsan *expects* this to be diagnosed. Atleast I was surprised
> > that it didn't catch more out-of-bounds accesses.
>  
> I wouldn't say broken, it's being used pretty often.  E.g.
> https://gcc.gnu.org/onlinedocs/gcc/Zero-Length.html
> "In ISO C90, you would have to give contents a length of 1"

Ok, let's add an option then. But that it is common doesn't
mean it is not broken (especially since there is a legal
way to that with GCC and C99) and I think there should be a 
way to diagnose it with ubsan.

> > If this is indeed intentional, we should:
> > 
> > - document these exceptions
> 
> See the link above + docs say for -fsanitize=bounds that "Flexible array
> members are not instrumented".

Flexible array members should not be intrumented. But
what is suprising to the user and should be documented
is that other arrays (e.g. which hjust happen to be the
last in a struct) are not instrumented.

> > - remove the misleading comment
> 
> Which one?
> The /* Detect flexible array members and suchlike.  */ IMHO says
> exactly what's meant to be done.

The reason it confused me was because flexible array members never
see this code because the are catched by the 'if' condition
directly before. 

> > - have test cases also for sizes > 0
> 
> Yes, we should have that.
> 
> > - fix it not to prevent instrumentation of all array accesses
> >   through pointers (i.e. when the array is not a member of a struct)
> 
> Yes, see the patch in my previous mail.

Thank you! I will test this and report back

> > - have a configuration option (e.g. -fsanitize=strict-bounds)
> 
> Yeah, something like that would be useful to have.  As Jakub
> mentioned, we discussed this in the past.  Probably GCC 6 stuff
> though.

I will look into this.

Martin



Re: [PATCH] ubsan: remove bogus check for flexible array members

2015-02-26 Thread Martin Uecker

Thu, 26 Feb 2015 07:36:54 +0100
Jakub Jelinek :
> On Wed, Feb 25, 2015 at 10:01:07PM -0800, Martin Uecker wrote:
> > this patch removes a bogus check for flexible array members
> > which prevents array references to be instrumented in some
> > interesting cases. Arrays accessed through pointers are now
> > instrumented correctly.
> > 
> > The check was unnecessary because flexible arrays are not 
> > instrumented anyway because of
> > TYPE_MAX_VALUE (domain) == NULL_TREE. 
> 
> No, it is not bogus nor unnecessary.
> This isn't about just real flexible arrays, but similar constructs,
> C++ doesn't have flexible array members, nor C89, so people use the
> GNU extension of struct S { ... ; char a[0]; } instead, or

The GNU extension is still allowed, i.e. not instrumented with
the patch.

> use char a[1]; as the last member and still expect to be able to access
> s->a[i] for i > 0 say on heap allocations etc.

And this is broken code. I would argue that a user who uses the
ubsan *expects* this to be diagnosed. Atleast I was surprised
that it didn't catch more out-of-bounds accesses.

If this is indeed intentional, we should:

- document these exceptions
- remove the misleading comment
- have test cases also for sizes > 0
- fix it not to prevent instrumentation of all array accesses
  through pointers (i.e. when the array is not a member of a struct)
- have a configuration option (e.g. -fsanitize=strict-bounds)


> I think we were talking at some point about having a strict-bounds or
> something similar that would accept only real flexible array members and
> nothing else and be more pedantic, at the disadvantage of diagnosing tons
> of real-world code that is supported by GCC.
>
> Perhaps if the reference is just an array, not a struct containing
> flexible-array-member-like array, we could consider it strict always,
> but that is certainly not what your patch does.

Indeed, currently the patch tries to make -fsanitize=bounds detect what
the  standard considers undefined behaviour. At the moment, I do not
quite see why ubsan should be so permissive as you say.

But we can also add a new option -fsanitize=strict-bounds. Then I could
use this for my (real-world) projects.



> > * c-family/c-ubsan.c (ubsan_instrument_bounds): Remove
> 
> c-family/ shouldn't be in the ChangeLog entry, instead that part should go
> into c-family/ChangeLog.

> > --- a/gcc/c-family/c-ubsan.c
> > +++ b/gcc/c-family/c-ubsan.c
> > @@ -293,6 +293,7 @@ ubsan_instrument_bounds (location_t loc, tree array, 
> > tree *index,
> >tree type = TREE_TYPE (array);
> >tree domain = TYPE_DOMAIN (type);
> >  
> > +  /* This also takes care of flexilbe array members */
> 
> Typo.
> 
> > +#ifdef __cplusplus
> > +extern "C" void* malloc(unsigned long x);
> > +#else
> > +extern void* malloc(unsigned long x);
> > +#endif
> 
> Why are you declaring malloc (wrongly), when it isn't used?
> Malloc argument is size_t aka __SIZE_TYPE__, not unsigned long.

Left over from removing tests already done elsewhere.

Thank you for your comments,
Martin




[PATCH] ubsan: remove bogus check for flexible array members

2015-02-25 Thread Martin Uecker

Hi,

this patch removes a bogus check for flexible array members
which prevents array references to be instrumented in some
interesting cases. Arrays accessed through pointers are now
instrumented correctly.

The check was unnecessary because flexible arrays are not 
instrumented anyway because of
TYPE_MAX_VALUE (domain) == NULL_TREE. 


Regression tested.


2015-02-25  Martin Uecker 

gcc/

* c-family/c-ubsan.c (ubsan_instrument_bounds): Remove
bogus check for flexible array members.

gcc/testsuite/

* gcc.dg/ubsan/bounds-2.c: New
* c-c++-common/ubsan/bounds-8.c: New



diff --git a/gcc/c-family/c-ubsan.c b/gcc/c-family/c-ubsan.c
index 90d59c0..dba3bbc 100644
--- a/gcc/c-family/c-ubsan.c
+++ b/gcc/c-family/c-ubsan.c
@@ -293,6 +293,7 @@ ubsan_instrument_bounds (location_t loc, tree array, tree 
*index,
   tree type = TREE_TYPE (array);
   tree domain = TYPE_DOMAIN (type);
 
+  /* This also takes care of flexilbe array members */
   if (domain == NULL_TREE || TYPE_MAX_VALUE (domain) == NULL_TREE)
 return NULL_TREE;
 
@@ -301,36 +302,6 @@ ubsan_instrument_bounds (location_t loc, tree array, tree 
*index,
 bound = fold_build2 (PLUS_EXPR, TREE_TYPE (bound), bound,
 build_int_cst (TREE_TYPE (bound), 1));
 
-  /* Detect flexible array members and suchlike.  */
-  tree base = get_base_address (array);
-  if (base && (TREE_CODE (base) == INDIRECT_REF
-  || TREE_CODE (base) == MEM_REF))
-{
-  tree next = NULL_TREE;
-  tree cref = array;
-
-  /* Walk all structs/unions.  */
-  while (TREE_CODE (cref) == COMPONENT_REF)
-   {
- if (TREE_CODE (TREE_TYPE (TREE_OPERAND (cref, 0))) == RECORD_TYPE)
-   for (next = DECL_CHAIN (TREE_OPERAND (cref, 1));
-next && TREE_CODE (next) != FIELD_DECL;
-next = DECL_CHAIN (next))
- ;
- if (next)
-   /* Not a last element.  Instrument it.  */
-   break;
- /* Ok, this is the last field of the structure/union.  But the
-aggregate containing the field must be the last field too,
-recursively.  */
- cref = TREE_OPERAND (cref, 0);
-   }
-  if (!next)
-   /* Don't instrument this flexible array member-like array in non-strict
-  -fsanitize=bounds mode.  */
-return NULL_TREE;
-}
-
   /* Don't emit instrumentation in the most common cases.  */
   tree idx = NULL_TREE;
   if (TREE_CODE (*index) == INTEGER_CST)
diff --git a/gcc/testsuite/c-c++-common/ubsan/bounds-8.c 
b/gcc/testsuite/c-c++-common/ubsan/bounds-8.c
new file mode 100644
index 000..554693f
--- /dev/null
+++ b/gcc/testsuite/c-c++-common/ubsan/bounds-8.c
@@ -0,0 +1,26 @@
+/* { dg-do run } */
+/* { dg-options "-O3 -fsanitize=bounds" } */
+/* Origin: Martin Uecker  */
+
+#ifdef __cplusplus
+extern "C" void* malloc(unsigned long x);
+#else
+extern void* malloc(unsigned long x);
+#endif
+
+void foo(int (*a)[3])
+{
+   (*a)[3] = 1;// error
+   a[0][0] = 1;// ok
+   a[1][0] = 1;// ok
+   a[1][4] = 1;// error
+}
+
+int main()
+{
+   int a[20];
+   foo((int (*)[3])&a);
+}
+
+/* { dg-output "index 3 out of bounds for type 'int 
\\\[3\\\]'\[^\n\r]*(\n|\r\n|\r)" } */
+/* { dg-output "\[^\n\r]*index 4 out of bounds for type 'int \\\[3\\\]'" } */
diff --git a/gcc/testsuite/gcc.dg/ubsan/bounds-2.c 
b/gcc/testsuite/gcc.dg/ubsan/bounds-2.c
new file mode 100644
index 000..722c54e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/ubsan/bounds-2.c
@@ -0,0 +1,18 @@
+/* { dg-do run } */
+/* { dg-options "-O3 -fsanitize=bounds" } */
+/* Origin: Martin Uecker  */
+
+extern void* malloc(unsigned long x);
+
+void foo(int n, int (*b)[n])
+{
+   (*b)[n] = 1;// error
+}
+
+int main()
+{
+   int a[20];
+   foo(3, (int (*)[3])&a);
+}
+
+/* { dg-output "index 3 out of bounds for type 'int \\\[\\\*\\\]'" } */






Re: [PATCH][2/2] Improve array-bound warnings and VRP

2015-01-27 Thread Martin Uecker


Richard Biener wrote:

> On Mon, 26 Jan 2015, Jakub Jelinek wrote:

> > Then it probably should be ok.  I'm really afraid of emitting more warnings
> > with such high false positive rate now.
>
> As the patch also mitigates some of the code bloat we get with
> the complete peeling (regression against 4.7) I have installed it.
> It's also the easiest vehicle to verify range-info is not broken
> by passes between vrp1 and vrp2.

You could make warnings appear only for warn_array_bounds > 1
if there are concerns about false positives.

For what it's worth, I tested the old version of both patches on 
one of my projects (mostly numerical algorithms) and it did not 
produce additional warnings.

I really appreciate all improvements in this area.

Martin




[committed] MAINTAINERS: add myself to write-after-approval list

2015-01-15 Thread Martin Uecker

2015-01-15  Martin Uecker  

* MAINTAINERS: (Write After Approval): Add myself.


Index: MAINTAINERS
===
--- MAINTAINERS (Revision 219713)
+++ MAINTAINERS (Revision 219714)
@@ -576,6 +576,7 @@
 Philipp Tomsich

 Konrad Trifunovic  
 Markus Trippelsdorf
+Martin Uecker  
 David Ung  
 Neil Vachharajani  
 Kris Van Hees  


Re: [PATCH] add option to emit more array bounds warnigs

2015-01-13 Thread Martin Uecker

Jeff Law :
> On 01/13/15 17:40, Martin Uecker wrote:
> > Jeff Law :
> >> On 01/13/15 10:34, Martin Uecker wrote:
> >>> Mon, 12 Jan 2015 11:00:44 -0700
> >>> Jeff Law :
> >>>> On 11/11/14 23:13, Martin Uecker wrote:
> >
> > ...
> >
> >>>> Has this patch been bootstrapped and regression tested, if so on what
> >>>> platform.
> >>>
> >>> x86_64-unknown-linux-gnu
> >> Approved.  Please install on the trunk.  Sorry about the delays.
> >
> > I don't have write access ;-(
> I fixed up the ChangeLog entries and installed the patch for you.

Thank you, Jeff!

> If you plan to contribute regularly, you should go ahead and apply for 
> write access to the repository so that you'll be able to commit your own 
> patches once they're approved.

I put a request in with you as sponsor (hope this is ok).

> You'll also need to make sure you have an assignment on file with the 
> FSF.That patch was pretty small (the testcase was larger than the 
> patch itself, which I always like :-) so I didn't request an assignment. 
>   Further submissions likely will require an assignment.

I already have an assignment on file.

Martin



Re: [PATCH] add option to emit more array bounds warnigs

2015-01-13 Thread Martin Uecker
Jeff Law :
> On 01/13/15 10:34, Martin Uecker wrote:
> > Mon, 12 Jan 2015 11:00:44 -0700
> > Jeff Law :
> >> On 11/11/14 23:13, Martin Uecker wrote:

...

> >> Has this patch been bootstrapped and regression tested, if so on what
> >> platform.
> >
> > x86_64-unknown-linux-gnu
> Approved.  Please install on the trunk.  Sorry about the delays.

I don't have write access ;-(

Martin





Re: [PATCH] add option to emit more array bounds warnigs

2015-01-13 Thread Martin Uecker

Mon, 12 Jan 2015 11:00:44 -0700
Jeff Law :
> On 11/11/14 23:13, Martin Uecker wrote:

...

> >
> >
> > * gcc/tree-vrp.c (check_array_ref): Emit more warnings
> > for warn_array_bounds >= 2.
> > * gcc/testsuite/gcc.dg/Warray-bounds-11.c: New test-case.
> > * gcc/c-family/c.opt: New option -Warray-bounds=.
> > * gcc/common.opt: New option -Warray-bounds=.
> > * gcc/doc/invoke.texi: Document new option.
> Has this patch been bootstrapped and regression tested, if so on what 
> platform.

x86_64-unknown-linux-gnu

> Given the new warnings (as implemented by the patch) are not enabled by 
> default, I'm inclined to approve once Martin verifies things via 
> bootstrap and regression test.

Thank you,

Martin

 



[PING] Re: [PATCH] add option to emit more array bounds warnigs

2015-01-11 Thread Martin Uecker



Please consider this patch. The additional warnings would be useful 
IMHO, are also emitted by clang, and the change seems trivial.

Previous discussion about potential false positives:
https://gcc.gnu.org/ml/gcc/2014-11/msg00114.html


Tue, 11 Nov 2014 22:13:20 -0800
Martin Uecker :

> 
> Hi,
> 
> this proposed patch adds an option "-Warray-bounds=" in addition to
> "-Warray-bound". "-Warray-bounds=1" corresponds to "-Warray-bound".
> For higher warning levels more warnings about optional accesses
> outside of arrays are emitted. For example, warnings for
> arrays accessed through pointers are now emitted:
> 
> void foo(int (*a)[3])
> {
>   (*a)[4] = 1;
> }
> 
> Also warnings for arrays which are the last element of a struct
> are emitted, if it is not a flexible array member or does not use
> the zero size extensions.
> 
> Because there is the risk of false positives, the higher warning
> level is not used by default.
> 
> 
> Martin

 

* gcc/tree-vrp.c (check_array_ref): Emit more warnings
   for warn_array_bounds >= 2.
* gcc/testsuite/gcc.dg/Warray-bounds-11.c: New test-case.
* gcc/c-family/c.opt: New option -Warray-bounds=.
* gcc/common.opt: New option -Warray-bounds=.
* gcc/doc/invoke.texi: Document new option.



diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 064c69e..e61fc56 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -279,6 +279,10 @@ Warray-bounds
 LangEnabledBy(C ObjC C++ ObjC++,Wall)
 ; in common.opt
 
+Warray-bounds=
+LangEnabledBy(C ObjC C++ ObjC++,Wall,1,0)
+; in common.opt
+
 Wassign-intercept
 ObjC ObjC++ Var(warn_assign_intercept) Warning
 Warn whenever an Objective-C assignment is being intercepted by the garbage 
collector
diff --git a/gcc/common.opt b/gcc/common.opt
index e104269..3d19875 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -529,6 +529,10 @@ Warray-bounds
 Common Var(warn_array_bounds) Warning
 Warn if an array is accessed out of bounds
 
+Warray-bounds=
+Common Joined RejectNegative UInteger Var(warn_array_bounds) Warning
+Warn if an array is accessed out of bounds
+
 Wattributes
 Common Var(warn_attributes) Init(1) Warning
 Warn about inappropriate attribute usage
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index ed23f6f..f20cbf0 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -240,7 +240,7 @@ Objective-C and Objective-C++ Dialects}.
 @gccoptlist{-fsyntax-only  -fmax-errors=@var{n}  -Wpedantic @gol
 -pedantic-errors @gol
 -w  -Wextra  -Wall  -Waddress  -Waggregate-return  @gol
--Waggressive-loop-optimizations -Warray-bounds @gol
+-Waggressive-loop-optimizations -Warray-bounds -Warray-bounds=@var{n} @gol
 -Wbool-compare @gol
 -Wno-attributes -Wno-builtin-macro-redefined @gol
 -Wc90-c99-compat -Wc99-c11-compat @gol
@@ -3382,7 +3382,7 @@ Options} and @ref{Objective-C and Objective-C++ Dialect 
Options}.
 @option{-Wall} turns on the following warning flags:
 
 @gccoptlist{-Waddress   @gol
--Warray-bounds @r{(only with} @option{-O2}@r{)}  @gol
+-Warray-bounds=1 @r{(only with} @option{-O2}@r{)}  @gol
 -Wc++11-compat  -Wc++14-compat@gol
 -Wchar-subscripts  @gol
 -Wenum-compare @r{(in C/ObjC; this is on by default in C++)} @gol
@@ -4296,12 +4296,26 @@ Warn about overriding virtual functions that are not 
marked with the override
 keyword.
 
 @item -Warray-bounds
+@itemx -Warray-bounds=@var{n}
 @opindex Wno-array-bounds
 @opindex Warray-bounds
 This option is only active when @option{-ftree-vrp} is active
 (default for @option{-O2} and above). It warns about subscripts to arrays
 that are always out of bounds. This warning is enabled by @option{-Wall}.
 
+@table @gcctabopt
+@item -Warray-bounds=1
+This is the warning level of @option{-Warray-bounds} and is enabled
+by @option{-Wall}; higher levels are not, and must be explicitly requested.
+
+@item -Warray-bounds=2
+This warning level also warns about out of bounds access for
+arrays at the end of a struct and for arrays accessed through
+pointers. This warning level may give a larger number of
+false positives and is deactivated by default.
+@end table
+
+
 @item -Wbool-compare
 @opindex Wno-bool-compare
 @opindex Wbool-compare
diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-11.c 
b/gcc/testsuite/gcc.dg/Warray-bounds-11.c
new file mode 100644
index 000..2e68498
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Warray-bounds-11.c
@@ -0,0 +1,96 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -Warray-bounds=2" } */
+
+extern void* malloc(unsigned long x);
+
+int e[3];
+
+struct f { int f[3]; };
+
+extern void bar(int v[]);
+
+struct h {
+
+   int i;
+   int j[];
+};
+
+struct h0 {
+
+   int i;
+   int j[0];
+};
+
+struct h0b {
+
+   int i;
+   int j[0];
+   int k;
+};
+
+struct h1 {
+
+   int i;
+   int j[1];
+};
+
+struct h1b {
+
+   int i;
+   int j[1];
+   int k;
+};
+
+struct h3 {
+
+  

[PATCH v5] warning about const multidimensional array as function parameter

2014-12-08 Thread Martin Uecker



Another version of this patch. I fixed the formatting problems and 
the spurios use of OPT_Wdiscarded_array_qualifiers. I also added 
'-pedantic -Wdiscarded-array-qualifiers' to the dg-options in
'testsuite/gcc.dg/qual-component-1.c' and changed the expected 
warnings to the new ones. For some reason, the changes to this
file were missing in my previous versions. (scroll down to the
end for this file)

Thank you,
Martin


2014-12-08 Martin Uecker 

* doc/invoke.texi: Document -Wdiscarded-array-qualifiers
* doc/extend.texi: Document new behavior for pointers to arrays with 
qualifies
c/
* c-typeck.c: New behavious for pointers to arrays with qualifiers
(common-pointer-type): For pointers to arrays take qualifiers from 
element type.
(build_conditional_expr): Add warnings for lost qualifiers.
(comp-target-types): Allow pointers to arrays with different qualifiers.
(convert-for-assignment): Adapt warnings for discarded qualifiers. Add
WARNING_FOR_QUALIFIERS macro and rename WARN_FOR_QUALIFIERS 
to PEDWARN_FOR_QUALIFIERS.
c-family/
* c.opt (Wdiscarded-array-qualifiers): New option
testsuite/
* gcc.dg/Wwrite-strings-1.c: Change dg-warning
* gcc.dg/array-quals-1.c: Use -Wno-discarded-array-qualifiers
* gcc.dg/array-quals-2.c: Change dg-options, dg-warning
* gcc.dg/pointer-array-atomic.c: New test
* gcc.dg/pointer-array-quals-1.c: New test
* gcc.dg/pointer-array-quals-2.c: New test (-pedantic-errors)
* gcc.dg/qual-component-1.c: Change dg-options, dg-warnings


Index: gcc/c/c-typeck.c
===
--- gcc/c/c-typeck.c(Revision 218476)
+++ gcc/c/c-typeck.c(Arbeitskopie)
@@ -673,12 +673,13 @@ common_pointer_type (tree t1, tree t2)
 mv2 = TYPE_MAIN_VARIANT (pointed_to_2);
   target = composite_type (mv1, mv2);
 
+  /* Strip array types to get correct qualifier for pointers to arrays */
+  quals1 = TYPE_QUALS_NO_ADDR_SPACE (strip_array_types (pointed_to_1));
+  quals2 = TYPE_QUALS_NO_ADDR_SPACE (strip_array_types (pointed_to_2));
+
   /* For function types do not merge const qualifiers, but drop them
  if used inconsistently.  The middle-end uses these to mark const
  and noreturn functions.  */
-  quals1 = TYPE_QUALS_NO_ADDR_SPACE (pointed_to_1);
-  quals2 = TYPE_QUALS_NO_ADDR_SPACE (pointed_to_2);
-
   if (TREE_CODE (pointed_to_1) == FUNCTION_TYPE)
 target_quals = (quals1 & quals2);
   else
@@ -1224,6 +1225,7 @@ static int
 comp_target_types (location_t location, tree ttl, tree ttr)
 {
   int val;
+  int val_ped;
   tree mvl = TREE_TYPE (ttl);
   tree mvr = TREE_TYPE (ttr);
   addr_space_t asl = TYPE_ADDR_SPACE (mvl);
@@ -1235,19 +1237,32 @@ comp_target_types (location_t location, tree ttl,
   if (!addr_space_superset (asl, asr, &as_common))
 return 0;
 
-  /* Do not lose qualifiers on element types of array types that are
- pointer targets by taking their TYPE_MAIN_VARIANT.  */
-  if (TREE_CODE (mvl) != ARRAY_TYPE)
-mvl = (TYPE_ATOMIC (mvl)
-  ? c_build_qualified_type (TYPE_MAIN_VARIANT (mvl), TYPE_QUAL_ATOMIC)
-  : TYPE_MAIN_VARIANT (mvl));
-  if (TREE_CODE (mvr) != ARRAY_TYPE)
-mvr = (TYPE_ATOMIC (mvr)
-  ? c_build_qualified_type (TYPE_MAIN_VARIANT (mvr), TYPE_QUAL_ATOMIC)
-  : TYPE_MAIN_VARIANT (mvr));
+  /* For pedantic record result of comptypes on arrays before losing
+ qualifiers on the element type below. */
+  val_ped = 1;
+
+  if (TREE_CODE (mvl) == ARRAY_TYPE
+  && TREE_CODE (mvr) == ARRAY_TYPE)
+val_ped = comptypes (mvl, mvr);
+
+  /* Qualifiers on element types of array types that are
+ pointer targets are lost by taking their TYPE_MAIN_VARIANT.  */
+
+  mvl = (TYPE_ATOMIC (strip_array_types (mvl))
+? c_build_qualified_type (TYPE_MAIN_VARIANT (mvl), TYPE_QUAL_ATOMIC)
+: TYPE_MAIN_VARIANT (mvl));
+
+  mvr = (TYPE_ATOMIC (strip_array_types (mvr))
+? c_build_qualified_type (TYPE_MAIN_VARIANT (mvr), TYPE_QUAL_ATOMIC)
+: TYPE_MAIN_VARIANT (mvr));
+
   enum_and_int_p = false;
   val = comptypes_check_enum_int (mvl, mvr, &enum_and_int_p);
 
+  if (val == 1 && val_ped != 1)
+pedwarn (location, OPT_Wpedantic, "pointers to arrays with different 
qualifiers "
+  "are incompatible in ISO C");
+
   if (val == 2)
 pedwarn (location, OPT_Wpedantic, "types are not quite compatible");
 
@@ -4609,6 +4624,13 @@ build_conditional_expr (location_t colon_loc, tree
   else if (VOID_TYPE_P (TREE_TYPE (type1))
   && !TYPE_ATOMIC (TREE_TYPE (type1)))
{
+ if ((TREE_CODE (TREE_TYPE (type2)) == ARRAY_TYPE)
+ && (TYPE_QUALS (strip_array_types (TREE_TYPE (type2)))
+ & ~TYPE_QUALS (TREE_TYPE (type1
+   warni

[PATCH] add option to emit more array bounds warnigs

2014-11-11 Thread Martin Uecker

Hi,

this proposed patch adds an option "-Warray-bounds=" in addition to
"-Warray-bound". "-Warray-bounds=1" corresponds to "-Warray-bound".
For higher warning levels more warnings about optional accesses
outside of arrays are emitted. For example, warnings for
arrays accessed through pointers are now emitted:

void foo(int (*a)[3])
{
(*a)[4] = 1;
}

Also warnings for arrays which are the last element of a struct
are emitted, if it is not a flexible array member or does not use
the zero size extensions.

Because there is the risk of false positives, the higher warning
level is not used by default.


Martin


* gcc/tree-vrp.c (check_array_ref): Emit more warnings
   for warn_array_bounds >= 2.
* gcc/testsuite/gcc.dg/Warray-bounds-11.c: New test-case.
* gcc/c-family/c.opt: New option -Warray-bounds=.
* gcc/common.opt: New option -Warray-bounds=.
* gcc/doc/invoke.texi: Document new option.


diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 66c62fb..0d5ecfd 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -279,6 +279,10 @@ Warray-bounds
 LangEnabledBy(C ObjC C++ ObjC++,Wall)
 ; in common.opt
 
+Warray-bounds=
+LangEnabledBy(C ObjC C++ ObjC++,Wall,1,0)
+; in common.opt
+
 Wassign-intercept
 ObjC ObjC++ Var(warn_assign_intercept) Warning
 Warn whenever an Objective-C assignment is being intercepted by the garbage 
collector
diff --git a/gcc/common.opt b/gcc/common.opt
index b400636..d65085a 100644
--- a/gcc/common.opt
+++ b/gcc/common.opt
@@ -525,6 +525,10 @@ Warray-bounds
 Common Var(warn_array_bounds) Warning
 Warn if an array is accessed out of bounds
 
+Warray-bounds=
+Common Joined RejectNegative UInteger Var(warn_array_bounds) Warning
+Warn if an array is accessed out of bounds
+
 Wattributes
 Common Var(warn_attributes) Init(1) Warning
 Warn about inappropriate attribute usage
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index 57666db..afc4be8 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -239,7 +239,7 @@ Objective-C and Objective-C++ Dialects}.
 @gccoptlist{-fsyntax-only  -fmax-errors=@var{n}  -Wpedantic @gol
 -pedantic-errors @gol
 -w  -Wextra  -Wall  -Waddress  -Waggregate-return  @gol
--Waggressive-loop-optimizations -Warray-bounds @gol
+-Waggressive-loop-optimizations -Warray-bounds -Warray-bounds=@var{n} @gol
 -Wbool-compare @gol
 -Wno-attributes -Wno-builtin-macro-redefined @gol
 -Wc90-c99-compat -Wc99-c11-compat @gol
@@ -3344,7 +3344,7 @@ Options} and @ref{Objective-C and Objective-C++ Dialect 
Options}.
 @option{-Wall} turns on the following warning flags:
 
 @gccoptlist{-Waddress   @gol
--Warray-bounds @r{(only with} @option{-O2}@r{)}  @gol
+-Warray-bounds=1 @r{(only with} @option{-O2}@r{)}  @gol
 -Wc++11-compat  @gol
 -Wchar-subscripts  @gol
 -Wenum-compare @r{(in C/ObjC; this is on by default in C++)} @gol
@@ -4239,12 +4239,26 @@ hiearchy graph is more complete. It is recommended to 
first consider suggestins
 of @option{-Wsuggest-final-types} and then rebuild with new annotations.
 
 @item -Warray-bounds
+@itemx -Warray-bounds=@var{n}
 @opindex Wno-array-bounds
 @opindex Warray-bounds
 This option is only active when @option{-ftree-vrp} is active
 (default for @option{-O2} and above). It warns about subscripts to arrays
 that are always out of bounds. This warning is enabled by @option{-Wall}.
 
+@table @gcctabopt
+@item -Warray-bounds=1
+This is the warning level of @option{-Warray-bounds} and is enabled
+by @option{-Wall}; higher levels are not, and must be explicitly requested.
+
+@item -Warray-bounds=2
+This warning level also warns about out of bounds access for
+arrays at the end of a struct and for arrays accessed through
+pointers. This warning level may give a larger number of
+false positives and is deactivated by default.
+@end table
+
+
 @item -Wbool-compare
 @opindex Wno-bool-compare
 @opindex Wbool-compare
diff --git a/gcc/testsuite/gcc.dg/Warray-bounds-11.c 
b/gcc/testsuite/gcc.dg/Warray-bounds-11.c
new file mode 100644
index 000..2e68498
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Warray-bounds-11.c
@@ -0,0 +1,96 @@
+/* { dg-do compile } */
+/* { dg-options "-O3 -Warray-bounds=2" } */
+
+extern void* malloc(unsigned long x);
+
+int e[3];
+
+struct f { int f[3]; };
+
+extern void bar(int v[]);
+
+struct h {
+
+   int i;
+   int j[];
+};
+
+struct h0 {
+
+   int i;
+   int j[0];
+};
+
+struct h0b {
+
+   int i;
+   int j[0];
+   int k;
+};
+
+struct h1 {
+
+   int i;
+   int j[1];
+};
+
+struct h1b {
+
+   int i;
+   int j[1];
+   int k;
+};
+
+struct h3 {
+
+   int i;
+   int j[3];
+};
+
+struct h3b {
+
+   int i;
+   int j[3];
+   int k;
+};
+
+void foo(int (*a)[3])
+{
+   (*a)[4] = 1;/* { dg-warning "subscript is above array bound" } */
+   a[0][0] = 1;// ok
+   a[1][0] = 1;// ok
+   a[1][4] = 1;/* { dg-warning "subscript is above array bound" } */
+
+   int c[3] = { 0 };
+
+   c[4] = 1;   /* { dg-warning 

[PATCH v4] warning about const multidimensional array as function parameter

2014-11-10 Thread Martin Uecker

For completeness, this version adds the missing warning if the 
'const' is lost in a conditional expression with a void* on the
other branch. The only code change relative to the previous
version is in c/c-typeck.c in build_conditional_expr (otherwise 
I added the warnings to the testsuite and fixed some typos and 
trailing whitespace errors).

I would rather have the 'const' propagate to the result
of the conditional expression as with regular pointers to
const, but I do not see an easy way to make the warnings
(or errors) which could result from this be dependent on 
-Wdiscarded-array-qualifiers.

Joseph Myers :

> On Thu, 6 Nov 2014, Martin Uecker wrote:
> > This patch implements a new proposed behaviour for 
> > pointers to arrays with qualifiers in C.
> > 
> > I found some time to work on this again, so here is another 
> > revision. Main changes to the previous version of the patch:
> > 
> > - add more test cases for cast from/to (const) void*
> > - correctly uses pedwarn/warning_at
> 
> Thanks.  I'll review this in more detail later, but I suspect it's quite 
> close to being ready to go in once the paperwork has been processed.

Thank you. I got the form and have sent it back, but did not get
a reply yet.
 
Martin


2014-11-10 Martin Uecker 

* doc/invoke.texi: Document -Wdiscarded-array-qualifiers
* doc/extend.texi: Document new behavior for pointers to arrays with 
qualifies
c/
* c-typeck.c: New behavious for pointers to arrays with qualifiers
(common-pointer-type): For pointers to arrays take qualifiers from 
element type.
(build_conditional_expr): Add warnings for lost qualifiers.
(comp-target-types): Allow pointers to arrays with different qualifiers.
(convert-for-assignment): Adapt warnings for discarded qualifiers. Add
WARNING_FOR_QUALIFIERS macro and rename WARN_FOR_QUALIFIERS 
to PEDWARN_FOR_QUALIFIERS.
c-family/
* c.opt (Wdiscarded-array-qualifiers): New option
testsuite/
* gcc.dg/Wwrite-strings-1.c: Change dg-warning
* gcc.dg/array-quals-1.c: Use -Wno-discarded-array-qualifiers
* gcc.dg/array-quals-2.c: Change dg-options, dg-warning
* gcc.dg/pointer-array-atomic.c: New test
* gcc.dg/pointer-array-quals-1.c: New test
* gcc.dg/pointer-array-quals-2.c: New test (-pedantic-errors)




Index: gcc/c/c-typeck.c
===
--- gcc/c/c-typeck.c(Revision 217273)
+++ gcc/c/c-typeck.c(Arbeitskopie)
@@ -673,12 +673,13 @@ common_pointer_type (tree t1, tree t2)
 mv2 = TYPE_MAIN_VARIANT (pointed_to_2);
   target = composite_type (mv1, mv2);
 
+  /* Strip array types to get correct qualifier for pointers to arrays */
+  quals1 = TYPE_QUALS_NO_ADDR_SPACE (strip_array_types (pointed_to_1));
+  quals2 = TYPE_QUALS_NO_ADDR_SPACE (strip_array_types (pointed_to_2));
+
   /* For function types do not merge const qualifiers, but drop them
  if used inconsistently.  The middle-end uses these to mark const
  and noreturn functions.  */
-  quals1 = TYPE_QUALS_NO_ADDR_SPACE (pointed_to_1);
-  quals2 = TYPE_QUALS_NO_ADDR_SPACE (pointed_to_2);
-
   if (TREE_CODE (pointed_to_1) == FUNCTION_TYPE)
 target_quals = (quals1 & quals2);
   else
@@ -1224,6 +1225,7 @@ static int
 comp_target_types (location_t location, tree ttl, tree ttr)
 {
   int val;
+  int val_ped;
   tree mvl = TREE_TYPE (ttl);
   tree mvr = TREE_TYPE (ttr);
   addr_space_t asl = TYPE_ADDR_SPACE (mvl);
@@ -1235,19 +1237,32 @@ comp_target_types (location_t location, tree ttl,
   if (!addr_space_superset (asl, asr, &as_common))
 return 0;
 
-  /* Do not lose qualifiers on element types of array types that are
- pointer targets by taking their TYPE_MAIN_VARIANT.  */
-  if (TREE_CODE (mvl) != ARRAY_TYPE)
-mvl = (TYPE_ATOMIC (mvl)
-  ? c_build_qualified_type (TYPE_MAIN_VARIANT (mvl), TYPE_QUAL_ATOMIC)
-  : TYPE_MAIN_VARIANT (mvl));
-  if (TREE_CODE (mvr) != ARRAY_TYPE)
-mvr = (TYPE_ATOMIC (mvr)
-  ? c_build_qualified_type (TYPE_MAIN_VARIANT (mvr), TYPE_QUAL_ATOMIC)
-  : TYPE_MAIN_VARIANT (mvr));
+  /* For pedantic record result of comptypes on arrays before losing
+ qualifiers on the element type below. */
+  val_ped = 1;
+
+  if (TREE_CODE (mvl) == ARRAY_TYPE
+  && TREE_CODE (mvr) == ARRAY_TYPE)
+val_ped = comptypes (mvl, mvr);
+
+  /* Qualifiers on element types of array types that are
+ pointer targets are lost by taking their TYPE_MAIN_VARIANT.  */
+
+  mvl = (TYPE_ATOMIC (strip_array_types (mvl))
+? c_build_qualified_type (TYPE_MAIN_VARIANT (mvl), TYPE_QUAL_ATOMIC)
+: TYPE_MAIN_VARIANT (mvl));
+
+  mvr = (TYPE_ATOMIC (strip_array_types (mvr))
+? c_build_qualified_type (TYPE_MAIN_VARIANT (mvr), TYPE_QUAL_ATOMIC)
+: TYPE_MAIN_VARIANT (mvr));
+
 

[PATCH v3] warning about const multidimensional array as function parameter

2014-11-06 Thread Martin Uecker


This patch implements a new proposed behaviour for 
pointers to arrays with qualifiers in C.

I found some time to work on this again, so here is another 
revision. Main changes to the previous version of the patch:

- add more test cases for cast from/to (const) void*
- correctly uses pedwarn/warning_at


previous versions (see v1 for a description of the main idea):
v2: https://gcc.gnu.org/ml/gcc/2014-10/msg00243.html
v1: https://gcc.gnu.org/ml/gcc/2014-10/msg00224.html



On Wed, 29 Oct 2014 16:43:16 +
"Joseph S. Myers" :
> On Tue, 28 Oct 2014, Martin Uecker wrote:

> > Note that there is now a semantic (and not only diagnostic) change.
> > Without this patch
> > 
> > const int a[1];
> > int b[1];
> > (x ? &a : &b)
> > 
> > would return a 'void*' and a warning about pointer type mismatch.
> > With this patch the conditional has type 'const int (*)[1]'.
> 
> I believe that is safe (in that that conditional expression isn't valid in 
> ISO C).  What wouldn't be safe is making a conditional expression between 
> void * and const int (*)[] have type const void * instead of void *.

Yes, the cases which are changed in the patch should all
be illegal in ISO C. 

On the other hand, not changing the case you mention means that
there is still inconsistent behaviour even with the patch:
 
void* v;
const int (*i)[1];
int (*ip)[1] = (1 ? v : i); // const is lost in conditional

const int (*i2);
int (*ip2) = (1 ? v : i2);  // const is not lost -> warning

Maybe I should at least add a warning for the first case where the 
'const' is lost already in the conditional?


> WARN_FOR_QUALIFIERS uses pedwarn.  That means this is not safe, because 
> pedwarns become errors with -pedantic-errors, but this includes cases that 
> are valid in ISO C and so must not become errors with -pedantic-errors 
> (such as converting const int (*)[] to void *).

Ok. I added a new macro WARNING_FOR_QUALIFIERS and renamed the others
to PEDWARN_FOR_* . The full logic to make this work correctly turned
out to be quite simple. 

The behaviour can be summarized like this:

p2ca = pointer to const array
p2cv = pointer to const void
...

lq = loss of qualifier
ip = incompatible pointer 
'!' error with -pedantic-errors
'*' can be deactivated with a new option

conversionold  new   new+pedantic
p2ca -> p2a : ip! | lq* | ip! + lq*
p2a  -> p2ca: ip! | | ip!
p2v  -> p2a : | | 
p2v -> p2ca : | |
p2cv -> p2a : lq! | lq! | lq!
p2cv -> p2ca: lq! | | lq!
p2a -> p2v  : | | 
p2a -> p2cv : | |
p2ca -> p2v : | lq* | lq*
p2ca -> p2cv: | |




2014-10-28 Martin Uecker 

* doc/invoke.texi: Document -Wdiscarded-array-qualifiers
* doc/extend.texi: Document new behavior for pointers to arrays with 
qualifies
c/
* c-typeck.c: New behavious for pointers to arrays with qualifiers
(common-pointer-type): For pointers to arrays take qualifiers from 
element type.
(comp-target-types): Allow pointers to arrays with different qualifiers.
(convert-for-assignment): Change warnings for discarded qualifiers. Add
WARNING_FOR_QUALIFIERS macro and rename WARN_FOR_QUALIFIERS 
to PEDWARN_FOR_QUALIFIERS.
c-family/
* c.opt (Wdiscarded-array-qualifiers): New option
testsuite/
* gcc.dg/Wwrite-strings-1.c: Change dg-warning
* gcc.dg/array-quals-1.c: Use -Wno-discarded-array-qualifiers
* gcc.dg/array-quals-2.c: Change dg-options, dg-warning
* gcc.dg/pointer-array-atomic.c: New test
* gcc.dg/pointer-array-quals-1.c: New test
* gcc.dg/pointer-array-quals-2.c: New test (-pedantic-errors)


Index: gcc/c/c-typeck.c
===
--- gcc/c/c-typeck.c(Revision 217175)
+++ gcc/c/c-typeck.c(Arbeitskopie)
@@ -673,12 +673,13 @@ common_pointer_type (tree t1, tree t2)
 mv2 = TYPE_MAIN_VARIANT (pointed_to_2);
   target = composite_type (mv1, mv2);
 
+  /* Strip array types to get correct qualifier for pointers to arrays */
+  quals1 = TYPE_QUALS_NO_ADDR_SPACE (strip_array_types (pointed_to_1));
+  quals2 = TYPE_QUALS_NO_ADDR_SPACE (strip_array_types (pointed_to_2));
+
   /* For function types do not merge const qualifiers, but drop them
  if used inconsistently.  The middle-end uses these to mark const
  and noreturn functions.  */
-  quals1 = TYPE_QUALS_NO_ADDR_SPACE (pointed_to_1);
-  quals2 = TYPE_QUALS_NO_ADDR_SPACE (pointed_to_2);
-
   if (TREE_CODE (pointed_to_1) == FUNCTION_TYPE)
 target_quals = (quals1 & quals2);
   else
@@ -1224,6 +1225,7 @@ static int
 comp_target_types (location_t location, tree ttl, tree ttr)
 {
   int val;
+  int val_ped;
   tree mvl = TREE_TYPE (ttl);
   tree mvr = TREE_TYPE (ttr);
   addr_space_t asl = TYPE_ADDR

<    1   2   3   4   >