Fix ICE with -g and -std=c23 when forming composite types [PR113438]

2024-01-27 Thread Martin Uecker


Debug output ICEs when we do not set TYPE_STUB_DECL, fix this.


Fix ICE with -g and -std=c23 when forming composite types [PR113438]

Set TYPE_STUB_DECL to an artificial decl when creating a new structure
as a composite type.

PR c/113438

gcc/c/
* c-typeck.cc (composite_type_internal): Set TYPE_STUB_DECL.

gcc/testsuite/
* gcc.dg/pr113438.c: New test.

diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 66c6abc9f07..cfa3b7ab10f 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -585,6 +585,11 @@ composite_type_internal (tree t1, tree t2, struct 
composite_cache* cache)
  /* Setup the struct/union type.  Because we inherit all variably
 modified components, we can ignore the size expression.  */
  tree expr = NULL_TREE;
+
+ /* Set TYPE_STUB_DECL for debugging symbols.  */
+ TYPE_STUB_DECL (n) = pushdecl (build_decl (input_location, TYPE_DECL,
+NULL_TREE, n));
+
  n = finish_struct(input_location, n, fields, attributes, NULL, &expr);
 
  n = qualify_type (n, t1);
diff --git a/gcc/testsuite/gcc.dg/pr113438.c b/gcc/testsuite/gcc.dg/pr113438.c
new file mode 100644
index 000..5612ee4fa38
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr113438.c
@@ -0,0 +1,7 @@
+/* PR113438
+ * { dg-do compile }
+ * { dg-options "-std=c23 -g" } */
+
+void g(struct foo { int x; } a);
+void g(struct foo { int x; } a);
+



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

2024-01-26 Thread Martin Uecker


I haven't looked at the patch, but it sounds you give the result
the wrong type. Then patching up all use cases instead of the
type seems wrong.

Martin


Am Donnerstag, dem 25.01.2024 um 20:11 + schrieb Qing Zhao:
> Thanks a lot for the testing.
> 
> Yes, I can repeat the issue with the following small example:
> 
> #include 
> #include 
> #include 
> 
> #define MAX(a, b)  ((a) > (b) ? (a) :  (b))
> 
> struct untracked {
>int size;
>int array[] __attribute__((counted_by (size)));
> } *a;
> struct untracked * alloc_buf (int index)
> {
>   struct untracked *p;
>   p = (struct untracked *) malloc (MAX (sizeof (struct untracked),
> (offsetof (struct untracked, array[0])
>  + (index) * sizeof (int;
>   p->size = index;
>   return p;
> }
> 
> int main()
> {
>   a = alloc_buf(10);
>  printf ("same_type is %d\n",
>   (__builtin_types_compatible_p(typeof (a->array), typeof (&(a->array)[0];
>   return 0;
> }
> 
> 
> /home/opc/Install/latest-d/bin/gcc -O2 btcp.c
> same_type is 1
> 
> Looks like that the “typeof” operator need to be handled specially in C FE
>  for the new internal function .ACCESS_WITH_SIZE. 
> 
> (I have specially handle the operator “offsetof” in C FE already).
> 
> Will fix this issue.
> 
> Thanks.
> 
> Qing
> 
> > On Jan 24, 2024, at 7:51 PM, Kees Cook  wrote:
> > 
> > On Wed, Jan 24, 2024 at 12:29:51AM +, Qing Zhao wrote:
> > > This is the 4th version of the patch.
> > 
> > Thanks very much for this!
> > 
> > I tripped over an unexpected behavioral change that the Linux kernel
> > depends on:
> > 
> > __builtin_types_compatible_p() no longer treats an array marked with
> > counted_by as different from that array's decayed pointer. Specifically,
> > the kernel uses these macros:
> > 
> > 
> > /*
> > * Force a compilation error if condition is true, but also produce a
> > * result (of value 0 and type int), so the expression can be used
> > * e.g. in a structure initializer (or where-ever else comma expressions
> > * aren't permitted).
> > */
> > #define BUILD_BUG_ON_ZERO(e) ((int)(sizeof(struct { int:(-!!(e)); })))
> > 
> > #define __same_type(a, b) __builtin_types_compatible_p(typeof(a), typeof(b))
> > 
> > /* &a[0] degrades to a pointer: a different type from an array */
> > #define __must_be_array(a)   BUILD_BUG_ON_ZERO(__same_type((a), &(a)[0]))
> > 
> > 
> > This gets used in various places to make sure we're dealing with an
> > array for a macro:
> > 
> > #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + 
> > __must_be_array(arr))
> > 
> > 
> > So this builds:
> > 
> > struct untracked {
> >int size;
> >int array[];
> > } *a;
> > 
> > __must_be_array(a->array)
> > => 0 (as expected)
> > __builtin_types_compatible_p(typeof(a->array), typeof(&(a->array)[0]))
> > => 0 (as expected, array vs decayed array pointer)
> > 
> > 
> > But if counted_by is added, we get a build failure:
> > 
> > struct tracked {
> >int size;
> >int array[] __counted_by(size);
> > } *b;
> > 
> > __must_be_array(b->array)
> > => build failure (not expected)
> > __builtin_types_compatible_p(typeof(b->array), typeof(&(b->array)[0]))
> > => 1 (not expected, both pointers?)
> > 
> > 
> > 
> > 
> > -- 
> > Kees Cook
> 



[C PATCH] Fix ICE for composite type for structs with unsigned bitfields [PR113492]

2024-01-20 Thread Martin Uecker


C23: Fix ICE for composite type for structs with unsigned bitfields [PR113492]

This patch fixes a bug when forming a composite type from structs that
contain an unsigned bitfield declared with int while using -funsigned-bitfields.
In such structs the unsigned integer type was not compatible to the
regular unsigned integer type used elsewhere in the C FE.

PR c/113492

gcc/c:
* c-decl.cc (grokdeclarator): Use c_common_unsigned_type instead of
unsigned_type_for to create the unsigned type for bitfields declared
with int when using -funsigned-bitfields.

gcc/testsuite:
* gcc.dg/pr113492.c: New test.




diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 4029bbc59fe..8d18a3e11f4 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -6947,7 +6947,7 @@ grokdeclarator (const struct c_declarator *declarator,
  "signed".  */
   if (bitfield && !flag_signed_bitfields && !declspecs->explicit_signed_p
   && TREE_CODE (type) == INTEGER_TYPE)
-type = unsigned_type_for (type);
+type = c_common_unsigned_type (type);
 
   /* Figure out the type qualifiers for the declaration.  There are
  two ways a declaration can become qualified.  One is something
diff --git a/gcc/testsuite/gcc.dg/pr113492.c b/gcc/testsuite/gcc.dg/pr113492.c
new file mode 100644
index 000..56296c51072
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr113492.c
@@ -0,0 +1,43 @@
+/* PR 113492
+ * { dg-do compile }
+ * { dg-options "-std=c23 -funsigned-bitfields" } */
+
+struct foo {
+   int i : 3;
+} i;
+
+void test()
+{
+   struct foo {
+   unsigned i : 3;
+   } u;
+
+   1 ? i : u;
+   1 ? u : i;
+}
+   
+struct bar {
+   unsigned i : 3;
+} u;
+
+void test2()
+{
+   struct bar {
+   int i : 3;
+   } i;
+
+   1 ? i : u;
+   1 ? u : i;
+}
+   
+void test3()
+{
+   typedef int myint;
+   struct bar {
+   myint i : 3;
+   } i;
+
+   1 ? i : u;
+   1 ? u : i;
+}
+



[C PATCH] C: Fix type compatibility for structs with variable sized fields.

2023-12-27 Thread Martin Uecker


This patch hopefully fixes the test failure we see with gnu23-tag-4.c.
It does for me locally with -march=native (which otherwise reproduces
the problem).

Bootstrapped and regession tested on x86_64


C: Fix type compatibility for structs with variable sized fields.

This fixes the test gcc.dg/gnu23-tag-4.c introduced by commit 23fee88f
which fails for -march=... because the DECL_FIELD_BIT_OFFSET are set
inconsistently for types with and without variable-sized field.  This
is fixed by testing for DECL_ALIGN instead.  The code is further
simplified by removing some unnecessary conditions, i.e. anon_field is
set unconditionaly and all fields are assumed to be DECL_FIELDs.

gcc/c:
* c-typeck.c (tagged_types_tu_compatible_p): Revise.

gcc/testsuite:
* gcc.dg./c23-tag-9.c: New test.
---
 gcc/c/c-typeck.cc| 19 ---
 gcc/testsuite/gcc.dg/c23-tag-9.c |  8 
 2 files changed, 16 insertions(+), 11 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-9.c

diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 2d9139d09d2..84ddda1ebab 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -1511,8 +1511,6 @@ tagged_types_tu_compatible_p (const_tree t1, const_tree 
t2,
   if (!data->anon_field && TYPE_STUB_DECL (t1) != TYPE_STUB_DECL (t2))
 data->different_types_p = true;
 
-  data->anon_field = false;
-
   /* Incomplete types are incompatible inside a TU.  */
   if (TYPE_SIZE (t1) == NULL || TYPE_SIZE (t2) == NULL)
 return false;
@@ -1592,22 +1590,21 @@ tagged_types_tu_compatible_p (const_tree t1, const_tree 
t2,
 s1 && s2;
 s1 = DECL_CHAIN (s1), s2 = DECL_CHAIN (s2))
  {
-   if (TREE_CODE (s1) != TREE_CODE (s2)
-   || DECL_NAME (s1) != DECL_NAME (s2))
+   gcc_assert (TREE_CODE (s1) == FIELD_DECL);
+   gcc_assert (TREE_CODE (s2) == FIELD_DECL);
+
+   if (DECL_NAME (s1) != DECL_NAME (s2))
+ return false;
+
+   if (DECL_ALIGN (s1) != DECL_ALIGN (s2))
  return false;
 
-   if (!DECL_NAME (s1) && RECORD_OR_UNION_TYPE_P (TREE_TYPE (s1)))
- data->anon_field = true;
+   data->anon_field = !DECL_NAME (s1);
 
data->cache = &entry;
if (!comptypes_internal (TREE_TYPE (s1), TREE_TYPE (s2), data))
  return false;
 
-   if (TREE_CODE (s1) == FIELD_DECL
-   && simple_cst_equal (DECL_FIELD_BIT_OFFSET (s1),
-DECL_FIELD_BIT_OFFSET (s2)) != 1)
- return false;
-
tree st1 = TYPE_SIZE (TREE_TYPE (s1));
tree st2 = TYPE_SIZE (TREE_TYPE (s2));
 
diff --git a/gcc/testsuite/gcc.dg/c23-tag-9.c b/gcc/testsuite/gcc.dg/c23-tag-9.c
new file mode 100644
index 000..1d32560ec23
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/c23-tag-9.c
@@ -0,0 +1,8 @@
+/* { dg-do compile } */
+/* { dg-options "-std=c23" } */
+
+struct foo { int x; } x;
+struct foo { alignas(128) int x; } y;  /* { dg-error "redefinition" } */
+static_assert(alignof(y) == 128);
+
+
-- 
2.39.2





Re: [r14-6770 Regression] FAIL: gcc.dg/gnu23-tag-4.c (test for excess errors) on Linux/x86_64

2023-12-25 Thread Martin Uecker


Yes, I am testing a patch. The DECL_FIELD_BIT_OFFSET are set
inconsistently for some reason.

Martin 

Am Montag, dem 25.12.2023 um 07:49 + schrieb Jiang, Haochen:
> It is not a target specific issue, it will fail if we enabled AVX.
> 
> e.g.:
> 
> $ /export/users/haochenj/env/build_no_bootstrap_master/gcc/xgcc 
> -B/export/users/haochenj/env/build_no_bootstrap_master/gcc/  
> /export/users/haochenj/src/gcc/master/gcc/testsuite/gcc.dg/gnu23-tag-4.c  
> -m64 -mavx   -fdiagnostics-plain-output   -std=gnu23 -S -o gnu23-tag-4.s
> /export/users/haochenj/src/gcc/master/gcc/testsuite/gcc.dg/gnu23-tag-4.c: In 
> function ‘bar’:
> /export/users/haochenj/src/gcc/master/gcc/testsuite/gcc.dg/gnu23-tag-4.c:18:47:
>  error: initialization of ‘struct g *’ from incompatible pointer type ‘struct 
> g *’ [-Wincompatible-pointer-types]
> 
> Thx,
> Haochen
> 
> > -Original Message-
> > From: Martin Uecker 
> > Sent: Friday, December 22, 2023 5:39 PM
> > To: gcc-regress...@gcc.gnu.org; gcc-patches@gcc.gnu.org; Jiang, Haochen
> > ; Joseph Myers 
> > Subject: Re: [r14-6770 Regression] FAIL: gcc.dg/gnu23-tag-4.c (test for 
> > excess
> > errors) on Linux/x86_64
> > 
> > 
> > Hm, this is weird, as it really seems to depend on the -march=  So if 
> > there is
> > really a difference between those structs which make them incompatible on
> > some archs, we should not consider them to be compatible in general.
> > 
> > struct g { int a[n]; int b; } *y;
> > { struct g { int a[4]; int b; } *y2 = y; }
> > 
> > But I do not see what could go wrong here as sizeof / alignment is the same 
> > for
> > n = 4.  So there is something else I missed
> > 
> > 
> > 
> > Am Freitag, dem 22.12.2023 um 05:07 +0800 schrieb haochen.jiang:
> > > On Linux/x86_64,
> > > 
> > > 23fee88f84873b0b8b41c8e5a9b229d533fb4022 is the first bad commit
> > > commit 23fee88f84873b0b8b41c8e5a9b229d533fb4022
> > > Author: Martin Uecker 
> > > Date:   Tue Aug 15 14:58:32 2023 +0200
> > > 
> > > c23: tag compatibility rules for struct and unions
> > > 
> > > caused
> > > 
> > > FAIL: gcc.dg/gnu23-tag-4.c (test for excess errors)
> > > 
> > > with GCC configured with
> > > 
> > > ../../gcc/configure
> > > --prefix=/export/users/haochenj/src/gcc-bisect/master/master/r14-6770/
> > > usr --enable-clocale=gnu --with-system-zlib --with-demangler-in-ld
> > > --with-fpmath=sse --enable-languages=c,c++,fortran --enable-cet
> > > --without-isl --enable-libmpx x86_64-linux --disable-bootstrap
> > > 
> > > To reproduce:
> > > 
> > > $ cd {build_dir}/gcc && make check RUNTESTFLAGS="dg.exp=gcc.dg/gnu23-
> > tag-4.c --target_board='unix{-m32\ -march=cascadelake}'"
> > > $ cd {build_dir}/gcc && make check RUNTESTFLAGS="dg.exp=gcc.dg/gnu23-
> > tag-4.c --target_board='unix{-m64\ -march=cascadelake}'"
> > > 
> > > (Please do not reply to this email, for question about this report,
> > > contact me at haochen dot jiang at intel.com.) (If you met problems
> > > with cascadelake related, disabling AVX512F in command line might save
> > that.) (However, please make sure that there is no potential problems with
> > AVX512.)
> 



Re: [r14-6770 Regression] FAIL: gcc.dg/gnu23-tag-4.c (test for excess errors) on Linux/x86_64

2023-12-22 Thread Martin Uecker


Hm, this is weird, as it really seems to depend on the
-march=  So if there is really a difference
between those structs which make them incompatible on
some archs, we should not consider them to be
compatible in general.

struct g { int a[n]; int b; } *y;
{ struct g { int a[4]; int b; } *y2 = y; }

But I do not see what could go wrong here as
sizeof / alignment is the same for n = 4.  So there
is something else I missed



Am Freitag, dem 22.12.2023 um 05:07 +0800 schrieb haochen.jiang:
> On Linux/x86_64,
> 
> 23fee88f84873b0b8b41c8e5a9b229d533fb4022 is the first bad commit
> commit 23fee88f84873b0b8b41c8e5a9b229d533fb4022
> Author: Martin Uecker 
> Date:   Tue Aug 15 14:58:32 2023 +0200
> 
> c23: tag compatibility rules for struct and unions
> 
> caused
> 
> FAIL: gcc.dg/gnu23-tag-4.c (test for excess errors)
> 
> with GCC configured with
> 
> ../../gcc/configure 
> --prefix=/export/users/haochenj/src/gcc-bisect/master/master/r14-6770/usr 
> --enable-clocale=gnu --with-system-zlib --with-demangler-in-ld 
> --with-fpmath=sse --enable-languages=c,c++,fortran --enable-cet --without-isl 
> --enable-libmpx x86_64-linux --disable-bootstrap
> 
> To reproduce:
> 
> $ cd {build_dir}/gcc && make check RUNTESTFLAGS="dg.exp=gcc.dg/gnu23-tag-4.c 
> --target_board='unix{-m32\ -march=cascadelake}'"
> $ cd {build_dir}/gcc && make check RUNTESTFLAGS="dg.exp=gcc.dg/gnu23-tag-4.c 
> --target_board='unix{-m64\ -march=cascadelake}'"
> 
> (Please do not reply to this email, for question about this report, contact 
> me at haochen dot jiang at intel.com.)
> (If you met problems with cascadelake related, disabling AVX512F in command 
> line might save that.)
> (However, please make sure that there is no potential problems with AVX512.)



[V6] c23: construct composite type for tagged types

2023-12-21 Thread Martin Uecker


This version now sets  DECL_NONADDRESSABLE_P, DECL_PADDING_P 
and C_DECL_VARIABLE_SIZE and adds three new tests:
c23-tag-alias-7.c, c23-tag-composite-10.c, and 
gnu23-tag-composite-5.c.

Martin



Support for constructing composite types for structs and unions
in C23.

gcc/c:
* c-typeck.cc (composite_type_internal): Adapted from
composite_type to support structs and unions.
(composite_type): New wrapper function.
(build_conditional_operator): Return composite type.
* c-decl.cc (finish_struct): Allow NULL for
enclosing_struct_parse_info.

gcc/testsuite:
* gcc.dg/c23-tag-alias-6.c: New test.
* gcc.dg/c23-tag-alias-7.c: New test.
* gcc.dg/c23-tag-composite-1.c: New test.
* gcc.dg/c23-tag-composite-2.c: New test.
* gcc.dg/c23-tag-composite-3.c: New test.
* gcc.dg/c23-tag-composite-4.c: New test.
* gcc.dg/c23-tag-composite-5.c: New test.
* gcc.dg/c23-tag-composite-6.c: New test.
* gcc.dg/c23-tag-composite-7.c: New test.
* gcc.dg/c23-tag-composite-8.c: New test.
* gcc.dg/c23-tag-composite-9.c: New test.
* gcc.dg/c23-tag-composite-10.c: New test.
* gcc.dg/gnu23-tag-composite-1.c: New test.
* gcc.dg/gnu23-tag-composite-2.c: New test.
* gcc.dg/gnu23-tag-composite-3.c: New test.
* gcc.dg/gnu23-tag-composite-4.c: New test.
* gcc.dg/gnu23-tag-composite-5.c: New test.
---
 gcc/c/c-decl.cc  |  21 +--
 gcc/c/c-typeck.cc| 140 ---
 gcc/testsuite/gcc.dg/c23-tag-alias-6.c   |  32 +
 gcc/testsuite/gcc.dg/c23-tag-alias-7.c   |  34 +
 gcc/testsuite/gcc.dg/c23-tag-composite-1.c   |  26 
 gcc/testsuite/gcc.dg/c23-tag-composite-10.c  |  35 +
 gcc/testsuite/gcc.dg/c23-tag-composite-2.c   |  16 +++
 gcc/testsuite/gcc.dg/c23-tag-composite-3.c   |  50 +++
 gcc/testsuite/gcc.dg/c23-tag-composite-4.c   |  21 +++
 gcc/testsuite/gcc.dg/c23-tag-composite-5.c   |  25 
 gcc/testsuite/gcc.dg/c23-tag-composite-6.c   |  18 +++
 gcc/testsuite/gcc.dg/c23-tag-composite-7.c   |  20 +++
 gcc/testsuite/gcc.dg/c23-tag-composite-8.c   |  15 ++
 gcc/testsuite/gcc.dg/c23-tag-composite-9.c   |  19 +++
 gcc/testsuite/gcc.dg/gnu23-tag-composite-1.c |  45 ++
 gcc/testsuite/gcc.dg/gnu23-tag-composite-2.c |  30 
 gcc/testsuite/gcc.dg/gnu23-tag-composite-3.c |  24 
 gcc/testsuite/gcc.dg/gnu23-tag-composite-4.c |  28 
 gcc/testsuite/gcc.dg/gnu23-tag-composite-5.c |  29 
 19 files changed, 601 insertions(+), 27 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-alias-6.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-alias-7.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-composite-1.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-composite-10.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-composite-2.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-composite-3.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-composite-4.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-composite-5.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-composite-6.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-composite-7.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-composite-8.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-composite-9.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-composite-1.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-composite-2.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-composite-3.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-composite-4.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-composite-5.c

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 6639ec35e5f..b72738ea04a 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -9674,7 +9674,7 @@ finish_struct (location_t loc, tree t, tree fieldlist, 
tree attributes,
 }
 
   /* Check for consistency with previous definition.  */
-  if (flag_isoc23)
+  if (flag_isoc23 && NULL != enclosing_struct_parse_info)
 {
   tree vistype = previous_tag (t);
   if (vistype
@@ -9744,16 +9744,19 @@ finish_struct (location_t loc, tree t, tree fieldlist, 
tree attributes,
   if (warn_cxx_compat)
 warn_cxx_compat_finish_struct (fieldlist, TREE_CODE (t), loc);
 
-  delete struct_parse_info;
+  if (NULL != enclosing_struct_parse_info)
+{
+  delete struct_parse_info;
 
-  struct_parse_info = enclosing_struct_parse_info;
+  struct_parse_info = enclosing_struct_parse_info;
 
-  /* If this struct is defined inside a struct, add it to
- struct_types.  */
-  if (warn_cxx_compat
-  && struct_parse_info != NULL
-  && !in_sizeof && !in_typeof && !in_alignof)
-struct_parse_info->struct_types.safe_push (t);
+  /* If this struct is defined inside a struct, add it to
+struct_types.  */
+  if (warn_cxx_compat
+ && struct_parse_info != NULL
+ && !in_sizeof && !in_typeof && !in_alignof)

Re: [PATCH] c: Split -Wcalloc-transposed-args warning from -Walloc-size, -Walloc-size fixes

2023-12-19 Thread Martin Uecker
Am Dienstag, dem 19.12.2023 um 12:20 -0500 schrieb Jason Merrill:
> On 12/19/23 03:47, Jakub Jelinek wrote:
> > On Tue, Dec 19, 2023 at 08:11:11AM +0100, Martin Uecker wrote:
> > > Am Montag, dem 18.12.2023 um 20:14 +0100 schrieb Jakub Jelinek:
> > > > Hi!
> > > > 
> > > > The following patch changes -Walloc-size warning to no longer warn
> > > > about int *p = calloc (1, sizeof (int));, because as discussed earlier,
> > > > the size is IMNSHO sufficient in that case, for alloc_size with 2
> > > > arguments warns if the product of the 2 arguments is insufficiently 
> > > > small.
> > > > 
> > > > Also, it warns also for explicit casts of malloc/calloc etc. calls
> > > > rather than just implicit, so not just
> > > >int *p = malloc (1);
> > > > but also
> > > >int *p = (int *) malloc (1);
> > > > 
> > > > It also fixes some ICEs where the code didn't verify the alloc_size
> > > > arguments properly (Walloc-size-5.c testcase ICEs with vanilla trunk).
> > > > 
> > > > And lastly, it introduces a coding style warning, 
> > > > -Wcalloc-transposed-args
> > > > to warn for calloc (sizeof (struct S), 1) and similar calls (regardless
> > > > of what they are cast to, warning whenever first argument is sizeof and
> > > > the second is not).
> > > 
> > > I would generally see function arguments that are swapped relative
> > > to the documented ABI as more than a coding style issue even in
> > > cases where it can be expected to make no difference.
> > 
> > If you have suggestions how to reword the documentation, would that be
> > sufficient for you?  I still don't see why given correct alignment one can't
> > store struct S into sizeof (struct S) sized heap char array,
> 
> Seems to me one can in C++, anyway.  An unsigned char array can provide 
> storage for another type, and the call to calloc can be interpreted as 
> creating such an array if that gives the program defined behavior.
> https://eel.is/c++draft/intro.object#def:provides_storage
> https://eel.is/c++draft/intro.object#def:object,implicit_creation

This is also true in C.  There is nothing wrong with calloc(10, 1)
allocating a char array with 10 elements and then storing a struct
of size 10 in it.


Martin

> 



Re: [PATCH] c: Split -Wcalloc-transposed-args warning from -Walloc-size, -Walloc-size fixes

2023-12-19 Thread Martin Uecker
Am Dienstag, dem 19.12.2023 um 09:47 +0100 schrieb Jakub Jelinek:
> On Tue, Dec 19, 2023 at 08:11:11AM +0100, Martin Uecker wrote:
> > Am Montag, dem 18.12.2023 um 20:14 +0100 schrieb Jakub Jelinek:
> > > Hi!
> > > 
> > > The following patch changes -Walloc-size warning to no longer warn
> > > about int *p = calloc (1, sizeof (int));, because as discussed earlier,
> > > the size is IMNSHO sufficient in that case, for alloc_size with 2
> > > arguments warns if the product of the 2 arguments is insufficiently small.
> > > 
> > > Also, it warns also for explicit casts of malloc/calloc etc. calls
> > > rather than just implicit, so not just
> > >   int *p = malloc (1);
> > > but also
> > >   int *p = (int *) malloc (1);
> > > 
> > > It also fixes some ICEs where the code didn't verify the alloc_size
> > > arguments properly (Walloc-size-5.c testcase ICEs with vanilla trunk).
> > > 
> > > And lastly, it introduces a coding style warning, -Wcalloc-transposed-args
> > > to warn for calloc (sizeof (struct S), 1) and similar calls (regardless
> > > of what they are cast to, warning whenever first argument is sizeof and
> > > the second is not).
> > 
> > I would generally see function arguments that are swapped relative
> > to the documented ABI as more than a coding style issue even in 
> > cases where it can be expected to make no difference.
> 
> If you have suggestions how to reword the documentation, would that be
> sufficient for you?  

Maybe simple remove "This is a coding style warning." ?

> I still don't see why given correct alignment one can't
> store struct S into sizeof (struct S) sized heap char array, but if the
> documentation explain reasons why should one write it one way and not the
> other except for coding style, sure.

I do not think we need to argue one way or the other in
the documentation.  

> 
> > > Ok for trunk if this passes bootstrap/regtest?
> > 
> > I wonder whether we could turn on -Walloc-size for -Wall with this change?
> 
> I think that is a possibility, yes.
> 
> BTW, the patch passed bootstrap/regtest on x86_64-linux and i686-linux.
> 
>   Jakub

Anyway, thank you for fixing / improving this warning!

Martin



Re: [PATCH] c: Split -Wcalloc-transposed-args warning from -Walloc-size, -Walloc-size fixes

2023-12-18 Thread Martin Uecker
Am Montag, dem 18.12.2023 um 20:14 +0100 schrieb Jakub Jelinek:
> Hi!
> 
> The following patch changes -Walloc-size warning to no longer warn
> about int *p = calloc (1, sizeof (int));, because as discussed earlier,
> the size is IMNSHO sufficient in that case, for alloc_size with 2
> arguments warns if the product of the 2 arguments is insufficiently small.
> 
> Also, it warns also for explicit casts of malloc/calloc etc. calls
> rather than just implicit, so not just
>   int *p = malloc (1);
> but also
>   int *p = (int *) malloc (1);
> 
> It also fixes some ICEs where the code didn't verify the alloc_size
> arguments properly (Walloc-size-5.c testcase ICEs with vanilla trunk).
> 
> And lastly, it introduces a coding style warning, -Wcalloc-transposed-args
> to warn for calloc (sizeof (struct S), 1) and similar calls (regardless
> of what they are cast to, warning whenever first argument is sizeof and
> the second is not).

I would generally see function arguments that are swapped relative
to the documented ABI as more than a coding style issue even in 
cases where it can be expected to make no difference.

> 
> Ok for trunk if this passes bootstrap/regtest?

I wonder whether we could turn on -Walloc-size for -Wall with this change?


Martin


> 
> If yes, I'd implement it for C++ next.
> If not, we should at least fix the ICEs.
> 
> 2023-12-18  Jakub Jelinek  
> 
> gcc/
>   * doc/invoke.texi (-Walloc-size): Add to the list of
>   warning options, remove unnecessary line-break.
>   (-Wcalloc-transposed-args): Document new warning.
> gcc/c-family/
>   * c.opt (Wcalloc-transposed-args): New warning.
>   * c-common.h (warn_for_calloc, warn_for_alloc_size): Declare.
>   * c-warn.cc (warn_for_calloc, warn_for_alloc_size): New functions.
> gcc/c/
>   * c-parser.cc (c_parser_postfix_expression_after_primary): Grow
>   sizeof_arg and sizeof_arg_loc arrays to 6 elements.  Call
>   warn_for_calloc if warn_calloc_transposed_args for functions with
>   alloc_size type attribute with 2 arguments.
>   (c_parser_expr_list): Use 6 instead of 3.
>   * c-typeck.cc (build_c_cast): Call warn_for_alloc_size for casts
>   of calls to functions with alloc_size type attribute.
>   (convert_for_assignment): Likewise.
> gcc/testsuite/
>   * gcc.dg/Walloc-size-4.c: New test.
>   * gcc.dg/Walloc-size-5.c: New test.
>   * gcc.dg/Wcalloc-transposed-args-1.c: New test.
> 
> --- gcc/doc/invoke.texi.jj2023-12-18 09:39:49.411355496 +0100
> +++ gcc/doc/invoke.texi   2023-12-18 19:59:37.139525128 +0100
> @@ -328,7 +328,7 @@ Objective-C and Objective-C++ Dialects}.
>  -pedantic-errors -fpermissive
>  -w  -Wextra  -Wall  -Wabi=@var{n}
>  -Waddress  -Wno-address-of-packed-member  -Waggregate-return
> --Walloc-size-larger-than=@var{byte-size}  -Walloc-zero
> +-Walloc-size  -Walloc-size-larger-than=@var{byte-size}  -Walloc-zero
>  -Walloca  -Walloca-larger-than=@var{byte-size}
>  -Wno-aggressive-loop-optimizations
>  -Warith-conversion
> @@ -344,6 +344,7 @@ Objective-C and Objective-C++ Dialects}.
>  -Wc++20-compat
>  -Wno-c++11-extensions  -Wno-c++14-extensions -Wno-c++17-extensions
>  -Wno-c++20-extensions  -Wno-c++23-extensions
> +-Wcalloc-transposed-args
>  -Wcast-align  -Wcast-align=strict  -Wcast-function-type  -Wcast-qual
>  -Wchar-subscripts
>  -Wclobbered  -Wcomment
> @@ -8260,8 +8261,7 @@ Warn about calls to allocation functions
>  @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}.
> +@code{calloc}, @code{malloc}, and @code{realloc}.
>  
>  @opindex Wno-alloc-zero
>  @opindex Walloc-zero
> @@ -8274,6 +8274,21 @@ when called with a zero size differs amo
>  of @code{realloc} has been deprecated) relying on it may result in subtle
>  portability bugs and should be avoided.
>  
> +@opindex Wcalloc-transposed-args
> +@opindex Wno-calloc-transposed-args
> +@item -Wcalloc-transposed-args
> +Warn about calls to allocation functions decorated with attribute
> +@code{alloc_size} with two arguments, which use @code{sizeof} operator
> +as the earlier size argument and don't use it as the later size argument.
> +This is a coding style warning.  The first argument to @code{calloc} is
> +documented to be number of elements in array, while the second argument
> +is size of each element, so @code{calloc (@var{n}, sizeof (int))} is 
> preferred
> +over @code{calloc (sizeof (int), @var{n})}.  If @code{sizeof} in the earlier
> +argument and not the latter is intentional, the warning can be suppressed
> +by using @code{calloc (sizeof (struct @var{S}) + 0, n)} or
> +@code{calloc (1 * sizeof (struct @var{S}), 4)} or using @code{sizeof} in the
> +later argument as well.
> +
>  @opindex Walloc-size-larger-than=
>  @opindex Wno-alloc-size-larger-than
>  @item -Walloc-size-lar

[V5] [C PATCH 4/4] c23: construct composite type for tagged types

2023-12-17 Thread Martin Uecker



Support for constructing composite types for structs and unions
in C23.

gcc/c:
* c-typeck.cc (composite_type_internal): Adapted from
composite_type to support structs and unions.
(composite_type): New wrapper function.
(build_conditional_operator): Return composite type.
* c-decl.cc (finish_struct): Allow NULL for
enclosing_struct_parse_info.

gcc/testsuite:
* gcc.dg/c23-tag-alias-6.c: New test.
* gcc.dg/c23-tag-composite-1.c: New test.
* gcc.dg/c23-tag-composite-2.c: New test.
* gcc.dg/c23-tag-composite-3.c: New test.
* gcc.dg/c23-tag-composite-4.c: New test.
* gcc.dg/c23-tag-composite-5.c: New test.
* gcc.dg/c23-tag-composite-6.c: New test.
* gcc.dg/c23-tag-composite-7.c: New test.
* gcc.dg/c23-tag-composite-8.c: New test.
* gcc.dg/c23-tag-composite-9.c: New test.
* gcc.dg/gnu23-tag-composite-1.c: New test.
* gcc.dg/gnu23-tag-composite-2.c: New test.
* gcc.dg/gnu23-tag-composite-3.c: New test.
* gcc.dg/gnu23-tag-composite-4.c: New test.
---
 gcc/c/c-decl.cc  |  21 +--
 gcc/c/c-typeck.cc| 137 ---
 gcc/testsuite/gcc.dg/c23-tag-alias-6.c   |  32 +
 gcc/testsuite/gcc.dg/c23-tag-composite-1.c   |  26 
 gcc/testsuite/gcc.dg/c23-tag-composite-2.c   |  16 +++
 gcc/testsuite/gcc.dg/c23-tag-composite-3.c   |  50 +++
 gcc/testsuite/gcc.dg/c23-tag-composite-4.c   |  21 +++
 gcc/testsuite/gcc.dg/c23-tag-composite-5.c   |  25 
 gcc/testsuite/gcc.dg/c23-tag-composite-6.c   |  18 +++
 gcc/testsuite/gcc.dg/c23-tag-composite-7.c   |  20 +++
 gcc/testsuite/gcc.dg/c23-tag-composite-8.c   |  15 ++
 gcc/testsuite/gcc.dg/c23-tag-composite-9.c   |  19 +++
 gcc/testsuite/gcc.dg/gnu23-tag-composite-1.c |  45 ++
 gcc/testsuite/gcc.dg/gnu23-tag-composite-2.c |  30 
 gcc/testsuite/gcc.dg/gnu23-tag-composite-3.c |  24 
 gcc/testsuite/gcc.dg/gnu23-tag-composite-4.c |  28 
 16 files changed, 500 insertions(+), 27 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-alias-6.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-composite-1.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-composite-2.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-composite-3.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-composite-4.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-composite-5.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-composite-6.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-composite-7.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-composite-8.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-composite-9.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-composite-1.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-composite-2.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-composite-3.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-composite-4.c

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 6639ec35e5f..b72738ea04a 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -9674,7 +9674,7 @@ finish_struct (location_t loc, tree t, tree fieldlist, 
tree attributes,
 }
 
   /* Check for consistency with previous definition.  */
-  if (flag_isoc23)
+  if (flag_isoc23 && NULL != enclosing_struct_parse_info)
 {
   tree vistype = previous_tag (t);
   if (vistype
@@ -9744,16 +9744,19 @@ finish_struct (location_t loc, tree t, tree fieldlist, 
tree attributes,
   if (warn_cxx_compat)
 warn_cxx_compat_finish_struct (fieldlist, TREE_CODE (t), loc);
 
-  delete struct_parse_info;
+  if (NULL != enclosing_struct_parse_info)
+{
+  delete struct_parse_info;
 
-  struct_parse_info = enclosing_struct_parse_info;
+  struct_parse_info = enclosing_struct_parse_info;
 
-  /* If this struct is defined inside a struct, add it to
- struct_types.  */
-  if (warn_cxx_compat
-  && struct_parse_info != NULL
-  && !in_sizeof && !in_typeof && !in_alignof)
-struct_parse_info->struct_types.safe_push (t);
+  /* If this struct is defined inside a struct, add it to
+struct_types.  */
+  if (warn_cxx_compat
+ && struct_parse_info != NULL
+ && !in_sizeof && !in_typeof && !in_alignof)
+   struct_parse_info->struct_types.safe_push (t);
+ }
 
   return t;
 }
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 4d3079156ba..ac31eba6e46 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -381,8 +381,15 @@ build_functype_attribute_variant (tree ntype, tree otype, 
tree attrs)
nonzero; if that isn't so, this may crash.  In particular, we
assume that qualifiers match.  */
 
+struct composite_cache {
+  tree t1;
+  tree t2;
+  tree composite;
+  struct composite_cache* next;
+};
+
 tree
-composite_type (tree t1, tree t2)
+composite_type_internal (tree t1, tree t2, struct composite_cache* cache)
 {
   enum tree_code code1;
   enum tree_code code2;
@@ -427,7 +4

[V5] [C PATCH 3/4] c23: aliasing of compatible tagged types

2023-12-17 Thread Martin Uecker



Tell the backend which types are equivalent by setting
TYPE_CANONICAL to one struct in the set of equivalent
structs.  Structs are considered equivalent by ignoring
all sizes of arrays nested in types below field level.

The following two structs are incompatible and lvalues
with these types can be assumed not to alias:

 struct foo { int a[3]; };
 struct foo { int a[4]; };

The following two structs are also incompatible, but
will get the same TYPE_CANONICAL and it is then not
exploited that lvalues with those types can not alias:

 struct bar { int (*p)[3]; };
 struct bar { int (*p)[4]; };

The reason is that both are compatible to

 struct bar { int (*p)[]; };

and therefore are in the same equivalence class.  For
the same reason all enums with the same underyling type
are in the same equivalence class.  Tests are added
for the expected aliasing behavior with optimization.

gcc/c:
* c-decl.cc (c_struct_hasher): Hash stable for struct
types.
(c_struct_hasher::hash, c_struct_hasher::equal): New
functions.
(finish_struct): Set TYPE_CANONICAL to first struct in
equivalence class.
* c-objc-common.cc (c_get_alias_set): Let structs or
unions with variable size alias anything.
* c-tree.h (comptypes_equiv): New prototype.
* c-typeck.cc (comptypes_equiv): New function.
(comptypes_internal): Implement equivalence mode.
(tagged_types_tu_compatible): Implement equivalence mode.

gcc/testsuite:
* gcc.dg/c23-tag-2.c: Activate.
* gcc.dg/c23-tag-5.c: Activate.
* gcc.dg/c23-tag-alias-1.c: New test.
* gcc.dg/c23-tag-alias-2.c: New test.
* gcc.dg/c23-tag-alias-3.c: New test.
* gcc.dg/c23-tag-alias-4.c: New test.
* gcc.dg/c23-tag-alias-5.c: New test.
* gcc.dg/gnu23-tag-alias-1.c: New test.
* gcc.dg/gnu23-tag-alias-2.c: New test.
* gcc.dg/gnu23-tag-alias-3.c: New test.
* gcc.dg/gnu23-tag-alias-4.c: New test.
* gcc.dg/gnu23-tag-alias-5.c: New test.
* gcc.dg/gnu23-tag-alias-6.c: New test.
* gcc.dg/gnu23-tag-alias-7.c: New test.
---
 gcc/c/c-decl.cc  |  51 ++-
 gcc/c/c-objc-common.cc   |   5 ++
 gcc/c/c-tree.h   |   1 +
 gcc/c/c-typeck.cc|  31 +++
 gcc/testsuite/gcc.dg/c23-tag-2.c |   2 +-
 gcc/testsuite/gcc.dg/c23-tag-5.c |   2 +-
 gcc/testsuite/gcc.dg/c23-tag-alias-1.c   |  49 +++
 gcc/testsuite/gcc.dg/c23-tag-alias-2.c   |  50 +++
 gcc/testsuite/gcc.dg/c23-tag-alias-3.c   |  32 +++
 gcc/testsuite/gcc.dg/c23-tag-alias-4.c   |  32 +++
 gcc/testsuite/gcc.dg/c23-tag-alias-5.c   |  36 
 gcc/testsuite/gcc.dg/gnu23-tag-alias-1.c |  33 +++
 gcc/testsuite/gcc.dg/gnu23-tag-alias-2.c |  85 ++
 gcc/testsuite/gcc.dg/gnu23-tag-alias-3.c |  83 ++
 gcc/testsuite/gcc.dg/gnu23-tag-alias-4.c |  36 
 gcc/testsuite/gcc.dg/gnu23-tag-alias-5.c | 107 +++
 gcc/testsuite/gcc.dg/gnu23-tag-alias-6.c |  60 +
 gcc/testsuite/gcc.dg/gnu23-tag-alias-7.c |  93 
 18 files changed, 785 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-alias-1.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-alias-2.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-alias-3.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-alias-4.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-alias-5.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-alias-1.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-alias-2.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-alias-3.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-alias-4.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-alias-5.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-alias-6.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-alias-7.c

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 26188aa225e..6639ec35e5f 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -634,6 +634,36 @@ public:
   auto_vec typedefs_seen;
 };
 
+
+/* Hash table for structs and unions.  */
+struct c_struct_hasher : ggc_ptr_hash
+{
+  static hashval_t hash (tree t);
+  static bool equal (tree, tree);
+};
+
+/* Hash an RECORD OR UNION.  */
+hashval_t
+c_struct_hasher::hash (tree type)
+{
+  inchash::hash hstate;
+
+  hstate.add_int (TREE_CODE (type));
+  hstate.add_object (TYPE_NAME (type));
+
+  return hstate.end ();
+}
+
+/* Compare two RECORD or UNION types.  */
+bool
+c_struct_hasher::equal (tree t1,  tree t2)
+{
+  return comptypes_equiv_p (t1, t2);
+}
+
+/* All tagged typed so that TYPE_CANONICAL can be set correctly.  */
+static GTY (()) hash_table *c_struct_htab;
+
 /* 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;
@@ -8713,7 +

[V5] [C PATCH 2/4] c23: tag compatibility rules for enums

2023-12-17 Thread Martin Uecker



Allow redefinition of enum types and enumerators.  Diagnose
nested redefinitions including redefinitions in the enum
specifier for enum types with fixed underlying type.

gcc/c:
* c-tree.h (c_parser_enum_specifier): Add parameter.
* c-decl.cc (start_enum): Allow redefinition.
(finish_enum): Diagnose conflicts.
(build_enumerator): Set context.
(diagnose_mismatched_decls): Diagnose conflicting enumerators.
(push_decl): Preserve context for enumerators.
* c-parser.cc (c_parser_enum_specifier): Remember when
seen is from an enum type which is not yet defined.

gcc/testsuide/:
* gcc.dg/c23-tag-enum-1.c: New test.
* gcc.dg/c23-tag-enum-2.c: New test.
* gcc.dg/c23-tag-enum-3.c: New test.
* gcc.dg/c23-tag-enum-4.c: New test.
* gcc.dg/c23-tag-enum-5.c: New test.
* gcc.dg/gnu23-tag-enum-1.c: Mew test.
---
 gcc/c/c-decl.cc | 65 +
 gcc/c/c-parser.cc   |  5 +-
 gcc/c/c-tree.h  |  3 +-
 gcc/c/c-typeck.cc   |  5 +-
 gcc/testsuite/gcc.dg/c23-tag-enum-1.c   | 56 +
 gcc/testsuite/gcc.dg/c23-tag-enum-2.c   | 17 +++
 gcc/testsuite/gcc.dg/c23-tag-enum-3.c   |  7 +++
 gcc/testsuite/gcc.dg/c23-tag-enum-4.c   | 22 +
 gcc/testsuite/gcc.dg/c23-tag-enum-5.c   | 18 +++
 gcc/testsuite/gcc.dg/gnu23-tag-enum-1.c | 19 
 10 files changed, 205 insertions(+), 12 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-enum-1.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-enum-2.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-enum-3.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-enum-4.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-enum-5.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-enum-1.c

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 0e6b4a5248b..26188aa225e 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -2112,9 +2112,24 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
  given scope.  */
   if (TREE_CODE (olddecl) == CONST_DECL)
 {
-  auto_diagnostic_group d;
-  error ("redeclaration of enumerator %q+D", newdecl);
-  locate_old_decl (olddecl);
+  if (flag_isoc23
+ && TYPE_NAME (DECL_CONTEXT (newdecl))
+ && DECL_CONTEXT (newdecl) != DECL_CONTEXT (olddecl)
+ && TYPE_NAME (DECL_CONTEXT (newdecl)) == TYPE_NAME (DECL_CONTEXT 
(olddecl)))
+   {
+ if (!simple_cst_equal (DECL_INITIAL (olddecl), DECL_INITIAL 
(newdecl)))
+   {
+ auto_diagnostic_group d;
+ error ("conflicting redeclaration of enumerator %q+D", newdecl);
+ locate_old_decl (olddecl);
+   }
+   }
+  else
+   {
+ auto_diagnostic_group d;
+ error ("redeclaration of enumerator %q+D", newdecl);
+ locate_old_decl (olddecl);
+   }
   return false;
 }
 
@@ -3275,8 +3290,11 @@ pushdecl (tree x)
 
   /* Must set DECL_CONTEXT for everything not at file scope or
  DECL_FILE_SCOPE_P won't work.  Local externs don't count
- unless they have initializers (which generate code).  */
+ unless they have initializers (which generate code).  We
+ also exclude CONST_DECLs because enumerators will get the
+ type of the enum as context.  */
   if (current_function_decl
+  && TREE_CODE (x) != CONST_DECL
   && (!VAR_OR_FUNCTION_DECL_P (x)
  || DECL_INITIAL (x) || !TREE_PUBLIC (x)))
 DECL_CONTEXT (x) = current_function_decl;
@@ -9759,7 +9777,7 @@ layout_array_type (tree t)
 
 tree
 start_enum (location_t loc, struct c_enum_contents *the_enum, tree name,
-   tree fixed_underlying_type)
+   tree fixed_underlying_type, bool potential_nesting_p)
 {
   tree enumtype = NULL_TREE;
   location_t enumloc = UNKNOWN_LOCATION;
@@ -9771,9 +9789,26 @@ start_enum (location_t loc, struct c_enum_contents 
*the_enum, tree name,
   if (name != NULL_TREE)
 enumtype = lookup_tag (ENUMERAL_TYPE, name, true, &enumloc);
 
+  if (enumtype != NULL_TREE && TREE_CODE (enumtype) == ENUMERAL_TYPE)
+{
+  /* If the type is currently being defined or if we have seen an
+incomplete version which is now complete, this is a nested
+redefinition.  The later happens if the redefinition occurs
+inside the enum specifier itself.  */
+  if (C_TYPE_BEING_DEFINED (enumtype)
+ || (potential_nesting_p && TYPE_VALUES (enumtype) != NULL_TREE))
+   error_at (loc, "nested redefinition of %", name);
+
+  /* For C23 we allow redefinitions.  We set to zero and check for
+consistency later.  */
+  if (flag_isoc23 && TYPE_VALUES (enumtype) != NULL_TREE)
+   enumtype = NULL_TREE;
+}
+
   if (enumtype == NULL_TREE || TREE_CODE (enumtype) != ENUMERAL_TYPE)
 {
   enumtype = make_node (ENUMERAL_TYPE);
+  TYPE_SIZE (enumtype) = NULL_TREE;
   pushtag 

[V5] [C PATCH 1/4] c23: tag compatibility rules for struct and unions

2023-12-17 Thread Martin Uecker


Here is the revised series.  The first three patches only
have changes in the tests as well as the return value
changes.   The fourth patch was now also revised,
with changes and tests to make sure that the composite
type works correctly for bit-fields, anonymous structs/unions,
alignment, packed structs, attributes, aliasing, etc. 
It now calls finish_struct to reuse the existing code for
setting up the struct.


Bootstrapped and regression tested on x86_64.




Implement redeclaration and compatibility rules for
structures and unions in C23.

gcc/c/:
* c-decl.cc (previous_tag): New function.
(parser_xref_tag): Find earlier definition.
(get_parm_info): Turn off warning for C23.
(start_struct): Allow redefinitons.
(finish_struct): Diagnose conflicts.
* c-tree.h (comptypes_same_p): Add prototype.
* c-typeck.cc (comptypes_same_p): New function
(comptypes_internal): Activate comparison of tagged types.
(convert_for_assignment): Ignore qualifiers.
(digest_init): Add error.
(initialized_elementwise_p): Allow compatible types.

gcc/testsuite/:
* gcc.dg/c23-enum-7.c: Remove warning.
* gcc.dg/c23-tag-1.c: New test.
* gcc.dg/c23-tag-2.c: New deactivated test.
* gcc.dg/c23-tag-3.c: New test.
* gcc.dg/c23-tag-4.c: New test.
* gcc.dg/c23-tag-5.c: New deactivated test.
* gcc.dg/c23-tag-6.c: New test.
* gcc.dg/c23-tag-7.c: New test.
* gcc.dg/c23-tag-8.c: New test.
* gcc.dg/gnu23-tag-1.c: New test.
* gcc.dg/gnu23-tag-2.c: New test.
* gcc.dg/gnu23-tag-3.c: New test.
* gcc.dg/gnu23-tag-4.c: New test.
* gcc.dg/pr112488-2.c: Remove warning.
---
 gcc/c/c-decl.cc| 72 +++---
 gcc/c/c-tree.h |  1 +
 gcc/c/c-typeck.cc  | 38 +---
 gcc/testsuite/gcc.dg/c23-enum-7.c  |  6 +--
 gcc/testsuite/gcc.dg/c23-tag-1.c   | 67 +++
 gcc/testsuite/gcc.dg/c23-tag-2.c   | 43 ++
 gcc/testsuite/gcc.dg/c23-tag-3.c   | 16 +++
 gcc/testsuite/gcc.dg/c23-tag-4.c   | 26 +++
 gcc/testsuite/gcc.dg/c23-tag-5.c   | 33 ++
 gcc/testsuite/gcc.dg/c23-tag-6.c   | 58 
 gcc/testsuite/gcc.dg/c23-tag-7.c   | 12 +
 gcc/testsuite/gcc.dg/c23-tag-8.c   | 10 +
 gcc/testsuite/gcc.dg/gnu23-tag-1.c | 10 +
 gcc/testsuite/gcc.dg/gnu23-tag-2.c | 18 
 gcc/testsuite/gcc.dg/gnu23-tag-3.c | 28 
 gcc/testsuite/gcc.dg/gnu23-tag-4.c | 31 +
 gcc/testsuite/gcc.dg/pr112488-2.c  |  2 +-
 17 files changed, 454 insertions(+), 17 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-1.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-2.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-3.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-4.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-5.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-6.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-7.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-8.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-1.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-2.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-3.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-4.c

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 039a66fef09..0e6b4a5248b 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -2037,6 +2037,28 @@ locate_old_decl (tree decl)
decl, TREE_TYPE (decl));
 }
 
+
+/* Helper function.  For a tagged type, it finds the declaration
+   for a visible tag declared in the the same scope if such a
+   declaration exists.  */
+static tree
+previous_tag (tree type)
+{
+  struct c_binding *b = NULL;
+  tree name = TYPE_NAME (type);
+
+  if (name)
+b = I_TAG_BINDING (name);
+
+  if (b)
+b = b->shadowed;
+
+  if (b && B_IN_CURRENT_SCOPE (b))
+return b->decl;
+
+  return NULL_TREE;
+}
+
 /* Subroutine of duplicate_decls.  Compare NEWDECL to OLDDECL.
Returns true if the caller should proceed to merge the two, false
if OLDDECL should simply be discarded.  As a side effect, issues
@@ -8573,11 +8595,14 @@ get_parm_info (bool ellipsis, tree expr)
  if (TREE_CODE (decl) != UNION_TYPE || b->id != NULL_TREE)
{
  if (b->id)
-   /* The %s will be one of 'struct', 'union', or 'enum'.  */
-   warning_at (b->locus, 0,
-   "%<%s %E%> declared inside parameter list"
-   " will not be visible outside of this definition or"
-   " declaration", keyword, b->id);
+   {
+ /* The %s will be one of 'struct', 'union', or 'enum'.  */
+ if (!flag_isoc23)
+   warning_at (b->locus, 0,
+   "%<%s %E%> declared inside parameter list"
+ 

v2 [C PATCH] Fix regression causing ICE for structs with VLAs [PR 112488]

2023-12-09 Thread Martin Uecker


I revised version which fixes a problem with breaking other
callers of finish_rust. Please ignore the previous one.

Bootstrapped and regression tested on x86_64


Fix regression causing ICE for structs with VLAs [PR 112488]

A previous patch the fixed several ICEs related to size expressions
of VM types (PR c/70418, ...) caused a regression for structs where
a DECL_EXPR is not generated anymore although reqired.  We now call
add_decl_expr introduced by the previous patch from finish_struct.
The function is revised with a new argument to not set the TYPE_NAME
for the type to the DECL_EXPR in this specific case.

PR c/112488

gcc/c
* c-decl.cc (add_decl_expr): Revise.
(finish_struct): Create DECL_EXPR.
* c-parser.cc (c_parser_struct_or_union_specifier): Call
finish_struct with expression for VLA sizes.
* c-tree.h (finish_struct): Add argument.

gcc/testsuite
* gcc.dg/pr112488-1.c: New test.
* gcc.dg/pr112488-2.c: New test.
* gcc.dg/pr112898.c: New test.
* gcc.misc-tests/gcov-pr85350.c: Adapt.
---
 gcc/c/c-decl.cc | 33 -
 gcc/c/c-parser.cc   |  2 +-
 gcc/c/c-tree.h  |  3 +-
 gcc/testsuite/gcc.dg/pr112488-1.c   | 14 +
 gcc/testsuite/gcc.dg/pr112488-2.c   | 13 
 gcc/testsuite/gcc.dg/pr112898.c |  9 ++
 gcc/testsuite/gcc.misc-tests/gcov-pr85350.c |  2 +-
 7 files changed, 65 insertions(+), 11 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/pr112488-1.c
 create mode 100644 gcc/testsuite/gcc.dg/pr112488-2.c
 create mode 100644 gcc/testsuite/gcc.dg/pr112898.c

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 92c83e1bf10..039a66fef09 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -6618,12 +6618,10 @@ smallest_type_quals_location (const location_t 
*locations,
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)
+add_decl_expr (location_t loc, tree type, tree *expr, bool set_name_p)
 {
   tree bind = NULL_TREE;
-  if (decl_context == TYPENAME || decl_context == PARM
-  || decl_context == FIELD)
+  if (expr)
 {
   bind = build3 (BIND_EXPR, void_type_node, NULL_TREE, NULL_TREE,
 NULL_TREE);
@@ -6636,7 +6634,8 @@ add_decl_expr (location_t loc, enum decl_context 
decl_context, tree type,
   pushdecl (decl);
   DECL_ARTIFICIAL (decl) = 1;
   add_stmt (build_stmt (DECL_SOURCE_LOCATION (decl), DECL_EXPR, decl));
-  TYPE_NAME (type) = decl;
+  if (set_name_p)
+TYPE_NAME (type) = decl;
 
   if (bind)
 {
@@ -7635,7 +7634,12 @@ grokdeclarator (const struct c_declarator *declarator,
   type has a name/declaration of it's own, but special attention
   is required if the type is anonymous. */
if (!TYPE_NAME (type) && c_type_variably_modified_p (type))
- add_decl_expr (loc, decl_context, type, expr);
+ {
+   bool bind_p = decl_context == TYPENAME
+ || decl_context == FIELD
+ || decl_context == PARM;
+   add_decl_expr (loc, type, bind_p ? expr : NULL, true);
+ }
 
type = c_build_pointer_type (type);
 
@@ -7900,7 +7904,12 @@ grokdeclarator (const struct c_declarator *declarator,
 
/* The pointed-to type may need a decl expr (see above).  */
if (!TYPE_NAME (type) && c_type_variably_modified_p (type))
- add_decl_expr (loc, decl_context, type, expr);
+ {
+   bool bind_p = decl_context == TYPENAME
+ || decl_context == FIELD
+ || decl_context == PARM;
+   add_decl_expr (loc, type, bind_p ? expr : NULL, true);
+ }
 
type = c_build_pointer_type (type);
type_quals = array_ptr_quals;
@@ -9257,7 +9266,8 @@ is_flexible_array_member_p (bool is_last_field,
 
 tree
 finish_struct (location_t loc, tree t, tree fieldlist, tree attributes,
-  class c_struct_parse_info *enclosing_struct_parse_info)
+  class c_struct_parse_info *enclosing_struct_parse_info,
+  tree *expr)
 {
   tree x;
   bool toplevel = file_scope == current_scope;
@@ -9595,6 +9605,13 @@ finish_struct (location_t loc, tree t, tree fieldlist, 
tree attributes,
 
   finish_incomplete_vars (incomplete_vars, toplevel);
 
+  /* Make sure a DECL_EXPR is created for structs with VLA members.
+ Because we do not know the context, we always pass expr
+ to force creation of a BIND_EXPR which is required in some
+ contexts.  */
+  if (c_type_variably_modified_p (t))
+add_decl_expr (loc, t, expr, false);
+
   if (warn_cxx_compat)
 warn_cxx_compat_finish_struct (fie

[C PATCH] Fix regression causing ICE for structs with VLAs [PR 112488]

2023-12-08 Thread Martin Uecker


This fixes a regression caused by my previous VM fixes.


Fix regression causing ICE for structs with VLAs [PR 112488]

A previous patch the fixed several ICEs related to size expressions
of VM types (PR c/70418, ...) caused a regression for structs where
a DECL_EXPR is not generated anymore although reqired.  We now call
add_decl_expr introduced by the previous patch from finish_struct.
The function gets a new argument to not set the TYPE_NAME for the
type to the DECL_EXPR in this spicitic case.

PR c/112488

gcc/c
* c-decl.cc (add_decl_expr): Add argument.
(finish_struct): Create DECL_EXPR.
(c_simulate_record_decl): Adapt.
* c-parser.cc (c_parser_struct_or_union_specifier): Call
finish_struct with expression for VLA sizes.
* c-tree.h (finish_struct): Add argument.

gcc/testsuite
* gcc.dg/pr112488-1.c: New test.
* gcc.dg/pr112488-2.c: New test.
* gcc.dg/pr112898.c: New test.
* gcc.misc-tests/gcov-pr85350.c: Adapt.
---
 gcc/c/c-decl.cc | 22 +++--
 gcc/c/c-parser.cc   |  2 +-
 gcc/c/c-tree.h  |  3 ++-
 gcc/testsuite/gcc.dg/pr112488-1.c   | 14 +
 gcc/testsuite/gcc.dg/pr112488-2.c   | 13 
 gcc/testsuite/gcc.dg/pr112898.c |  9 +
 gcc/testsuite/gcc.misc-tests/gcov-pr85350.c |  2 +-
 7 files changed, 56 insertions(+), 9 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/pr112488-1.c
 create mode 100644 gcc/testsuite/gcc.dg/pr112488-2.c
 create mode 100644 gcc/testsuite/gcc.dg/pr112898.c

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 92c83e1bf10..0b500c19e70 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -6619,7 +6619,7 @@ smallest_type_quals_location (const location_t *locations,
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 *expr, bool set_name_p)
 {
   tree bind = NULL_TREE;
   if (decl_context == TYPENAME || decl_context == PARM
@@ -6636,7 +6636,8 @@ add_decl_expr (location_t loc, enum decl_context 
decl_context, tree type,
   pushdecl (decl);
   DECL_ARTIFICIAL (decl) = 1;
   add_stmt (build_stmt (DECL_SOURCE_LOCATION (decl), DECL_EXPR, decl));
-  TYPE_NAME (type) = decl;
+  if (set_name_p)
+TYPE_NAME (type) = decl;
 
   if (bind)
 {
@@ -7635,7 +7636,7 @@ grokdeclarator (const struct c_declarator *declarator,
   type has a name/declaration of it's own, but special attention
   is required if the type is anonymous. */
if (!TYPE_NAME (type) && c_type_variably_modified_p (type))
- add_decl_expr (loc, decl_context, type, expr);
+ add_decl_expr (loc, decl_context, type, expr, true);
 
type = c_build_pointer_type (type);
 
@@ -7900,7 +7901,7 @@ grokdeclarator (const struct c_declarator *declarator,
 
/* The pointed-to type may need a decl expr (see above).  */
if (!TYPE_NAME (type) && c_type_variably_modified_p (type))
- add_decl_expr (loc, decl_context, type, expr);
+ add_decl_expr (loc, decl_context, type, expr, true);
 
type = c_build_pointer_type (type);
type_quals = array_ptr_quals;
@@ -9257,7 +9258,8 @@ is_flexible_array_member_p (bool is_last_field,
 
 tree
 finish_struct (location_t loc, tree t, tree fieldlist, tree attributes,
-  class c_struct_parse_info *enclosing_struct_parse_info)
+  class c_struct_parse_info *enclosing_struct_parse_info,
+  tree *expr)
 {
   tree x;
   bool toplevel = file_scope == current_scope;
@@ -9595,6 +9597,13 @@ finish_struct (location_t loc, tree t, tree fieldlist, 
tree attributes,
 
   finish_incomplete_vars (incomplete_vars, toplevel);
 
+  /* Make sure a DECL_EXPR is created for structs with VLA members.
+ Because we do not know the context, we use decl_context TYPENAME
+ here to force creation of a BIND_EXPR which is required in some
+ contexts.  */
+  if (c_type_variably_modified_p (t))
+add_decl_expr (loc, TYPENAME, t, expr, false);
+
   if (warn_cxx_compat)
 warn_cxx_compat_finish_struct (fieldlist, TREE_CODE (t), loc);
 
@@ -10191,7 +10200,8 @@ c_simulate_record_decl (location_t loc, const char 
*name,
DECL_CHAIN (fields[i - 1]) = fields[i];
 }
 
-  finish_struct (loc, type, fields[0], NULL_TREE, struct_info);
+  tree expr = NULL_TREE;
+  finish_struct (loc, type, fields[0], NULL_TREE, struct_info, &expr);
 
   tree decl = build_decl (loc, TYPE_DECL, ident, type);
   set_underlying_type (decl);
diff --git a/gcc/c/c-parser.cc b/gcc/c/c-parser.cc
index df9a07928b5..dcb6c21da41 100644
--- a/gcc/c/c-parser.cc
+++ b/gcc/c/c-parser.cc
@@ -4087,7 +4087,7 @@ c_parser_struct_or_union_specifier (c_parser *parser)
   ret.spec = finish_struct (struct_loc, type, nrev

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

2023-12-06 Thread Martin Uecker
Am Mittwoch, dem 06.12.2023 um 16:01 +0100 schrieb Jakub Jelinek:
> On Wed, Dec 06, 2023 at 03:56:10PM +0100, Martin Uecker wrote:
> > > That would be my preference because then the allocation size is
> > > correct and it is purely a style warning.
> > > It doesn't follow how the warning is described:
> > > "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"
> > > when the size is certainly sufficient.
> > 
> > The C standard defines the semantics of to allocate space 
> > of 'nmemb' objects of size 'size', so I would say
> > the warning and its description are correct because
> > if you call calloc with '1' as size argument but
> > the object size is larger then you specify an 
> > insufficient size for the object given the semantical
> > description of calloc in the standard.
> 
> 1 is sizeof (char), so you ask for an array of sizeof (struct ...)
> chars and store the struct into it.

If you use

char *p = calloc(sizeof(struct foo), 1);

it does not warn.

> 
> > > We have the -Wmemset-transposed-args warning, couldn't we
> > > have a similar one for calloc, and perhaps do it solely in
> > > the case where one uses sizeof of the type used in the cast
> > > pointer?
> > > So warn for
> > > (struct S *) calloc (sizeof (struct S), 1)
> > > or
> > > (struct S *) calloc (sizeof (struct S), n)
> > > but not for
> > > (struct S *) calloc (4, 15)
> > > or
> > > (struct S *) calloc (sizeof (struct T), 1)
> > > or similar?  Of course check for compatible types of TYPE_MAIN_VARIANTs.
> > 
> > Yes, although in contrast to -Wmeset-transposed-args
> > this would be considered a "style" option which then
> > nobody would activate.  And if we put it into -Wextra
> > then we have the same situation as today.
> 
> Well, the significant difference would be that users would
> know that they got the size for the allocation right, just
> that a coding style says it is better to put the type's size
> as the second argument rather than first, and they could disable
> that warning separately from -Walloc-size and still get warnings
> on (struct S *) calloc (1, 1) or (struct S *) malloc (3) if
> sizeof (struct S) is 24...

Ok. 

Note that another limitation of the current version is that it
does not warn for

... = (struct S*) calloc (...)

with the cast (which is non-idiomatic in C).  This is also
something I would like to address in the future and would be
more important for the C++ version.  But for this case it
should probably use the type of the cast and the warning
needs to be added somewhere else in the FE.


Martin



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

2023-12-06 Thread Martin Uecker
Am Mittwoch, dem 06.12.2023 um 15:21 +0100 schrieb Jakub Jelinek:
> On Wed, Dec 06, 2023 at 02:34:10PM +0100, Martin Uecker wrote:
> > > Further I think
> > > "size less than or equal to the size requested"
> > > is quite ambiguous in the calloc case, isn't the size requested in the
> > > calloc case actually nmemb * size rather than just size?
> > 
> > This is unclear but it can be understood this way.
> > This was also Joseph's point.
> > 
> > I am happy to submit a patch that changes the code so
> > that the swapped arguments to calloc do not cause a warning
> > anymore.
> 
> That would be my preference because then the allocation size is
> correct and it is purely a style warning.
> It doesn't follow how the warning is described:
> "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"
> when the size is certainly sufficient.

The C standard defines the semantics of to allocate space 
of 'nmemb' objects of size 'size', so I would say
the warning and its description are correct because
if you call calloc with '1' as size argument but
the object size is larger then you specify an 
insufficient size for the object given the semantical
description of calloc in the standard.

If this does not affect alignment, then  this should 
not matter, but it is still not really correct. 
> 
> But wonder what others think about it.
> 
> BTW, shouldn't the warning be for C++ as well?  Sure, I know,
> people use operator new more often, but still, the 
> allocators are used in there as well.

We should, but it I am not familiar with the C++ FE.

> 
> We have the -Wmemset-transposed-args warning, couldn't we
> have a similar one for calloc, and perhaps do it solely in
> the case where one uses sizeof of the type used in the cast
> pointer?
> So warn for
> (struct S *) calloc (sizeof (struct S), 1)
> or
> (struct S *) calloc (sizeof (struct S), n)
> but not for
> (struct S *) calloc (4, 15)
> or
> (struct S *) calloc (sizeof (struct T), 1)
> or similar?  Of course check for compatible types of TYPE_MAIN_VARIANTs.
> 
>   Jakub

Yes, although in contrast to -Wmeset-transposed-args
this would be considered a "style" option which then
nobody would activate.  And if we put it into -Wextra
then we have the same situation as today.

Martin





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

2023-12-06 Thread Martin Uecker
Am Mittwoch, dem 06.12.2023 um 14:34 +0100 schrieb Martin Uecker:
> Am Mittwoch, dem 06.12.2023 um 13:57 +0100 schrieb Jakub Jelinek:
> > On Wed, Dec 06, 2023 at 08:31:12PM +0800, Xi Ruoyao wrote:
> > > On Wed, 2023-12-06 at 13:24 +0100, Jakub Jelinek wrote:
> > > > I wonder if this part isn't too pedantic or more of a code style.
> > > > Some packages fail to build with this with -Werror because they do
> > > >   struct S *p = calloc (sizeof (struct S), 1);
> > > > or similar.  It is true that calloc arguments are documented to be
> > > > nmemb, size, but given sufficient alignment (which is not really 
> > > > different
> > > > between either order of arguments) isn't it completely valid to allocate
> > > > char array with sizeof (struct S) elements and then store a struct S 
> > > > object
> > > > into it?
> > > 
> > > In PR112364 Martin Uecker has pointed out the alignment may be different
> > > with the different order of arguments, per C23 (N2293).  With earlier
> > > versions of the standard some people believe the alignment should not be
> > > different, while the other people disagree (as the text is not very
> > > clear).
> > 
> > I can understand implementations which use smaller alignment based on
> > allocation size, but are there any which consider for that just the second
> > calloc argument rather than the product of both arguments?
> 
> Not that I know of.  
> 
> > I think they'd quickly break a lot of real-world code.
> 
> There are quite a few projects which use calloc with swapped
> arguments.
> 
> > Further I think
> > "size less than or equal to the size requested"
> > is quite ambiguous in the calloc case, isn't the size requested in the
> > calloc case actually nmemb * size rather than just size?
> 
> This is unclear but it can be understood this way.
> This was also Joseph's point.
> 
> I am happy to submit a patch that changes the code so
> that the swapped arguments to calloc do not cause a warning
> anymore.
> 
> On the other hand, the only feedback I got so far was
> from people who were then happy to get this warning.

Note that it is now -Wextra.  



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

2023-12-06 Thread Martin Uecker
Am Mittwoch, dem 06.12.2023 um 13:57 +0100 schrieb Jakub Jelinek:
> On Wed, Dec 06, 2023 at 08:31:12PM +0800, Xi Ruoyao wrote:
> > On Wed, 2023-12-06 at 13:24 +0100, Jakub Jelinek wrote:
> > > I wonder if this part isn't too pedantic or more of a code style.
> > > Some packages fail to build with this with -Werror because they do
> > >   struct S *p = calloc (sizeof (struct S), 1);
> > > or similar.  It is true that calloc arguments are documented to be
> > > nmemb, size, but given sufficient alignment (which is not really different
> > > between either order of arguments) isn't it completely valid to allocate
> > > char array with sizeof (struct S) elements and then store a struct S 
> > > object
> > > into it?
> > 
> > In PR112364 Martin Uecker has pointed out the alignment may be different
> > with the different order of arguments, per C23 (N2293).  With earlier
> > versions of the standard some people believe the alignment should not be
> > different, while the other people disagree (as the text is not very
> > clear).
> 
> I can understand implementations which use smaller alignment based on
> allocation size, but are there any which consider for that just the second
> calloc argument rather than the product of both arguments?

Not that I know of.  

> I think they'd quickly break a lot of real-world code.

There are quite a few projects which use calloc with swapped
arguments.

> Further I think
> "size less than or equal to the size requested"
> is quite ambiguous in the calloc case, isn't the size requested in the
> calloc case actually nmemb * size rather than just size?

This is unclear but it can be understood this way.
This was also Joseph's point.

I am happy to submit a patch that changes the code so
that the swapped arguments to calloc do not cause a warning
anymore.

On the other hand, the only feedback I got so far was
from people who were then happy to get this warning.

Martin






Re: [gcc15] nested functions in C

2023-12-05 Thread Martin Uecker
Am Dienstag, dem 05.12.2023 um 21:08 + schrieb Joseph Myers:
> On Mon, 4 Dec 2023, Martin Uecker wrote:
> 
> > > The key feature of lambdas (which failed to make it into C23) for this 
> > > purpose is that you can't convert them to function pointers, which 
> > > eliminates any need for trampolines.
> > 
> > And also makes them useful only for template-like macro programming,
> > but not much else. So my understanding was that this needs to be 
> > addressed at some point. 
> 
> Where "addressed" probably means some kind of callable object that stores 
> more than just a function pointer in order to be able to encapsulate both 
> the code address of a lambda and the context it needs to receive 
> implicitly.  So still not needing trampolines.

Yes, a wide function pointer type similar to C++'s std::function.

This would also be a way to eliminate the need for trampolines
for GCC's nested function.

Martin
> 



Re: [gcc15] nested functions in C

2023-12-04 Thread Martin Uecker
Am Montag, dem 04.12.2023 um 19:51 +0100 schrieb Jakub Jelinek:
> On Mon, Dec 04, 2023 at 01:27:32PM -0500, Siddhesh Poyarekar wrote:
> > [Branching this into a separate conversation to avoid derailing the patch,
> > which isn't directly related]
> > 
> > On 2023-12-04 12:21, Martin Uecker wrote:
> > > I do not really agree with that.  Nested functions can substantially
> > > improve code quality and in C can avoid type unsafe use of
> > > void* pointers in callbacks. The code is often much better with
> > > nested functions than without.  Nested functions and lambdas
> > > (i.e. anonymous nested functions) are used in many languages
> > > because they make code better and GNU's nested function are no
> > > exception.
> > > 
> > > So I disagree with the idea that discouraging nested functions leads
> > > to better code - I think the exact opposite is true.
> > 
> > I would argue that GNU's nested functions *are* an exception because they're
> > like feathers stuck on a pig to try and make it fly; I think a significant
> > specification effort is required to actually make it a cleanly usable
> > feature.
> 
> Why?  The syntax doesn't seem to be something unexpected, and as C doesn't
> have lambdas, one can use the nested functions instead.
> The only problem is if you need to pass function pointers somewhere else
> (and target doesn't have function descriptors or something similar), if it
> is only done to make code more readable compared to say use of macros, I
> think the nested functions are better, one doesn't have to worry about
> multiple evaluations of argument side-effects etc.  And if everything is
> inlined and SRA optimized, there is no extra cost.
> The problem of passing it as a function pointer to other functions is
> common with C++, only lambdas which don't capture anything actually can be
> convertible to function pointer, for anything else you need a template and
> instantiate it for a particular lambda (which is something you can't do in
> C).

In C++ you can erase the type with std::function.  C is missing a 
function pointer type which can encapsulate the static chain on
all archs (not only for nested functions, also for language 
interoperability).

Martin

> 



Re: [gcc15] nested functions in C

2023-12-04 Thread Martin Uecker
Am Montag, dem 04.12.2023 um 15:35 -0500 schrieb Siddhesh Poyarekar:
> On 2023-12-04 13:48, Martin Uecker wrote:
> > > I empathize with Jakub's stated use case though of keeping the C
> > > frontend support for testing purposes, but that could easily be done
> > > behind a flag, or by putting nested C func deprecation behind a flag.
> > 
> > I am relatively sure C will get some form of nested functions.
> > Maybe as anonymous nested functions, i.e. lambdas, but I do
> > not see a fundamental difference here (I personally like naming
> > things for clarity, so i prefer named nested functions)
> 
> If (assuming from them being called lambdas) they are primarily for 
> small functions without side-effects then it's already a significantly 
> stronger specification than what we have right now with C nested 
> functions.  That would end up enforcing what you demonstrate as the good 
> way to use nested functions.

The proposal we have seen for C23 (which was not accepted into
C23 mostly due to timing and lack of implementation experience)
were similar to C++'s lambdas and did not have any such restriction.

> 
> I suppose minimal, contained side-effects (such as atomically updating a 
> structure) may also constitute sound design, but that should be made 
> explicit in the language.

Updating some variable is useful for example for contractions, e.g.
summing over a certain range of values in an array, etc.

> 
> > > I don't disagree for cases like -Warray-bounds,
> > > but for warnings/errors that are more deterministic in nature (like
> > > -Werror=trampolines), they're going to point at actual problems and
> > > larger projects and distributions will usually prefer to at least track
> > > them, if not actually fix them.  For Fedora we tend to provide macro
> > > overrides for packages that need to explicitly disable a security
> > > related flag.
> > 
> > In projects such as mine, this will lead to a lot of code
> > transformations as indicated above, i.e. much worse code.
> > 
> > One could get away with it, since nested functions are rarely
> > used, but I think this is bad, because a lot of code would
> > improve if it used them.
> 
> If nested functions are eventually going to make it into the C standard 
> then effort is probably better spent in porting the C nested functions 
> to use descriptors instead of executable stacks or heaps.

I submitted a patch for this a long time ago which was based
on the code for Ada that uses a bit in the pointer to differentiate
between conventional pointers and descriptors.

I would now prefer an approach that uses a qualifier on the
function type to indicate that the static chain has to be
set. A pointer to such a qualified function would a descriptor
that consists of the address and the value for the static chain.

This would be useful for many things.

Martin







Re: [gcc15] nested functions in C

2023-12-04 Thread Martin Uecker
Am Montag, dem 04.12.2023 um 21:33 + schrieb Joseph Myers:
> On Mon, 4 Dec 2023, Siddhesh Poyarekar wrote:
> 
> > On 2023-12-04 13:48, Martin Uecker wrote:
> > > > I empathize with Jakub's stated use case though of keeping the C
> > > > frontend support for testing purposes, but that could easily be done
> > > > behind a flag, or by putting nested C func deprecation behind a flag.
> > > 
> > > I am relatively sure C will get some form of nested functions.
> > > Maybe as anonymous nested functions, i.e. lambdas, but I do
> > > not see a fundamental difference here (I personally like naming
> > > things for clarity, so i prefer named nested functions)
> > 
> > If (assuming from them being called lambdas) they are primarily for small
> > functions without side-effects then it's already a significantly stronger
> > specification than what we have right now with C nested functions.  That 
> > would
> > end up enforcing what you demonstrate as the good way to use nested 
> > functions.
> 
> The key feature of lambdas (which failed to make it into C23) for this 
> purpose is that you can't convert them to function pointers, which 
> eliminates any need for trampolines.

And also makes them useful only for template-like macro programming,
but not much else. So my understanding was that this needs to be 
addressed at some point. 

Martin

> 



Re: [gcc15] nested functions in C

2023-12-04 Thread Martin Uecker
Am Montag, dem 04.12.2023 um 13:27 -0500 schrieb Siddhesh Poyarekar:
> [Branching this into a separate conversation to avoid derailing the 
> patch, which isn't directly related]
> 
> On 2023-12-04 12:21, Martin Uecker wrote:
> > I do not really agree with that.  Nested functions can substantially
> > improve code quality and in C can avoid type unsafe use of
> > void* pointers in callbacks. The code is often much better with
> > nested functions than without.  Nested functions and lambdas
> > (i.e. anonymous nested functions) are used in many languages
> > because they make code better and GNU's nested function are no
> > exception.
> > 
> > So I disagree with the idea that discouraging nested functions leads
> > to better code - I think the exact opposite is true.
> 
> I would argue that GNU's nested functions *are* an exception because 
> they're like feathers stuck on a pig to try and make it fly; I think a 
> significant specification effort is required to actually make it a 
> cleanly usable feature.  It *may* be possible to implement patterns that 
> use C nested functions well enough *and* result in readable code, but 
> IMO it is easier to write clunky and unmaintainable code with it.

I use them in my code a lot and I think they improve
code quality.  For example:

int foo_find(int N, struct foo in_array[N], const char* *key)
{
  bool cond(struct foo* x)
  {
return 0 == strcmp(x->name, key); 
  }
  return find(N, in_array, cond);
}

is a lot cleaner and safer than what you need to write
without nested functions:

struct foo_find {
  const char* name;
}; 

int foo_cond(void *vdata, struct foo* a)
{
  struct foo *key = data;
  return 0 == strcmp(x->name, key->name);  
}

void foo_sort(int N, struct foo in_array[N], const char* key)
{
  struct foo_find data = { key };
  sort(N, in_array, foo_cond, &data);
}

and this is a toy example, the improvement gets more 
substantial with more complicated logic.

> 
> I empathize with Jakub's stated use case though of keeping the C 
> frontend support for testing purposes, but that could easily be done 
> behind a flag, or by putting nested C func deprecation behind a flag.

I am relatively sure C will get some form of nested functions.
Maybe as anonymous nested functions, i.e. lambdas, but I do
not see a fundamental difference here (I personally like naming
things for clarity, so i prefer named nested functions)

> > I am generally wary of mitigations that may make exploitation of
> > buffer overflows a bit harder  while increasing the likelihood
> > of buffer overflows by reducing type safety and/or code quality.
> > 
> > But I would agree that trampolines are generally problematic. A
> > better strategy would be wide function pointer type (as in Apple'
> > Blocks extension). Alternatively, an explicit way to obtain the
> > static chain for a nested function which could be used with
> > __builtin_call_with_static_chain  could also work.
> > 
> > But in any case, I think it diminishes the value of -fhardening
> > it if requires source code changes, because then it is not as easy
> > to simply turn it on in larger projects / distributitions.
> 
> I suppose you mean source code changes even in correct code just to 
> comply with the flag?  

Yes

> I don't disagree for cases like -Warray-bounds, 
> but for warnings/errors that are more deterministic in nature (like 
> -Werror=trampolines), they're going to point at actual problems and 
> larger projects and distributions will usually prefer to at least track 
> them, if not actually fix them.  For Fedora we tend to provide macro 
> overrides for packages that need to explicitly disable a security 
> related flag.

In projects such as mine, this will lead to a lot of code
transformations as indicated above, i.e. much worse code. 

One could get away with it, since nested functions are rarely
used, but I think this is bad, because a lot of code would
improve if it used them.

Martin

> 
> Thanks,
> Sid



Re: [PATCH] gcc: Disallow trampolines when -fhardened

2023-12-04 Thread Martin Uecker
Am Montag, dem 04.12.2023 um 11:46 -0500 schrieb Siddhesh Poyarekar:
> On 2023-12-04 11:39, Andreas Schwab wrote:
> > On Dez 04 2023, Siddhesh Poyarekar wrote:
> > 
> > > For hardened code in C, I think we really should look to step away from
> > > nested functions instead of adding ways to continue supporting it. There's
> > > probably a larger conversation to be had about the utility of nested
> > > functions in general for C (and whether this GCC extension should be
> > > deprecated altogether in future), but I feel like the -fhardened subset
> > > gives us the opportunity to enforce at least a safe subset for now,
> > > possibly extending it in future.
> > 
> > Nested functions by itself don't need a trampoline, only if the address
> > of it is passed outside the containing function's scope (as a callback,
> > for example).
> 
> Yes, that's why I said that the conversation about deprecating the C 
> nested functions extension is a broader one (and hence for gcc 15) that 
> will likely involve the question of whether dropping the extension 
> altogether gives any benefit or if dropping support for on-stack 
> trampolines is sufficient.  On-heap trampolines are maybe slightly 
> better in that they don't need an executable stack, but defaulting to 
> on-heap trampolines for -fhardened seems like a lost opportunity to 
> enforce better user code.

I do not really agree with that.  Nested functions can substantially
improve code quality and in C can avoid type unsafe use of
void* pointers in callbacks. The code is often much better with
nested functions than without.  Nested functions and lambdas
(i.e. anonymous nested functions) are used in many languages
because they make code better and GNU's nested function are no
exception.

So I disagree with the idea that discouraging nested functions leads 
to better code - I think the exact opposite is true.

I am generally wary of mitigations that may make exploitation of
buffer overflows a bit harder  while increasing the likelihood
of buffer overflows by reducing type safety and/or code quality.

But I would agree that trampolines are generally problematic. A
better strategy would be wide function pointer type (as in Apple'
Blocks extension). Alternatively, an explicit way to obtain the
static chain for a nested function which could be used with 
__builtin_call_with_static_chain  could also work.

But in any case, I think it diminishes the value of -fhardening 
it if requires source code changes, because then it is not as easy
to simply turn it on in larger projects / distributitions. 

Martin



> 
> Thanks,
> Sid



Re: [PATCH] gcc: Disallow trampolines when -fhardened

2023-12-02 Thread Martin Uecker


> Bootstrapped/regtested on x86_64-pc-linux-gnu, ok for trunk?
> 
> -- >8 --
> It came up that a good hardening strategy is to disable trampolines
> which may require executable stack.  Therefore the following patch
> adds -Werror=trampolines to -fhardened.

This would add a warning about specific code (where it is then
unclear whether rewriting it is feasible or even an improvement),
which seems different to all the other flags -fhardening has
now.

GCC now has an option to allocate trampolines on the heap,
which would seem to be a better fit.  On the other hand,
it does not work with longjmp which may be a limitation.

Martin


> 
> gcc/ChangeLog:
> 
>   * common.opt (Wtrampolines): Enable by -fhardened.
>   * doc/invoke.texi: Reflect that -fhardened enables -Werror=trampolines.
>   * opts.cc (print_help_hardened): Add -Werror=trampolines.
>   * toplev.cc (process_options): Enable -Werror=trampolines for
>   -fhardened.
> 
> gcc/testsuite/ChangeLog:
> 
>   * gcc.dg/fhardened-1.c: New test.
>   * gcc.dg/fhardened-2.c: New test.
>   * gcc.dg/fhardened-3.c: New test.
>   * gcc.dg/fhardened-4.c: New test.
>   * gcc.dg/fhardened-5.c: New test.
> ---
>  gcc/common.opt |  2 +-
>  gcc/doc/invoke.texi|  1 +
>  gcc/opts.cc|  1 +
>  gcc/testsuite/gcc.dg/fhardened-1.c | 27 +++
>  gcc/testsuite/gcc.dg/fhardened-2.c | 25 +
>  gcc/testsuite/gcc.dg/fhardened-3.c | 25 +
>  gcc/testsuite/gcc.dg/fhardened-4.c | 25 +
>  gcc/testsuite/gcc.dg/fhardened-5.c | 27 +++
>  gcc/toplev.cc  |  8 +++-
>  9 files changed, 139 insertions(+), 2 deletions(-)
>  create mode 100644 gcc/testsuite/gcc.dg/fhardened-1.c
>  create mode 100644 gcc/testsuite/gcc.dg/fhardened-2.c
>  create mode 100644 gcc/testsuite/gcc.dg/fhardened-3.c
>  create mode 100644 gcc/testsuite/gcc.dg/fhardened-4.c
>  create mode 100644 gcc/testsuite/gcc.dg/fhardened-5.c
> 
> diff --git a/gcc/common.opt b/gcc/common.opt
> index 161a035d736..9b09c7cb3df 100644
> --- a/gcc/common.opt
> +++ b/gcc/common.opt
> @@ -807,7 +807,7 @@ Common Var(warn_system_headers) Warning
>  Do not suppress warnings from system headers.
>  
>  Wtrampolines
> -Common Var(warn_trampolines) Warning
> +Common Var(warn_trampolines) Warning EnabledBy(fhardened)
>  Warn whenever a trampoline is generated.
>  
>  Wtrivial-auto-var-init
> diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
> index 2fab4c5d71f..c1664a1a0f1 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -17745,6 +17745,7 @@ may change between major releases of GCC, but are 
> currently:
>  -fstack-protector-strong
>  -fstack-clash-protection
>  -fcf-protection=full @r{(x86 GNU/Linux only)}
> +-Werror=trampolines
>  }
>  
>  The list of options enabled by @option{-fhardened} can be generated using
> diff --git a/gcc/opts.cc b/gcc/opts.cc
> index 5d5efaf1b9e..aa062b87cef 100644
> --- a/gcc/opts.cc
> +++ b/gcc/opts.cc
> @@ -2517,6 +2517,7 @@ print_help_hardened ()
>printf ("  %s\n", "-fstack-protector-strong");
>printf ("  %s\n", "-fstack-clash-protection");
>printf ("  %s\n", "-fcf-protection=full");
> +  printf ("  %s\n", "-Werror=trampolines");
>putchar ('\n');
>  }
>  
> diff --git a/gcc/testsuite/gcc.dg/fhardened-1.c 
> b/gcc/testsuite/gcc.dg/fhardened-1.c
> new file mode 100644
> index 000..8710959b6f1
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/fhardened-1.c
> @@ -0,0 +1,27 @@
> +/* { dg-do compile { target *-*-linux* *-*-gnu* } } */
> +/* { dg-require-effective-target trampolines } */
> +/* { dg-options "-fhardened -O" } */
> +
> +static void
> +baz (int (*bar) (void))
> +{
> +  bar ();
> +}
> +
> +int
> +main (void)
> +{
> +  int a = 6;
> +
> +  int
> +  bar (void) // { dg-error "trampoline" }
> +  {
> +return a;
> +  }
> +
> +  baz (bar);
> +
> +  return 0;
> +}
> +
> +/* { dg-prune-output "some warnings being treated as errors" } */
> diff --git a/gcc/testsuite/gcc.dg/fhardened-2.c 
> b/gcc/testsuite/gcc.dg/fhardened-2.c
> new file mode 100644
> index 000..d47512aa47f
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/fhardened-2.c
> @@ -0,0 +1,25 @@
> +/* { dg-do compile { target *-*-linux* *-*-gnu* } } */
> +/* { dg-require-effective-target trampolines } */
> +/* { dg-options "-fhardened -O -Wno-trampolines" } */
> +
> +static void
> +baz (int (*bar) (void))
> +{
> +  bar ();
> +}
> +
> +int
> +main (void)
> +{
> +  int a = 6;
> +
> +  int
> +  bar (void) // { dg-bogus "trampoline" }
> +  {
> +return a;
> +  }
> +
> +  baz (bar);
> +
> +  return 0;
> +}
> diff --git a/gcc/testsuite/gcc.dg/fhardened-3.c 
> b/gcc/testsuite/gcc.dg/fhardened-3.c
> new file mode 100644
> index 000..cebae13d8be
> --- /dev/null
> +++ b/gcc/testsuite/gcc.dg/fhardened-3.c
> @@ -0,0 +1,25 @@
> +/* { dg-do compile { target *-*-linux* *-*-gnu* } } */

Re: [PATCH 3/4] c23: aliasing of compatible tagged types

2023-11-28 Thread Martin Uecker
Am Dienstag, dem 28.11.2023 um 10:47 + schrieb Richard Biener:
> On Tue, 28 Nov 2023, Joseph Myers wrote:
> 
> > On Sun, 26 Nov 2023, Martin Uecker wrote:
> > 
> 

> > > > I also think more rationale is needed for ignoring sizes like this.  Is 
> > > > it 
> > > > intended for e.g. making structs with flexible array members 
> > > > alias-compatible with similar structs with a fixed-size array?
> > > 
> > > The main reason are pointers to arrays:
> > > 
> > > struct foo { int (*x)[]; }
> > > struct foo { int (*x)[2]; };
> > > struct foo { int (*x)[1]; };
> > 
> > Thanks for the explanation.
> > 
> > I guess the cases involving flexible array members actually show up a bug 
> > in the standard rather than any kind of issue with this patch - the 
> > standard allows one structure ending with a flexible array member, and 
> > another ending with a fixed-size array, to be compatible (and in different 
> > translation units allowed that even before C23), but there is also clear 
> > text in the standard showing it's not intended to require the layout to be 
> > consistent (the fixed-size and flexible arrays might have different 
> > offsets), and what you'd actually get with an assignment or conditional 
> > expression mixing such structures certainly isn't clearly specified.  
> > Maybe the right resolution for that issue with the standard would be to 
> > make that particular case incompatible, but it would need to be raised as 
> > an issue after C23 is out.
> 
> I think from a middle-end perspective it's desirable that accessing
> either of the foo with size 2 and 1 through a pointer of the type
> of the foo with unknown size is permissible from a TBAA view.  But
> it's not clear to me that accessing the foo with array size 2 via
> an lvalue of the type of foo with array size 1 is required to be
> supported (from a TBAA view).

This is the same from the C language side.  In principle, accesses 
to an object with effective type foo [2] using an lvalue of type 
foo [1] or vice versa are undefined behavior.

So a model based on equivalence classes loses some information. 

Martin



Re: [PATCH 3/4] c23: aliasing of compatible tagged types

2023-11-27 Thread Martin Uecker
Am Dienstag, dem 28.11.2023 um 01:00 + schrieb Joseph Myers:
> On Sun, 26 Nov 2023, Martin Uecker wrote:
> 
> > My understand is that it is used for aliasing analysis and also
> > checking of conversions.  TYPE_CANONICAL must be consistent with
> > the idea the middle-end has about type conversions.  But as long
> > as we do not give the same TYPE_CANONICAL to types the middle-end
> > thinks must be incompatible using its own type checking machinery,
> > it should be safe even for types the C standard thinks must be
> > incompatible for some reason.
> 
> And presumably also for types that definitely can't be assigned because 
> they have incompatible layout through the use of different array sizes - 
> since the front end won't generate such assignments, it would never matter 
> whether the middle end considers them valid without conversion or not?

Yes, for checking assignments we use the stricter language
semantics so we should never generate assignments for
structs with different fields offsets or sizes. (I will
check this again).

> > > I also think more rationale is needed for ignoring sizes like this.  Is 
> > > it 
> > > intended for e.g. making structs with flexible array members 
> > > alias-compatible with similar structs with a fixed-size array?
> > 
> > The main reason are pointers to arrays:
> > 
> > struct foo { int (*x)[]; }
> > struct foo { int (*x)[2]; };
> > struct foo { int (*x)[1]; };
> 
> Thanks for the explanation.
> 
> I guess the cases involving flexible array members actually show up a bug 
> in the standard rather than any kind of issue with this patch - the 
> standard allows one structure ending with a flexible array member, and 
> another ending with a fixed-size array, to be compatible (and in different 
> translation units allowed that even before C23), but there is also clear 
> text in the standard showing it's not intended to require the layout to be 
> consistent (the fixed-size and flexible arrays might have different 
> offsets), and what you'd actually get with an assignment or conditional 
> expression mixing such structures certainly isn't clearly specified.  

I agree, unfortunately it seems not well specified and we somehow missed 
that this now becomes more important.

> Maybe the right resolution for that issue with the standard would be to 
> make that particular case incompatible, but it would need to be raised as 
> an issue after C23 is out.

I think FAM may need further consideration from the standard
point of view for also other reasons.

My other issues I have now run into are structs with variably size
which I think do not work properly with LTO already today:

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



Martin

> 






Re: Ping: [PATCH] Fix PR112419

2023-11-27 Thread Martin Uecker
Am Montag, dem 27.11.2023 um 16:54 +0100 schrieb Martin Uecker:
> Am Montag, dem 27.11.2023 um 08:36 -0700 schrieb Jeff Law:
> > 
> > On 11/23/23 10:05, Hans-Peter Nilsson wrote:
> > > > From: Hans-Peter Nilsson 
> > > > Date: Thu, 16 Nov 2023 05:24:06 +0100
> > > > 
> > > > > From: Martin Uecker 
> > > > > Date: Tue, 07 Nov 2023 06:56:25 +0100
> > > > 
> > > > > Am Montag, dem 06.11.2023 um 21:01 -0700 schrieb Jeff Law:
> > > > > > 
> > > > > > On 11/6/23 20:58, Hans-Peter Nilsson wrote:
> > > > > > > This patch caused a testsuite regression: there's now an
> > > > > > > "excess error" failure for gcc.dg/Wnonnull-4.c for 32-bit
> > > > > > > targets (and 64-bit targets testing with a "-m32" option)
> > > > > > > after your r14-5115-g6e9ee44d96e5.  It's logged as PR112419.
> > > > > > It caused failures for just about every target ;(  Presumably it 
> > > > > > worked
> > > > > > on x86_64...
> > > > > 
> > > > > I do not think this is a true regression
> > > > > just a problem with the test on 32-bit which somehow surfaced
> > > > > due to the change.
> > > > > 
> > > > > The excess error is:
> > > > > 
> > > > > FAIL: gcc.dg/Wnonnull-4.c (test for excess errors)
> > > > > Excess errors:
> > > > > /home/tcwg-buildslave/workspace/tcwg_gnu_6/abe/snapshots/gcc.git~master/gcc/testsuite/gcc.dg/Wnonnull-4.c:144:3:
> > > > >  warning: 'fda_n_5' specified size 4294967256 exceeds maximum object 
> > > > > size
> > > > > 2147483647 [-Wstringop-overflow=]
> > > > > 
> > > > > I think the warning was suppressed before due to the other (nonnull)
> > > > > warning which I removed in this case.
> > > > > 
> > > > > I think the simple fix might be to to turn off -Wstringop-overflow.
> > > > 
> > > > No, that trigs many of the dg-warnings that are tested.
> > > > 
> > > > (I didn't pay attention to the actual warning messages and
> > > > tried to pursue that at first.)
> > > > 
> > > > Maybe think it's best to actually expect the warning, like
> > > > so.
> > > > 
> > > > Maintainers of 16-bit targets will have to address their
> > > > concerns separately.  For example, they may choose to not
> > > > run the test at all.
> > > > 
> > > > Ok to commit?
> > > > 
> > > > Subject: [PATCH] gcc.dg/Wnonnull-4.c: Handle new overflow warning for 
> > > > 32-bit targets [PR112419]
> > > > 
> > > > PR testsuite/112419
> > > > * gcc.dg/Wnonnull-4.c (test_fda_n_5): Expect warning for 
> > > > exceeding
> > > > maximum object size for 32-bit targets.
> > > > ---
> > > >   gcc/testsuite/gcc.dg/Wnonnull-4.c | 1 +
> > > >   1 file changed, 1 insertion(+)
> > > > 
> > > > diff --git a/gcc/testsuite/gcc.dg/Wnonnull-4.c 
> > > > b/gcc/testsuite/gcc.dg/Wnonnull-4.c
> > > > index 1f14fbba45df..d63e76da70a2 100644
> > > > --- a/gcc/testsuite/gcc.dg/Wnonnull-4.c
> > > > +++ b/gcc/testsuite/gcc.dg/Wnonnull-4.c
> > > > @@ -142,6 +142,7 @@ void test_fda_n_5 (int r_m1)
> > > > T (  1);  // { dg-bogus "argument 2 of variable length 
> > > > array 'double\\\[n]\\\[5]' is null but the corresponding bound argument 
> > > > 1 value is 1" }
> > > > T (  9);  // { dg-bogus "argument 2 of variable length 
> > > > array 'double\\\[n]\\\[5]' is null but the corresponding bound argument 
> > > > 1 value is 9" }
> > > > T (max);  // { dg-bogus "argument 2 of variable length 
> > > > array 'double\\\[n]\\\[5]' is null but the corresponding bound argument 
> > > > 1 value is \\d+" }
> > > > +// { dg-warning "size 4294967256 exceeds maximum object size" "" { 
> > > > target ilp32 } .-1 }
> > > >   }
> > Unfortunately I think we need to go back to the original issue that 
> > Martin (I think) dismissed.
> > 
> > Specifically, this is a regression.  It's very clear that prior to the 
> > patch in question there was no diagnostic about the size of the 
> > requested memory allocation and after the patch in question we get the 
> > "exceeds maximum object size" diagnostic.
> > 
> > Now one explanation could be that the diagnostic is warranted and it was 
> > a bug that the diagnostic hadn't been emitted prior to Martin's patch. 
> > In this case some kind of dg-blah is warranted, but I don't think anyone 
> > has made this argument.
> > 
> I believe the warning is correct but was suppressed before.
> 
> 
> My plan was to split up the test case in one which is for
> -Wstringop-overflow and one which is for -Wnonnull and then
> one could turn off the -Wstringop-overflow for the tests
> which are actually for -Wnonnull.  But adding the dg-blah
> would certainly be simpler.

Specifically, also with 13.2 if you suppress the warning which
I removed with -Wno-nonnull you will get the otherwise hidden
-Wstringop-overflow warning with -m32:

See here: https://godbolt.org/z/ev5GhMonq

The warning also seems correct to me, so I suggest to accept
the proposed patch. 

Martin






Re: Ping: [PATCH] Fix PR112419

2023-11-27 Thread Martin Uecker
Am Montag, dem 27.11.2023 um 08:36 -0700 schrieb Jeff Law:
> 
> On 11/23/23 10:05, Hans-Peter Nilsson wrote:
> > > From: Hans-Peter Nilsson 
> > > Date: Thu, 16 Nov 2023 05:24:06 +0100
> > > 
> > > > From: Martin Uecker 
> > > > Date: Tue, 07 Nov 2023 06:56:25 +0100
> > > 
> > > > Am Montag, dem 06.11.2023 um 21:01 -0700 schrieb Jeff Law:
> > > > > 
> > > > > On 11/6/23 20:58, Hans-Peter Nilsson wrote:
> > > > > > This patch caused a testsuite regression: there's now an
> > > > > > "excess error" failure for gcc.dg/Wnonnull-4.c for 32-bit
> > > > > > targets (and 64-bit targets testing with a "-m32" option)
> > > > > > after your r14-5115-g6e9ee44d96e5.  It's logged as PR112419.
> > > > > It caused failures for just about every target ;(  Presumably it 
> > > > > worked
> > > > > on x86_64...
> > > > 
> > > > I do not think this is a true regression
> > > > just a problem with the test on 32-bit which somehow surfaced
> > > > due to the change.
> > > > 
> > > > The excess error is:
> > > > 
> > > > FAIL: gcc.dg/Wnonnull-4.c (test for excess errors)
> > > > Excess errors:
> > > > /home/tcwg-buildslave/workspace/tcwg_gnu_6/abe/snapshots/gcc.git~master/gcc/testsuite/gcc.dg/Wnonnull-4.c:144:3:
> > > >  warning: 'fda_n_5' specified size 4294967256 exceeds maximum object 
> > > > size
> > > > 2147483647 [-Wstringop-overflow=]
> > > > 
> > > > I think the warning was suppressed before due to the other (nonnull)
> > > > warning which I removed in this case.
> > > > 
> > > > I think the simple fix might be to to turn off -Wstringop-overflow.
> > > 
> > > No, that trigs many of the dg-warnings that are tested.
> > > 
> > > (I didn't pay attention to the actual warning messages and
> > > tried to pursue that at first.)
> > > 
> > > Maybe think it's best to actually expect the warning, like
> > > so.
> > > 
> > > Maintainers of 16-bit targets will have to address their
> > > concerns separately.  For example, they may choose to not
> > > run the test at all.
> > > 
> > > Ok to commit?
> > > 
> > > Subject: [PATCH] gcc.dg/Wnonnull-4.c: Handle new overflow warning for 
> > > 32-bit targets [PR112419]
> > > 
> > >   PR testsuite/112419
> > >   * gcc.dg/Wnonnull-4.c (test_fda_n_5): Expect warning for exceeding
> > >   maximum object size for 32-bit targets.
> > > ---
> > >   gcc/testsuite/gcc.dg/Wnonnull-4.c | 1 +
> > >   1 file changed, 1 insertion(+)
> > > 
> > > diff --git a/gcc/testsuite/gcc.dg/Wnonnull-4.c 
> > > b/gcc/testsuite/gcc.dg/Wnonnull-4.c
> > > index 1f14fbba45df..d63e76da70a2 100644
> > > --- a/gcc/testsuite/gcc.dg/Wnonnull-4.c
> > > +++ b/gcc/testsuite/gcc.dg/Wnonnull-4.c
> > > @@ -142,6 +142,7 @@ void test_fda_n_5 (int r_m1)
> > > T (  1);  // { dg-bogus "argument 2 of variable length array 
> > > 'double\\\[n]\\\[5]' is null but the corresponding bound argument 1 value 
> > > is 1" }
> > > T (  9);  // { dg-bogus "argument 2 of variable length array 
> > > 'double\\\[n]\\\[5]' is null but the corresponding bound argument 1 value 
> > > is 9" }
> > > T (max);  // { dg-bogus "argument 2 of variable length array 
> > > 'double\\\[n]\\\[5]' is null but the corresponding bound argument 1 value 
> > > is \\d+" }
> > > +// { dg-warning "size 4294967256 exceeds maximum object size" "" { 
> > > target ilp32 } .-1 }
> > >   }
> Unfortunately I think we need to go back to the original issue that 
> Martin (I think) dismissed.
> 
> Specifically, this is a regression.  It's very clear that prior to the 
> patch in question there was no diagnostic about the size of the 
> requested memory allocation and after the patch in question we get the 
> "exceeds maximum object size" diagnostic.
> 
> Now one explanation could be that the diagnostic is warranted and it was 
> a bug that the diagnostic hadn't been emitted prior to Martin's patch. 
> In this case some kind of dg-blah is warranted, but I don't think anyone 
> has made this argument.
> 
I believe the warning is correct but was suppressed before.


My plan was to split up the test case in one which is for
-Wstringop-overflow and one which is for -Wnonnull and then
one could turn off the -Wstringop-overflow for the tests
which are actually for -Wnonnull.  But adding the dg-blah
would certainly be simpler.


Martin





[V4] [PATCH 3/4] c23: aliasing of compatible tagged types

2023-11-27 Thread Martin Uecker


(this mostly got an extended description and more
comments, also tests were reorganized)



c23: aliasing of compatible tagged types

Tell the backend which types are equivalent by setting
TYPE_CANONICAL to one struct in the set of equivalent
structs.  Structs are considered equivalent by ignoring
all sizes of arrays nested in types below field level.

The following two structs are incompatible and lvalues
with these types can be assumed not to alias:

 struct foo { int a[3]; };
 struct foo { int a[4]; };

The following two structs are also incompatible, but
will get the same TYPE_CANONICAL and it is then not
exploited that lvalues with those types can not alias:

 struct bar { int (*p)[3]; };
 struct bar { int (*p)[4]; };

The reason is that both are compatible to

 struct bar { int (*p)[]; };

and therefore are in the same equivalence class.  For
the same reason all enums with the same underyling type
are in the same equivalence class.  Tests are added
for the expected aliasing behavior with optimization.

gcc/c:
* c-decl.cc (c_struct_hasher): Hash stable for struct
types.
(c_struct_hasher::hash, c_struct_hasher::equal): New
functions.
(finish_struct): Set TYPE_CANONICAL to first struct in
equivalence class.
* c-objc-common.cc (c_get_alias_set): Let structs or
unions with variable size alias anything.
* c-tree.h (comptypes_equiv): New prototype.
* c-typeck.cc (comptypes_equiv): New function.
(comptypes_internal): Implement equivalence mode.
(tagged_types_tu_compatible): Implement equivalence mode.

gcc/testsuite:
* gcc.dg/c23-tag-2.c: Activate.
* gcc.dg/c23-tag-6.c: Activate.
* gcc.dg/c23-tag-alias-1.c: New test.
* gcc.dg/c23-tag-alias-2.c: New test.
* gcc.dg/gnu23-tag-alias-1.c: New test.
* gcc.dg/gnu23-tag-alias-2.c: New test.
* gcc.dg/gnu23-tag-alias-3.c: New test.
* gcc.dg/gnu23-tag-alias-4.c: New test.
* gcc.dg/gnu23-tag-alias-5.c: New test.
* gcc.dg/gnu23-tag-alias-6.c: New test.
* gcc.dg/gnu23-tag-alias-7.c: New test.
---
 gcc/c/c-decl.cc  |  51 ++-
 gcc/c/c-objc-common.cc   |   5 ++
 gcc/c/c-tree.h   |   1 +
 gcc/c/c-typeck.cc|  31 +++
 gcc/testsuite/gcc.dg/c23-tag-2.c |   2 +-
 gcc/testsuite/gcc.dg/c23-tag-5.c |   2 +-
 gcc/testsuite/gcc.dg/c23-tag-alias-1.c   |  49 +++
 gcc/testsuite/gcc.dg/c23-tag-alias-2.c   |  50 +++
 gcc/testsuite/gcc.dg/c23-tag-alias-3.c   |  32 +++
 gcc/testsuite/gcc.dg/c23-tag-alias-4.c   |  54 
 gcc/testsuite/gcc.dg/gnu23-tag-alias-1.c |  33 +++
 gcc/testsuite/gcc.dg/gnu23-tag-alias-2.c |  85 ++
 gcc/testsuite/gcc.dg/gnu23-tag-alias-3.c |  83 ++
 gcc/testsuite/gcc.dg/gnu23-tag-alias-4.c |  36 
 gcc/testsuite/gcc.dg/gnu23-tag-alias-5.c | 107 +++
 gcc/testsuite/gcc.dg/gnu23-tag-alias-6.c |  60 +
 gcc/testsuite/gcc.dg/gnu23-tag-alias-7.c |  93 
 17 files changed, 771 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-alias-1.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-alias-2.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-alias-3.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-alias-4.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-alias-1.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-alias-2.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-alias-3.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-alias-4.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-alias-5.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-alias-6.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-alias-7.c

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index bcc09ba479e..68cba131704 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -634,6 +634,36 @@ public:
   auto_vec typedefs_seen;
 };
 
+
+/* Hash table for structs and unions.  */
+struct c_struct_hasher : ggc_ptr_hash
+{
+  static hashval_t hash (tree t);
+  static bool equal (tree, tree);
+};
+
+/* Hash an RECORD OR UNION.  */
+hashval_t
+c_struct_hasher::hash (tree type)
+{
+  inchash::hash hstate;
+
+  hstate.add_int (TREE_CODE (type));
+  hstate.add_object (TYPE_NAME (type));
+
+  return hstate.end ();
+}
+
+/* Compare two RECORD or UNION types.  */
+bool
+c_struct_hasher::equal (tree t1,  tree t2)
+{
+  return comptypes_equiv_p (t1, t2);
+}
+
+/* All tagged typed so that TYPE_CANONICAL can be set correctly.  */
+static GTY (()) hash_table *c_struct_htab;
+
 /* 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;
@@ -8713,7 +8743,8 @@ parser_xref_tag (location_t loc, enum tree_code code, 
tree name,
   ref = lookup_tag (code, name, has_enu

[V4] [PATCH 4/4] c23: construct composite type for tagged types

2023-11-27 Thread Martin Uecker


(this patch was still not updated and needs more work, so
only included now for completeness) 


c23: construct composite type for tagged types

Support for constructing composite type for structs and unions
in C23.

gcc/c:
* c-typeck.cc (composite_type_internal): Adapted from
composite_type to support structs and unions.
(composite_type): New wrapper function.
(build_conditional_operator): Return composite type.

gcc/testsuite:
* gcc.dg/c23-tag-composite-1.c: New test.
* gcc.dg/c23-tag-composite-2.c: New test.
* gcc.dg/c23-tag-composite-3.c: New test.
* gcc.dg/c23-tag-composite-4.c: New test.
---
 gcc/c/c-typeck.cc  | 114 +
 gcc/testsuite/gcc.dg/c23-tag-composite-1.c |  26 +
 gcc/testsuite/gcc.dg/c23-tag-composite-2.c |  16 +++
 gcc/testsuite/gcc.dg/c23-tag-composite-3.c |  17 +++
 gcc/testsuite/gcc.dg/c23-tag-composite-4.c |  21 
 5 files changed, 176 insertions(+), 18 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-composite-1.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-composite-2.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-composite-3.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-composite-4.c

diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 00eb65dbcce..7901368c9fd 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -381,8 +381,15 @@ build_functype_attribute_variant (tree ntype, tree otype, 
tree attrs)
nonzero; if that isn't so, this may crash.  In particular, we
assume that qualifiers match.  */
 
+struct composite_cache {
+  tree t1;
+  tree t2;
+  tree composite;
+  struct composite_cache* next;
+};
+
 tree
-composite_type (tree t1, tree t2)
+composite_type_internal (tree t1, tree t2, struct composite_cache* cache)
 {
   enum tree_code code1;
   enum tree_code code2;
@@ -427,7 +434,8 @@ composite_type (tree t1, tree t2)
   {
tree pointed_to_1 = TREE_TYPE (t1);
tree pointed_to_2 = TREE_TYPE (t2);
-   tree target = composite_type (pointed_to_1, pointed_to_2);
+   tree target = composite_type_internal (pointed_to_1,
+  pointed_to_2, cache);
 t1 = build_pointer_type_for_mode (target, TYPE_MODE (t1), false);
t1 = build_type_attribute_variant (t1, attributes);
return qualify_type (t1, t2);
@@ -435,7 +443,8 @@ composite_type (tree t1, tree t2)
 
 case ARRAY_TYPE:
   {
-   tree elt = composite_type (TREE_TYPE (t1), TREE_TYPE (t2));
+   tree elt = composite_type_internal (TREE_TYPE (t1), TREE_TYPE (t2),
+   cache);
int quals;
tree unqual_elt;
tree d1 = TYPE_DOMAIN (t1);
@@ -503,9 +512,61 @@ composite_type (tree t1, tree t2)
return build_type_attribute_variant (t1, attributes);
   }
 
-case ENUMERAL_TYPE:
 case RECORD_TYPE:
 case UNION_TYPE:
+  if (flag_isoc23 && !comptypes_same_p (t1, t2))
+   {
+ gcc_checking_assert (COMPLETE_TYPE_P (t1) && COMPLETE_TYPE_P (t2));
+ gcc_checking_assert (comptypes (t1, t2));
+
+ /* If a composite type for these two types is already under
+construction, return it.  */
+
+ for (struct composite_cache *c = cache; c != NULL; c = c->next)
+   if (c->t1 == t1 && c->t2 == t2)
+  return c->composite;
+
+ /* Otherwise, create a new type node and link it into the cache.  */
+
+ tree n = make_node (code1);
+ struct composite_cache cache2 = { t1, t2, n, cache };
+ cache = &cache2;
+
+ tree f1 = TYPE_FIELDS (t1);
+ tree f2 = TYPE_FIELDS (t2);
+ tree fields = NULL_TREE;
+
+ for (tree a = f1, b = f2; a && b;
+  a = DECL_CHAIN (a), b = DECL_CHAIN (b))
+   {
+ tree ta = TREE_TYPE (a);
+ tree tb = TREE_TYPE (b);
+
+ gcc_assert (DECL_NAME (a) == DECL_NAME (b));
+ gcc_assert (comptypes (ta, tb));
+
+ tree f = build_decl (input_location, FIELD_DECL, DECL_NAME (a),
+  composite_type_internal (ta, tb, cache));
+
+ DECL_FIELD_CONTEXT (f) = n;
+ DECL_CHAIN (f) = fields;
+ fields = f;
+   }
+
+ TYPE_NAME (n) = TYPE_NAME (t1);
+ TYPE_FIELDS (n) = nreverse (fields);
+ TYPE_ATTRIBUTES (n) = attributes;
+ layout_type (n);
+ n = build_type_attribute_variant (n, attributes);
+ n = qualify_type (n, t1);
+
+ gcc_checking_assert (comptypes (n, t1));
+ gcc_checking_assert (comptypes (n, t2));
+
+ return n;
+   }
+  /* FALLTHRU */
+case ENUMERAL_TYPE:
   if (attributes != NULL)
{
  /* Try harder not to create a new aggregate type.  */
@@ -520,7 +581,8 @@ composite_type (tree t1, tree t2)
   /* Function types: prefer the one that specified arg types.

[V4] [PATCH 2/4] c23: tag compatibility rules for enums

2023-11-27 Thread Martin Uecker


(only tests were changed)


c23: tag compatibility rules for enums

Allow redefinition of enum types and enumerators.  Diagnose
nested redefinitions including redefinitions in the enum
specifier for enum types with fixed underlying type.

gcc/c:
* c-tree.h (c_parser_enum_specifier): Add parameter.
* c-decl.cc (start_enum): Allow redefinition.
(finish_enum): Diagnose conflicts.
(build_enumerator): Set context.
(diagnose_mismatched_decls): Diagnose conflicting enumerators.
(push_decl): Preserve context for enumerators.
* c-parser.cc (c_parser_enum_specifier): Remember when
seen is from an enum type which is not yet defined.

gcc/testsuide/:
* gcc.dg/c23-tag-enum-1.c: New test.
* gcc.dg/c23-tag-enum-2.c: New test.
* gcc.dg/c23-tag-enum-3.c: New test.
* gcc.dg/c23-tag-enum-4.c: New test.
* gcc.dg/c23-tag-enum-5.c: New test.
* gcc.dg/gnu23-tag-enum-1.c: Mew test.
---
 gcc/c/c-decl.cc | 65 +
 gcc/c/c-parser.cc   |  5 +-
 gcc/c/c-tree.h  |  3 +-
 gcc/c/c-typeck.cc   |  5 +-
 gcc/testsuite/gcc.dg/c23-tag-enum-1.c   | 56 +
 gcc/testsuite/gcc.dg/c23-tag-enum-2.c   | 17 +++
 gcc/testsuite/gcc.dg/c23-tag-enum-3.c   |  7 +++
 gcc/testsuite/gcc.dg/c23-tag-enum-4.c   | 22 +
 gcc/testsuite/gcc.dg/c23-tag-enum-5.c   | 18 +++
 gcc/testsuite/gcc.dg/gnu23-tag-enum-1.c | 19 
 10 files changed, 205 insertions(+), 12 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-enum-1.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-enum-2.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-enum-3.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-enum-4.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-enum-5.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-enum-1.c

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index ebe1708b977..bcc09ba479e 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -2114,9 +2114,24 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
  given scope.  */
   if (TREE_CODE (olddecl) == CONST_DECL)
 {
-  auto_diagnostic_group d;
-  error ("redeclaration of enumerator %q+D", newdecl);
-  locate_old_decl (olddecl);
+  if (flag_isoc23
+ && TYPE_NAME (DECL_CONTEXT (newdecl))
+ && DECL_CONTEXT (newdecl) != DECL_CONTEXT (olddecl)
+ && TYPE_NAME (DECL_CONTEXT (newdecl)) == TYPE_NAME (DECL_CONTEXT 
(olddecl)))
+   {
+ if (!simple_cst_equal (DECL_INITIAL (olddecl), DECL_INITIAL 
(newdecl)))
+   {
+ auto_diagnostic_group d;
+ error ("conflicting redeclaration of enumerator %q+D", newdecl);
+ locate_old_decl (olddecl);
+   }
+   }
+  else
+   {
+ auto_diagnostic_group d;
+ error ("redeclaration of enumerator %q+D", newdecl);
+ locate_old_decl (olddecl);
+   }
   return false;
 }
 
@@ -3277,8 +3292,11 @@ pushdecl (tree x)
 
   /* Must set DECL_CONTEXT for everything not at file scope or
  DECL_FILE_SCOPE_P won't work.  Local externs don't count
- unless they have initializers (which generate code).  */
+ unless they have initializers (which generate code).  We
+ also exclude CONST_DECLs because enumerators will get the
+ type of the enum as context.  */
   if (current_function_decl
+  && TREE_CODE (x) != CONST_DECL
   && (!VAR_OR_FUNCTION_DECL_P (x)
  || DECL_INITIAL (x) || !TREE_PUBLIC (x)))
 DECL_CONTEXT (x) = current_function_decl;
@@ -9747,7 +9765,7 @@ layout_array_type (tree t)
 
 tree
 start_enum (location_t loc, struct c_enum_contents *the_enum, tree name,
-   tree fixed_underlying_type)
+   tree fixed_underlying_type, bool potential_nesting_p)
 {
   tree enumtype = NULL_TREE;
   location_t enumloc = UNKNOWN_LOCATION;
@@ -9759,9 +9777,26 @@ start_enum (location_t loc, struct c_enum_contents 
*the_enum, tree name,
   if (name != NULL_TREE)
 enumtype = lookup_tag (ENUMERAL_TYPE, name, true, &enumloc);
 
+  if (enumtype != NULL_TREE && TREE_CODE (enumtype) == ENUMERAL_TYPE)
+{
+  /* If the type is currently being defined or if we have seen an
+incomplete version which is now complete, this is a nested
+redefinition.  The later happens if the redefinition occurs
+inside the enum specifier itself.  */
+  if (C_TYPE_BEING_DEFINED (enumtype)
+ || (potential_nesting_p && TYPE_VALUES (enumtype) != NULL_TREE))
+   error_at (loc, "nested redefinition of %", name);
+
+  /* For C23 we allow redefinitions.  We set to zero and check for
+consistency later.  */
+  if (flag_isoc23 && TYPE_VALUES (enumtype) != NULL_TREE)
+   enumtype = NULL_TREE;
+}
+
   if (enumtype == NULL_TREE || TREE_CODE (enumtype) != ENUMERAL_TYPE)
 {
   enumtype = make_node (ENUME

[V4] [C PATCH 1/4] c23: tag compatibility rules for struct and unions

2023-11-27 Thread Martin Uecker


Note that there is an additional change in parser_xref_tag
to address the issue regarding completeness in redefinition
which affects also structs / unions.  The test c23-tag-6.c
was changed accordingly.


c23: tag compatibility rules for struct and unions

Implement redeclaration and compatibility rules for
structures and unions in C23.

gcc/c/:
* c-decl.cc (previous_tag): New function.
(parser_xref_tag): Find earlier definition.
(get_parm_info): Turn off warning for C23.
(start_struct): Allow redefinitons.
(finish_struct): Diagnose conflicts.
* c-tree.h (comptypes_same_p): Add prototype.
* c-typeck.cc (comptypes_same_p): New function
(comptypes_internal): Activate comparison of tagged types.
(convert_for_assignment): Ignore qualifiers.
(digest_init): Add error.
(initialized_elementwise_p): Allow compatible types.

gcc/testsuite/:
* gcc.dg/c23-enum-7.c: Remove warning.
* gcc.dg/c23-tag-1.c: New test.
* gcc.dg/c23-tag-2.c: New deactivated test.
* gcc.dg/c23-tag-3.c: New test.
* gcc.dg/c23-tag-4.c: New test.
* gcc.dg/c23-tag-5.c: New deactivated test.
* gcc.dg/c23-tag-6.c: New test.
* gcc.dg/c23-tag-7.c: New test.
* gcc.dg/c23-tag-8.c: New test.
* gcc.dg/gnu23-tag-1.c: New test.
* gcc.dg/gnu23-tag-2.c: New test.
* gcc.dg/gnu23-tag-3.c: New test.
* gcc.dg/gnu23-tag-4.c: New test.
---
 gcc/c/c-decl.cc| 72 +++---
 gcc/c/c-tree.h |  1 +
 gcc/c/c-typeck.cc  | 38 +---
 gcc/testsuite/gcc.dg/c23-enum-7.c  |  6 +--
 gcc/testsuite/gcc.dg/c23-tag-1.c   | 67 +++
 gcc/testsuite/gcc.dg/c23-tag-2.c   | 43 ++
 gcc/testsuite/gcc.dg/c23-tag-3.c   | 16 +++
 gcc/testsuite/gcc.dg/c23-tag-4.c   | 26 +++
 gcc/testsuite/gcc.dg/c23-tag-5.c   | 33 ++
 gcc/testsuite/gcc.dg/c23-tag-6.c   | 58 
 gcc/testsuite/gcc.dg/c23-tag-7.c   | 12 +
 gcc/testsuite/gcc.dg/c23-tag-8.c   | 10 +
 gcc/testsuite/gcc.dg/gnu23-tag-1.c | 10 +
 gcc/testsuite/gcc.dg/gnu23-tag-2.c | 19 
 gcc/testsuite/gcc.dg/gnu23-tag-3.c | 28 
 gcc/testsuite/gcc.dg/gnu23-tag-4.c | 31 +
 16 files changed, 454 insertions(+), 16 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-1.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-2.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-3.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-4.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-5.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-6.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-7.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-8.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-1.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-2.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-3.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-4.c

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 64d3a941cb9..ebe1708b977 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -2039,6 +2039,28 @@ locate_old_decl (tree decl)
decl, TREE_TYPE (decl));
 }
 
+
+/* Helper function.  For a tagged type, it finds the declaration
+   for a visible tag declared in the the same scope if such a
+   declaration exists.  */
+static tree
+previous_tag (tree type)
+{
+  struct c_binding *b = NULL;
+  tree name = TYPE_NAME (type);
+
+  if (name)
+b = I_TAG_BINDING (name);
+
+  if (b)
+b = b->shadowed;
+
+  if (b && B_IN_CURRENT_SCOPE (b))
+return b->decl;
+
+  return NULL_TREE;
+}
+
 /* Subroutine of duplicate_decls.  Compare NEWDECL to OLDDECL.
Returns true if the caller should proceed to merge the two, false
if OLDDECL should simply be discarded.  As a side effect, issues
@@ -8573,11 +8595,14 @@ get_parm_info (bool ellipsis, tree expr)
  if (TREE_CODE (decl) != UNION_TYPE || b->id != NULL_TREE)
{
  if (b->id)
-   /* The %s will be one of 'struct', 'union', or 'enum'.  */
-   warning_at (b->locus, 0,
-   "%<%s %E%> declared inside parameter list"
-   " will not be visible outside of this definition or"
-   " declaration", keyword, b->id);
+   {
+ /* The %s will be one of 'struct', 'union', or 'enum'.  */
+ if (!flag_isoc23)
+   warning_at (b->locus, 0,
+   "%<%s %E%> declared inside parameter list"
+   " will not be visible outside of this 
definition or"
+   " declaration", keyword, b->id);
+   }
  else
/* The %s will be one of 'struct', 'union', or 'enum'.  */
warning_at (b->locus, 0,
@@ -8668,6 +8693,16 

Re: [PATCH 3/4] c23: aliasing of compatible tagged types

2023-11-26 Thread Martin Uecker


Thanks Joseph, I will sent an updated series tomorrow. 

Richard, maybe you could look at what I wrote below
about my use of TYPE_CANONICAL ?  Does this make sense?


Am Donnerstag, dem 23.11.2023 um 23:47 + schrieb Joseph Myers:
> On Thu, 16 Nov 2023, Martin Uecker wrote:
> 
> > Tell the backend which types are equivalent by setting
> > TYPE_CANONICAL to one struct in the set of equivalent
> > structs. Structs are considered equivalent by ignoring
> > all sizes of arrays nested in types below field level.
> 
> Is TYPE_CANONICAL *only* used for alias analysis?  It's not obvious to me 
> that setting TYPE_CANONICAL to a type that's definitely not equivalent for 
> other purposes is necessarily safe.

My understand is that it is used for aliasing analysis and also
checking of conversions.  TYPE_CANONICAL must be consistent with
the idea the middle-end has about type conversions.  But as long
as we do not give the same TYPE_CANONICAL to types the middle-end
thinks must be incompatible using its own type checking machinery,
it should be safe even for types the C standard thinks must be
incompatible for some reason.

> I also think more rationale is needed for ignoring sizes like this.  Is it 
> intended for e.g. making structs with flexible array members 
> alias-compatible with similar structs with a fixed-size array?

The main reason are pointers to arrays:

struct foo { int (*x)[]; }
struct foo { int (*x)[2]; };
struct foo { int (*x)[1]; };

So at least when putting it in terms of equivalence classes,
one has no choice than making those types equivalent. So
all those would get the same TYPE_CANONICAL. The middle-end 
does not care about the different pointer types (in
useless_type_conversion_p or
gimple_canonical_types_compatible_p).


Martin




> 
> > @@ -1250,6 +1266,9 @@ comptypes_internal (const_tree type1, const_tree 
> > type2,
> >  
> > if ((d1 == NULL_TREE) != (d2 == NULL_TREE))
> >   data->different_types_p = true;
> > +   /* ignore size mismatches */
> > +   if (data->equiv)
> > + return 1;
> 
> Should start comment with capital letter, end with '.'.
> 
> > diff --git a/gcc/testsuite/gcc.dg/c23-tag-2.c 
> > b/gcc/testsuite/gcc.dg/c23-tag-2.c
> > index 5dd4a21e9df..e28c2b5eea2 100644
> > --- a/gcc/testsuite/gcc.dg/c23-tag-2.c
> > +++ b/gcc/testsuite/gcc.dg/c23-tag-2.c
> > @@ -1,5 +1,5 @@
> > -/* { dg-do compile { target { ! "*-*-*" } } }
> > - * { dg-options "-std=c23" }
> > +/* { dg-do compile }
> > + * { dg-options "-std=c2x" }
> >   */
> >  
> >  // compatibility of structs in assignment
> > diff --git a/gcc/testsuite/gcc.dg/c23-tag-5.c 
> > b/gcc/testsuite/gcc.dg/c23-tag-5.c
> > index ff40d07aef1..95a04bf9b0e 100644
> > --- a/gcc/testsuite/gcc.dg/c23-tag-5.c
> > +++ b/gcc/testsuite/gcc.dg/c23-tag-5.c
> > @@ -1,5 +1,6 @@
> > -/* { dg-do run { target { ! "*-*-*" } } }
> > - * { dg-options "-std=c23" }
> > +/*
> > + * { dg-do run }
> > + * { dg-options "-std=c2x" }
> 
> These tests should not be changed to use -std=c2x.
> 
> > diff --git a/gcc/testsuite/gcc.dg/c23-tag-alias-2.c 
> > b/gcc/testsuite/gcc.dg/c23-tag-alias-2.c
> > new file mode 100644
> > index 000..555c30a8501
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.dg/c23-tag-alias-2.c
> > @@ -0,0 +1,73 @@
> > +/*
> > + * { dg-do run }
> > + * { dg-options "-std=c23 -O2" }
> > + */
> > +
> > +
> > +struct foo { int x; };
> > +
> > +int test_foo1(struct foo* a, void* b)
> > +{
> > +   a->x = 1;
> > +
> > +   struct foo { int x; int y; }* p = b;
> > +   p->x = 2;
> > +
> > +   return a->x;
> > +}
> 
> > +int main()
> > +{
> > +   struct foo y;
> > +
> > +   if (1 != test_foo1(&y, &y))
> > +   __builtin_abort();
> 
> This test appears to be testing various invalid cases - testing that the 
> compiler does not consider aliasing to occur in those cases (even though 
> in fact there is aliasing).
> 
> If that's the intent of this test, it definitely needs commenting.  The 
> test would also need to (be a gnu23-* test and) use appropriate attributes 
> to disable interprocedural analysis, since it would be entirely valid for 
> the compiler in this test to inline test_foo1, see that p->x in fact 
> points to the same location as a->x despite the incompatible types, and 
> have the function return 2.
> 
> The same applies to c23-tag-alias-4.c and c23-tag-alias-5.c.
> 
> > diff --git a/gcc/testsuite/gcc.dg/c23-tag-alias-5.c 
> > b/gcc/testsuite/gcc.dg/c23-tag-alias-5.c
> > new file mode 100644
> > index 000..4e956720143
> > --- /dev/null
> > +++ b/gcc/testsuite/gcc.dg/c23-tag-alias-5.c
> > @@ -0,0 +1,30 @@
> > +/* { dg-do run }
> > + * { dg-options "-std=c23 -O2" }
> > + */
> > +
> > +// not sure this is wise, but this was already like thi sbefore
> 
> "this before"
> 



Re: [PATCH] c-family, middle-end: Add __builtin_c[lt]zg (arg, 0ULL) exception

2023-11-20 Thread Martin Uecker


(corrected address)


> On Mon, 20 Nov 2023, Jakub Jelinek wrote:
> 
> > On Mon, Nov 20, 2023 at 08:37:55AM +, Richard Biener wrote:
> > > > I'm not sure about that, it would be nice for them to be usable there,
> > > 
> > > Btw, I think that {( .. )} should be made usable in sizeof () and
> > > possibly even in at least C++ constant expressions (not sure about C).
> > 
> > I believe the problkem is having new VAR_DECLs in those which actually
> > aren't file scope/namespace scope variables but there is no function
> > DECL_CONTEXT to attach to them.  So, it probably wouldn't be one afternoon
> > change to allow that.

There is an open bug about this:
https://gcc.gnu.org/bugzilla/show_bug.cgi?id=93239

But the required feature is simpler than full statement 
expression, essentially

let x = y in z

where x is an identifier and y and z are expression, and
this should be much easier to implement.

I thought about an extension to _Generic which would be
useful here:

_GNU_Generic(y, int x1: z1, float x2: z2)

or even

_GNU_Generic(y, default x: z)

which would be useful in general.


> > 
> > > > but I think e.g. none of Joseph's implementation of those macros
> > > > made them usable there (except inside of sizeof/typeof/typeof_unquall)
> > > > and I don't see a requirement in the C23 standard that they must be 
> > > > usable
> > > > in constant expressions.
> > > > The versions I've posted on Thursday were usable there except for
> > > > stdc_has_single_bit (but that actually can be implemented that way too)
> > > > and stdc_bit_floor.  And the version I haven't posted that used the 3
> > > > patches posted on Saturday would have all functions usable when the
> > > > argument to those macros is a constant expression.
> > > > 
> > > > BTW, if we go route of implementing all of the stdc_ type-generic macros
> > > > as builtins, we could as well not implement that way the following 4
> > > > # define stdc_first_leading_one(x) (__builtin_clzg (x, -1) + 1U)
> > > > # define stdc_first_trailing_one(x) (__builtin_ctzg (x, -1) + 1U)
> > > > # define stdc_count_ones(x) ((unsigned int) __builtin_popcountg (x))
> > > > # define stdc_has_single_bit(x) ((_Bool) (__builtin_popcountg (x) == 1))
> > > > which are implementable without any new extensions.
> > > 
> > > I'd rather do all of those necessary as builtins instead of hacking
> > > around limitations.  If we don't want to solve those limitations in
> > > a more generic way.
> > 
> > Ok, I can prepare a patch for that, shouldn't be that hard.
> > Do you want all 14, or just the 10 and leave the above 4 with the
> > above definitions?
> 
> I'd say all of them for consistency, we can parse/gimplify them to
> the open-coded variants then.

For use of _Generic with _BitInt one would need some kind
of _BitInt_Width(x) macro/builtin that returns the width as an
constant expressions, which would also be useful in general.

Then one could write:

_Generic(x, int a: foo, _BitInt(_BitInt_Width(x)): bar);

With this and an extension as suggested above, I think one could
solve this in a generic way.

Martin

> > > And of course nobody would write
> > > 
> > > const int x = sizeof (stdc_first_leading_one (5));
> > > 
> > > that's just stupid ... (but oh well).
> > 
> > Well, standard testsuite needs to include that at least.
> > But of course, if it is usable in constant expressions,
> > unsigned a = stdc_bit_width ((unsigned _BitInt(824)) 
> > 435987349856735489657489657468954768954674589674598uwb * 
> > 49876558967549867548967548967548967549867548967456uwb);
> > etc. can be useful in constant expressions.


> > 
> > Jakub
> > 
> > 



[PATCH 4/4] c: runtime checking for assigment of VM types 4/4

2023-11-18 Thread Martin Uecker



Add warning for the case when a function call can not be instrumened.

gcc/c-family/:
* c.opt (Wvla-parameter-missing-check): Add warning.

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

gcc/doc/:
* invoke.texi (Wvla-parameter-missing-check): Document warning.
(flag_vla_bounds): Update.

gcc/testsuite/:
* gcc.dg/vla-bounds-func-1.c: Add warning.
---
 gcc/c-family/c.opt   |  5 +
 gcc/c/c-typeck.cc|  4 
 gcc/doc/invoke.texi  | 11 ---
 gcc/testsuite/gcc.dg/vla-bounds-func-1.c |  6 +++---
 4 files changed, 20 insertions(+), 6 deletions(-)

diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 29bc0956181..bd45ba577bd 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -1485,6 +1485,11 @@ Wvla-parameter
 C ObjC C++ ObjC++ Var(warn_vla_parameter) Warning LangEnabledBy(C ObjC C++ 
ObjC++,Wall)
 Warn about mismatched declarations of VLA parameters.
 
+Wvla-parameter-missing-check
+C ObjC Var(warn_vla_parameter_check) Warning Init(0)
+When using run-time checking of VLA bounds, warn about function calls which
+could not be instrumented.
+
 Wvolatile
 C++ ObjC++ Var(warn_volatile) Warning
 Warn about deprecated uses of volatile qualifier.
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 1200abc2f4a..a4fb0a6b527 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -3481,6 +3481,8 @@ process_vm_constraints (location_t location,
{
  /* FIXME: this can happen when forming composite types for the
 conditional operator.  */
+ warning_at (location, OPT_Wvla_parameter_missing_check,
+ "Function call not instrumented");
  return void_node;
}
}
@@ -3564,6 +3566,8 @@ process_vm_constraints (location_t location,
  also not instrument any of the others because it may have
  side effects affecting them.  (We could restart and instrument
  only the ones with integer constants.)   */
+   warning_at (location, OPT_Wvla_parameter_missing_check,
+   "Function call not instrumented");
return void_node;
}
 cont:
diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi
index c94ca59086b..6f4bbd43919 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -10269,6 +10269,7 @@ void g (int n)
 @option{-Warray-parameter} option triggers warnings for similar problems
 involving ordinary array arguments.
 
+
 @opindex Wvla-parameter-missing-check
 @item -Wvla-parameter-missing-check
 Warn when function calls can not be instrumented with the use of
@@ -20063,9 +20064,13 @@ The @var{string} should be different for every file 
you compile.
 @item -fvla-bounds
 This option is only available when compiling C code.  If activated,
 additional code is emitted that verifies at run time for assignments
-involving variably-modified types that corresponding size expressions
-evaluate to the same value.
-
+and function calls involving variably-modified types that corresponding
+size expressions evaluate to the same value.  Note that for function
+calls the visible declarations needs to have a size expression that
+matches the size expression in the definition.  A mismatch seen by the
+the compiler is diagnosed by @option{-Wvla-parameter}). In same cases,
+a function call can not be instrumented.  This can be diagnosed by
+@option{-Wvla-parameter-missing-check}.
 
 @opindex save-temps
 @item -save-temps
diff --git a/gcc/testsuite/gcc.dg/vla-bounds-func-1.c 
b/gcc/testsuite/gcc.dg/vla-bounds-func-1.c
index 72dba39107b..205e5174185 100644
--- a/gcc/testsuite/gcc.dg/vla-bounds-func-1.c
+++ b/gcc/testsuite/gcc.dg/vla-bounds-func-1.c
@@ -1,5 +1,5 @@
 /* { dg-do compile } */
-/* { dg-options "-fvla-bounds" } */
+/* { dg-options "-fvla-bounds -Wvla-parameter-missing-check" } */
 
 // make sure we do not ICE on any of these
 
@@ -31,7 +31,7 @@ void f(void)
 
int u = 3; int v = 4;
char a[u][v];
-   (1 ? f1 : f2)(u, v, a); /* "Function call not instrumented." */
+   (1 ? f1 : f2)(u, v, a); /* { dg-warning "Function call" "not 
instrumented." } */
 }
 
 /* size expression in parameter */
@@ -51,6 +51,6 @@ int c(int u, char (*a)[u]) { }
 int d(void)
 {
char a[3];
-   c(3, &a);   /* "Function call not instrumented." */
+   c(3, &a);   /* { dg-warning "Function call" "not 
instrumented." } */
 }
 
-- 
2.39.2




[PATCH 3/4] c: runtime checking for assigment of VM types 3/4

2023-11-18 Thread Martin Uecker



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-typeck.cc (process_vm_constraints): Instrument functions
called via pointers.

gcc/testsuide/gcc.dg:
* vla-bounds-func-1.c: Add warning.
* vla-bounds-fnptr.c: New test.
* vla-bounds-fnptr-1.c: New test.
* vla-bounds-fnptr-2.c: New test.
* vla-bounds-fnptr-3.c: New test.
* vla-bounds-fnptr-4.c: New test.
* vla-bounds-fnptr-5.c: New test.
---
 gcc/c/c-decl.cc   |  4 ++
 gcc/c/c-typeck.cc | 14 +++-
 gcc/testsuite/gcc.dg/vla-bounds-fnptr-1.c | 78 +++
 gcc/testsuite/gcc.dg/vla-bounds-fnptr-2.c | 78 +++
 gcc/testsuite/gcc.dg/vla-bounds-fnptr-3.c | 78 +++
 gcc/testsuite/gcc.dg/vla-bounds-fnptr-4.c | 78 +++
 gcc/testsuite/gcc.dg/vla-bounds-fnptr-5.c | 78 +++
 gcc/testsuite/gcc.dg/vla-bounds-fnptr.c   | 78 +++
 gcc/testsuite/gcc.dg/vla-bounds-func-1.c  |  2 +-
 9 files changed, 485 insertions(+), 3 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-fnptr-1.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-fnptr-2.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-fnptr-3.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-fnptr-4.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-fnptr-5.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-fnptr.c

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 64d3a941cb9..84a30f7476a 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -8549,6 +8549,10 @@ 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 for VLA bounds checking.  */
+ if (flag_vla_bounds)
+   TREE_PURPOSE (types) = decl;
}
  break;
 
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index b65fc450940..1200abc2f4a 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -3472,9 +3472,19 @@ 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.  */
+ return void_node;
+   }
}
+  gcc_assert (PARM_DECL == TREE_CODE (args));
 }
 
   for (struct instrument_data* d = *instr_vec; d; d = d->next)
diff --git a/gcc/testsuite/gcc.dg/vla-bounds-fnptr-1.c 
b/gcc/testsuite/gcc.dg/vla-bounds-fnptr-1.c
new file mode 100644
index 000..b9af87f6338
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vla-bounds-fnptr-1.c
@@ -0,0 +1,78 @@
+/* { dg-do run } */
+/* { dg-options "-fvla-bounds" } */
+
+#include 
+#include 
+
+static void handler(int) { exit(0); }
+
+#define TRY(...) __VA_ARGS__ __builtin_abort();
+#define ERROR(...)
+
+
+
+void foo1(void (*p)(int n, char (*a)[n]))
+{
+   char A0[3];
+   (*p)(3, &A0);
+TRY(   (*p)(4, &A0); ) // 4 != 3
+}
+
+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);
+ERROR( (*p)(4, &A0); ) // 4 != 3
+}
+
+void foo3(void (*p)(int n0, char (*a)[n]))
+{
+   n = 4;
+   char A0[3];
+ERROR( (*p)(3, &A0); ) // 4 != 3
+ERROR( (*p)(4, &A0); ) // 4 != 3 
+}
+
+void foo4(void (*p)(int n, char (*a)[n]))
+{
+   n = 3;
+   char A0[3];
+   (*p)(3, &A0);
+ERROR( (*p)(4, &A0); ) // 4 != 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()
+{
+   signal(SIGILL, handler);
+
+   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
+}
+
+
+
diff --git a/gcc/testsuite/gcc.dg/vla-bounds-fnptr-2.c 
b/gcc/testsuite/gcc.dg/vla-bounds-fnptr-2.c
new file mode 100644
index 000..4ec326af06c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/vla-bounds-fnptr-2.c
@@ -0,0 +1,78 @@
+/* { dg-do run } */
+/* { dg-options "-fvla-bounds" } */
+
+#include 
+#include 
+
+static void handler(int) { exit(0); }
+
+#define TRY(...) __VA_ARGS__ __builtin_abort();
+#define ERROR(...)
+
+
+
+void foo1(voi

[PATCH 2/4] c: runtime checking for assigment of VM types 2/4

2023-11-18 Thread Martin Uecker



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

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

gcc/testsuide/gcc.dg:
* vla-bounds-func-1.c: Update.
* vla-bounds-func-2.c: New test.
* vla-bounds-func-3.c: New test.
* vla-bounds-func-4.c: New test.
* vla-bounds-func-5.c: New test.
* vla-bounds-func-6.c: New test.
* vla-bounds-func-7.c: New test.
* vla-bounds-func-8.c: New test.
* vla-bounds-func-9.c: New test.
* vla-bounds-func-10.c: New test.
* vla-bounds-func-11.c: New test.
* vla-bounds-func-12.c: New test.
* vla-bounds-func-13.c: New test.
* vla-bounds-func-14.c: New test.
* vla-bounds-func-15.c: New test.
* vla-bounds-func-16.c: New test.
* vla-bounds-func-17.c: New test.
* vla-bounds-func-18.c: New test.
* vla-bounds-func-19.c: New test.
* vla-bounds-func-20.c: New test.
---
 gcc/c/c-typeck.cc | 151 +++---
 gcc/testsuite/gcc.dg/vla-bounds-func-1.c  |   4 +-
 gcc/testsuite/gcc.dg/vla-bounds-func-10.c |  99 ++
 gcc/testsuite/gcc.dg/vla-bounds-func-11.c |  99 ++
 gcc/testsuite/gcc.dg/vla-bounds-func-12.c |  99 ++
 gcc/testsuite/gcc.dg/vla-bounds-func-13.c |  99 ++
 gcc/testsuite/gcc.dg/vla-bounds-func-14.c |  45 +++
 gcc/testsuite/gcc.dg/vla-bounds-func-15.c |  45 +++
 gcc/testsuite/gcc.dg/vla-bounds-func-16.c |  45 +++
 gcc/testsuite/gcc.dg/vla-bounds-func-17.c |  45 +++
 gcc/testsuite/gcc.dg/vla-bounds-func-18.c |  45 +++
 gcc/testsuite/gcc.dg/vla-bounds-func-19.c |  45 +++
 gcc/testsuite/gcc.dg/vla-bounds-func-2.c  |  99 ++
 gcc/testsuite/gcc.dg/vla-bounds-func-20.c |  45 +++
 gcc/testsuite/gcc.dg/vla-bounds-func-3.c  |  99 ++
 gcc/testsuite/gcc.dg/vla-bounds-func-4.c  |  99 ++
 gcc/testsuite/gcc.dg/vla-bounds-func-5.c  |  99 ++
 gcc/testsuite/gcc.dg/vla-bounds-func-6.c  |  99 ++
 gcc/testsuite/gcc.dg/vla-bounds-func-7.c  |  99 ++
 gcc/testsuite/gcc.dg/vla-bounds-func-8.c  |  99 ++
 gcc/testsuite/gcc.dg/vla-bounds-func-9.c  |  99 ++
 21 files changed, 1641 insertions(+), 17 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-10.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-11.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-12.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-13.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-14.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-15.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-16.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-17.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-18.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-19.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-2.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-20.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-3.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-4.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-5.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-6.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-7.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-8.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-9.c

diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index cb5887b6255..b65fc450940 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -1067,19 +1067,13 @@ common_type (tree t1, tree t2)
 /* Instrument assignment of variably modified types.  */
 
 static tree
-c_instrument_vm_assign (location_t loc, tree a, tree b)
+c_instrument_vm_assign (location_t loc, tree a, tree b, tree as, tree bs)
 {
   gcc_assert (flag_vla_bounds);
 
   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);
-
   tree t = build2 (NE_EXPR, boolean_type_node, as, bs);
   tree tt = build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_TRAP), 
0);
 
@@ -3286,7 +3280,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,
- boo

[PATCH 1/4] c: runtime checking for assigment of VM types 1/4

2023-11-18 Thread Martin Uecker



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 runtime checks for
each bound.

gcc/c-family:
* c-opt (fvla-bounds): New flag.

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_argument): Adapt.
(convert_for_assignment_instrument): New interface.
(convert_for_assignment): Instrument assignments.
(c_instrument_vm_assign): Helper function.
(process_vm_constraints): Helper function.

gcc/doc/:
* invoke.texi (fvla-bounds): Document new flag.

gcc/testsuite:
* gcc.dg/vla-bounds-1.c: New test.
* gcc.dg/vla-bounds-assign-1.c: New test.
* gcc.dg/vla-bounds-assign-2.c: New test.
* gcc.dg/vla-bounds-assign-3.c: New test.
* gcc.dg/vla-bounds-assign-4.c: New test.
* gcc.dg/vla-bounds-func-1.c: New test.
* gcc.dg/vla-bounds-init-1.c: New test.
* gcc.dg/vla-bounds-init-2.c: New test.
* gcc.dg/vla-bounds-init-3.c: New test.
* gcc.dg/vla-bounds-init-4.c: New test.
* gcc.dg/vla-bounds-nest-1.c: New test.
* gcc.dg/vla-bounds-nest-2.c: New test.
* gcc.dg/vla-bounds-ret-1.c: New test.
* gcc.dg/vla-bounds-ret-2.c: New test.
---
 gcc/c-family/c.opt |   4 +
 gcc/c/c-typeck.cc  | 171 ++---
 gcc/doc/invoke.texi|  15 ++
 gcc/testsuite/gcc.dg/vla-bounds-1.c|  85 ++
 gcc/testsuite/gcc.dg/vla-bounds-assign-1.c | 126 +++
 gcc/testsuite/gcc.dg/vla-bounds-assign-2.c | 126 +++
 gcc/testsuite/gcc.dg/vla-bounds-assign-3.c | 126 +++
 gcc/testsuite/gcc.dg/vla-bounds-assign-4.c | 133 
 gcc/testsuite/gcc.dg/vla-bounds-func-1.c   |  56 +++
 gcc/testsuite/gcc.dg/vla-bounds-init-1.c   | 125 +++
 gcc/testsuite/gcc.dg/vla-bounds-init-2.c   | 125 +++
 gcc/testsuite/gcc.dg/vla-bounds-init-3.c   | 126 +++
 gcc/testsuite/gcc.dg/vla-bounds-init-4.c   | 125 +++
 gcc/testsuite/gcc.dg/vla-bounds-nest-1.c   |  39 +
 gcc/testsuite/gcc.dg/vla-bounds-nest-2.c   |  33 
 gcc/testsuite/gcc.dg/vla-bounds-ret-1.c| 132 
 gcc/testsuite/gcc.dg/vla-bounds-ret-2.c| 133 
 17 files changed, 1661 insertions(+), 19 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-1.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-assign-1.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-assign-2.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-assign-3.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-assign-4.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-func-1.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-init-1.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-init-2.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-init-3.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-init-4.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-nest-1.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-nest-2.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-ret-1.c
 create mode 100644 gcc/testsuite/gcc.dg/vla-bounds-ret-2.c

diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index b10c6057cd1..29bc0956181 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -2280,6 +2280,10 @@ fvisibility-ms-compat
 C++ ObjC++ Var(flag_visibility_ms_compat)
 Changes visibility to match Microsoft Visual Studio by default.
 
+fvla-bounds
+C Var(flag_vla_bounds)
+Emit run-time consistency checks for variably-modified types.
+
 fvtable-gc
 C++ ObjC++ WarnRemoved
 No longer supported.
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 1dbb4471a88..cb5887b6255 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -93,11 +93,13 @@ static tree qualify_type (tree, tree);
 struct comptypes_data;
 static bool tagged_types_tu_compatible_p (const_tree, const_tree,
  struct comptypes_data *);
-static bool comp_target_types (location_t, tree, tree);
 static bool function_types_compatible_p (const_tree, const_tree,
 struct comptypes_data *);
 static bool type_lists_compatible_p (const_tree, const_tree,
   

C runtime checking for assigment of VM types

2023-11-18 Thread Martin Uecker


This is another revised series for checking for
bounds consistency when assigning VM types.


Based on feedback, I disentangled this from UBSan for 
a three reasons:

- I think it makes sense as a stand-alone feature
similar to other run-time instrumentation features
GCC already has.

- Not all checks are strictly speaking for UB, i.e. it
triggers for strictly conforming code which has
inconsistent bounds.  For this feature, it makes 
sense to assume that bounds are correct (and GCC warns 
about inconsistently declared bounds by default already
for a while).

- So far, there is no upstream support in libubsan
which we could use.



Bootstrapped and regression tested on x86_64.


Martin









[PATCH 4/4] c23: construct composite type for tagged types

2023-11-16 Thread Martin Uecker






Support for constructing composite type for structs and unions
in C23.

gcc/c:
* c-typeck.cc (composite_type_internal): Adapted from
composite_type to support structs and unions.
(composite_type): New wrapper function.
(build_conditional_operator): Return composite type.

gcc/testsuite:
* gcc.dg/c23-tag-composite-1.c: New test.
* gcc.dg/c23-tag-composite-2.c: New test.
* gcc.dg/c23-tag-composite-3.c: New test.
* gcc.dg/c23-tag-composite-4.c: New test.
---
 gcc/c/c-typeck.cc  | 114 +
 gcc/testsuite/gcc.dg/c23-tag-composite-1.c |  26 +
 gcc/testsuite/gcc.dg/c23-tag-composite-2.c |  16 +++
 gcc/testsuite/gcc.dg/c23-tag-composite-3.c |  17 +++
 gcc/testsuite/gcc.dg/c23-tag-composite-4.c |  21 
 5 files changed, 176 insertions(+), 18 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-composite-1.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-composite-2.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-composite-3.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-composite-4.c

diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 262b04c582f..2255fb66bb2 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -381,8 +381,15 @@ build_functype_attribute_variant (tree ntype, tree otype, 
tree attrs)
nonzero; if that isn't so, this may crash.  In particular, we
assume that qualifiers match.  */
 
+struct composite_cache {
+  tree t1;
+  tree t2;
+  tree composite;
+  struct composite_cache* next;
+};
+
 tree
-composite_type (tree t1, tree t2)
+composite_type_internal (tree t1, tree t2, struct composite_cache* cache)
 {
   enum tree_code code1;
   enum tree_code code2;
@@ -427,7 +434,8 @@ composite_type (tree t1, tree t2)
   {
tree pointed_to_1 = TREE_TYPE (t1);
tree pointed_to_2 = TREE_TYPE (t2);
-   tree target = composite_type (pointed_to_1, pointed_to_2);
+   tree target = composite_type_internal (pointed_to_1,
+  pointed_to_2, cache);
 t1 = build_pointer_type_for_mode (target, TYPE_MODE (t1), false);
t1 = build_type_attribute_variant (t1, attributes);
return qualify_type (t1, t2);
@@ -435,7 +443,8 @@ composite_type (tree t1, tree t2)
 
 case ARRAY_TYPE:
   {
-   tree elt = composite_type (TREE_TYPE (t1), TREE_TYPE (t2));
+   tree elt = composite_type_internal (TREE_TYPE (t1), TREE_TYPE (t2),
+   cache);
int quals;
tree unqual_elt;
tree d1 = TYPE_DOMAIN (t1);
@@ -503,9 +512,61 @@ composite_type (tree t1, tree t2)
return build_type_attribute_variant (t1, attributes);
   }
 
-case ENUMERAL_TYPE:
 case RECORD_TYPE:
 case UNION_TYPE:
+  if (flag_isoc23 && !comptypes_same_p (t1, t2))
+   {
+ gcc_checking_assert (COMPLETE_TYPE_P (t1) && COMPLETE_TYPE_P (t2));
+ gcc_checking_assert (comptypes (t1, t2));
+
+ /* If a composite type for these two types is already under
+construction, return it.  */
+
+ for (struct composite_cache *c = cache; c != NULL; c = c->next)
+   if (c->t1 == t1 && c->t2 == t2)
+  return c->composite;
+
+ /* Otherwise, create a new type node and link it into the cache.  */
+
+ tree n = make_node (code1);
+ struct composite_cache cache2 = { t1, t2, n, cache };
+ cache = &cache2;
+
+ tree f1 = TYPE_FIELDS (t1);
+ tree f2 = TYPE_FIELDS (t2);
+ tree fields = NULL_TREE;
+
+ for (tree a = f1, b = f2; a && b;
+  a = DECL_CHAIN (a), b = DECL_CHAIN (b))
+   {
+ tree ta = TREE_TYPE (a);
+ tree tb = TREE_TYPE (b);
+
+ gcc_assert (DECL_NAME (a) == DECL_NAME (b));
+ gcc_assert (comptypes (ta, tb));
+
+ tree f = build_decl (input_location, FIELD_DECL, DECL_NAME (a),
+  composite_type_internal (ta, tb, cache));
+
+ DECL_FIELD_CONTEXT (f) = n;
+ DECL_CHAIN (f) = fields;
+ fields = f;
+   }
+
+ TYPE_NAME (n) = TYPE_NAME (t1);
+ TYPE_FIELDS (n) = nreverse (fields);
+ TYPE_ATTRIBUTES (n) = attributes;
+ layout_type (n);
+ n = build_type_attribute_variant (n, attributes);
+ n = qualify_type (n, t1);
+
+ gcc_checking_assert (comptypes (n, t1));
+ gcc_checking_assert (comptypes (n, t2));
+
+ return n;
+   }
+  /* FALLTHRU */
+case ENUMERAL_TYPE:
   if (attributes != NULL)
{
  /* Try harder not to create a new aggregate type.  */
@@ -520,7 +581,8 @@ composite_type (tree t1, tree t2)
   /* Function types: prefer the one that specified arg types.
 If both do, merge the arg types.  Also merge the return types.  */
   {
-   tree valtype = composite_type (TREE_TYPE (t1), T

[PATCH 3/4] c23: aliasing of compatible tagged types

2023-11-16 Thread Martin Uecker




Tell the backend which types are equivalent by setting
TYPE_CANONICAL to one struct in the set of equivalent
structs. Structs are considered equivalent by ignoring
all sizes of arrays nested in types below field level.

gcc/c:
* c-decl.cc (c_struct_hasher): Hash stable for struct
types.
(c_struct_hasher::hash, c_struct_hasher::equal): New
functions.
(finish_struct): Set TYPE_CANONICAL to first struct in
equivalence class.
* c-objc-common.cc (c_get_alias_set): Let structs or
unions with variable size alias anything.
* c-tree.h (comptypes_equiv): New prototype.
* c-typeck.cc (comptypes_equiv): New function.
(comptypes_internal): Implement equivalence mode.
(tagged_types_tu_compatible): Implement equivalence mode.

gcc/testsuite:
* gcc.dg/c23-tag-2.c: Activate.
* gcc.dg/c23-tag-6.c: Activate.
* gcc.dg/c23-tag-alias-1.c: New test.
* gcc.dg/c23-tag-alias-2.c: New test.
* gcc.dg/c23-tag-alias-3.c: New test.
* gcc.dg/c23-tag-alias-4.c: New test.
* gcc.dg/c23-tag-alias-5.c: New test.
* gcc.dg/c23-tag-alias-6.c: New test.
* gcc.dg/c23-tag-alias-7.c: New test.
* gcc.dg/c23-tag-alias-8.c: New test.
* gcc.dg/gnu23-tag-alias-1.c: New test.
---
 gcc/c/c-decl.cc  | 48 +
 gcc/c/c-objc-common.cc   |  5 ++
 gcc/c/c-tree.h   |  1 +
 gcc/c/c-typeck.cc| 31 
 gcc/testsuite/gcc.dg/c23-tag-2.c |  4 +-
 gcc/testsuite/gcc.dg/c23-tag-5.c |  5 +-
 gcc/testsuite/gcc.dg/c23-tag-alias-1.c   | 48 +
 gcc/testsuite/gcc.dg/c23-tag-alias-2.c   | 73 +++
 gcc/testsuite/gcc.dg/c23-tag-alias-3.c   | 48 +
 gcc/testsuite/gcc.dg/c23-tag-alias-4.c   | 73 +++
 gcc/testsuite/gcc.dg/c23-tag-alias-5.c   | 30 
 gcc/testsuite/gcc.dg/c23-tag-alias-6.c   | 77 
 gcc/testsuite/gcc.dg/c23-tag-alias-7.c   | 86 ++
 gcc/testsuite/gcc.dg/c23-tag-alias-8.c   | 90 
 gcc/testsuite/gcc.dg/gnu23-tag-alias-1.c | 33 +
 15 files changed, 648 insertions(+), 4 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-alias-1.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-alias-2.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-alias-3.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-alias-4.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-alias-5.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-alias-6.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-alias-7.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-alias-8.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-alias-1.c

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index e5d48c3fa56..d0a405087c3 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -634,6 +634,36 @@ public:
   auto_vec typedefs_seen;
 };
 
+
+/* Hash table for structs and unions.  */
+struct c_struct_hasher : ggc_ptr_hash
+{
+  static hashval_t hash (tree t);
+  static bool equal (tree, tree);
+};
+
+/* Hash an RECORD OR UNION.  */
+hashval_t
+c_struct_hasher::hash (tree type)
+{
+  inchash::hash hstate;
+
+  hstate.add_int (TREE_CODE (type));
+  hstate.add_object (TYPE_NAME (type));
+
+  return hstate.end ();
+}
+
+/* Compare two RECORD or UNION types.  */
+bool
+c_struct_hasher::equal (tree t1,  tree t2)
+{
+  return comptypes_equiv_p (t1, t2);
+}
+
+/* All tagged typed so that TYPE_CANONICAL can be set correctly.  */
+static GTY (()) hash_table *c_struct_htab;
+
 /* 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;
@@ -9646,6 +9676,24 @@ finish_struct (location_t loc, tree t, tree fieldlist, 
tree attributes,
 
   C_TYPE_BEING_DEFINED (t) = 0;
 
+  /* Set type canonical based on equivalence class.  */
+  if (flag_isoc23)
+{
+  if (NULL == c_struct_htab)
+   c_struct_htab = hash_table::create_ggc (61);
+
+  hashval_t hash = c_struct_hasher::hash (t);
+
+  tree *e = c_struct_htab->find_slot_with_hash (t, hash, INSERT);
+  if (*e)
+   TYPE_CANONICAL (t) = *e;
+  else
+   {
+ TYPE_CANONICAL (t) = t;
+ *e = t;
+   }
+}
+
   tree incomplete_vars = C_TYPE_INCOMPLETE_VARS (TYPE_MAIN_VARIANT (t));
   for (x = TYPE_MAIN_VARIANT (t); x; x = TYPE_NEXT_VARIANT (x))
 {
diff --git a/gcc/c/c-objc-common.cc b/gcc/c/c-objc-common.cc
index c8f49aa2370..738afbad770 100644
--- a/gcc/c/c-objc-common.cc
+++ b/gcc/c/c-objc-common.cc
@@ -389,6 +389,11 @@ c_get_alias_set (tree t)
   if (TREE_CODE (t) == ENUMERAL_TYPE)
 return get_alias_set (ENUM_UNDERLYING_TYPE (t));
 
+  /* Structs with variable size can alias different incompatible
+ structs.  Let them alias anything.   */
+  if (RECORD_OR_UNION_TYPE_P (t) && C_TYPE_VARIABLE_SIZ

[PATCH 2/4] c23: tag compatibility rules for enums

2023-11-16 Thread Martin Uecker




Allow redefinition of enum types and enumerators.  Diagnose
nested redefinitions including redefinitions in the enum
specifier for enum types with fixed underlying type.

gcc/c:
* c-tree.h (c_parser_enum_specifier): Add parameter.
* c-decl.cc (start_enum): Allow redefinition.
(finish_enum): Diagnose conflicts.
(build_enumerator): Set context.
(diagnose_mismatched_decls): Diagnose conflicting enumerators.
(push_decl): Preserve context for enumerators.
* c-parser.cc (c_parser_enum_specifier): Remember when
seen is from an enum type which is not yet defined.

gcc/testsuide/:
* gcc.dg/c23-tag-enum-1.c: New test.
* gcc.dg/c23-tag-enum-2.c: New test.
* gcc.dg/c23-tag-enum-3.c: New test.
* gcc.dg/c23-tag-enum-4.c: New test.
* gcc.dg/c23-tag-enum-5.c: New test.
---
 gcc/c/c-decl.cc   | 65 +++
 gcc/c/c-parser.cc |  5 ++-
 gcc/c/c-tree.h|  3 +-
 gcc/c/c-typeck.cc |  5 ++-
 gcc/testsuite/gcc.dg/c23-tag-enum-1.c | 56 +++
 gcc/testsuite/gcc.dg/c23-tag-enum-2.c | 23 ++
 gcc/testsuite/gcc.dg/c23-tag-enum-3.c |  7 +++
 gcc/testsuite/gcc.dg/c23-tag-enum-4.c | 22 +
 gcc/testsuite/gcc.dg/c23-tag-enum-5.c | 18 
 9 files changed, 192 insertions(+), 12 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-enum-1.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-enum-2.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-enum-3.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-enum-4.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-enum-5.c

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 194dd595334..e5d48c3fa56 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -2114,9 +2114,24 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
  given scope.  */
   if (TREE_CODE (olddecl) == CONST_DECL)
 {
-  auto_diagnostic_group d;
-  error ("redeclaration of enumerator %q+D", newdecl);
-  locate_old_decl (olddecl);
+  if (flag_isoc23
+ && TYPE_NAME (DECL_CONTEXT (newdecl))
+ && DECL_CONTEXT (newdecl) != DECL_CONTEXT (olddecl)
+ && TYPE_NAME (DECL_CONTEXT (newdecl)) == TYPE_NAME (DECL_CONTEXT 
(olddecl)))
+   {
+ if (!simple_cst_equal (DECL_INITIAL (olddecl), DECL_INITIAL 
(newdecl)))
+   {
+ auto_diagnostic_group d;
+ error ("conflicting redeclaration of enumerator %q+D", newdecl);
+ locate_old_decl (olddecl);
+   }
+   }
+  else
+   {
+ auto_diagnostic_group d;
+ error ("redeclaration of enumerator %q+D", newdecl);
+ locate_old_decl (olddecl);
+   }
   return false;
 }
 
@@ -3277,8 +3292,11 @@ pushdecl (tree x)
 
   /* Must set DECL_CONTEXT for everything not at file scope or
  DECL_FILE_SCOPE_P won't work.  Local externs don't count
- unless they have initializers (which generate code).  */
+ unless they have initializers (which generate code).  We
+ also exclude CONST_DECLs because enumerators will get the
+ type of the enum as context.  */
   if (current_function_decl
+  && TREE_CODE (x) != CONST_DECL
   && (!VAR_OR_FUNCTION_DECL_P (x)
  || DECL_INITIAL (x) || !TREE_PUBLIC (x)))
 DECL_CONTEXT (x) = current_function_decl;
@@ -9737,7 +9755,7 @@ layout_array_type (tree t)
 
 tree
 start_enum (location_t loc, struct c_enum_contents *the_enum, tree name,
-   tree fixed_underlying_type)
+   tree fixed_underlying_type, bool potential_nesting_p)
 {
   tree enumtype = NULL_TREE;
   location_t enumloc = UNKNOWN_LOCATION;
@@ -9749,9 +9767,26 @@ start_enum (location_t loc, struct c_enum_contents 
*the_enum, tree name,
   if (name != NULL_TREE)
 enumtype = lookup_tag (ENUMERAL_TYPE, name, true, &enumloc);
 
+  if (enumtype != NULL_TREE && TREE_CODE (enumtype) == ENUMERAL_TYPE)
+{
+  /* If the type is currently being defined or if we have seen an
+incomplete version which is now complete, this is a nested
+redefinition.  The later happens if the redefinition occurs
+inside the enum specifier itself.  */
+  if (C_TYPE_BEING_DEFINED (enumtype)
+ || (potential_nesting_p && TYPE_VALUES (enumtype) != NULL_TREE))
+   error_at (loc, "nested redefinition of %", name);
+
+ /* For C23 we allow redefinitions.  We set to zero and check for
+   consistency later.  */
+  if (flag_isoc23 && TYPE_VALUES (enumtype) != NULL_TREE)
+   enumtype = NULL_TREE;
+}
+
   if (enumtype == NULL_TREE || TREE_CODE (enumtype) != ENUMERAL_TYPE)
 {
   enumtype = make_node (ENUMERAL_TYPE);
+  TYPE_SIZE (enumtype) = NULL_TREE;
   pushtag (loc, name, enumtype);
   if (fixed_underlying_type != NULL_TREE)
{
@@ -9779,9 +9814,6 @@ start_enum (location_t loc, struct c_enum_contents 
*the_enum, tree na

[PATCH 1/4] c23: tag compatibility rules for struct and unions

2023-11-16 Thread Martin Uecker



Implement redeclaration and compatibility rules for
structures and unions in C23.

gcc/c/:
* c-decl.cc (previous_tag): New function.
(get_parm_info): Turn off warning for C2X.
(start_struct): Allow redefinitons.
(finish_struct): Diagnose conflicts.
* c-tree.h (comptypes_same_p): Add prototype.
* c-typeck.cc (comptypes_same_p): New function
(comptypes_internal): Activate comparison of tagged
types (convert_for_assignment): Ingore qualifiers.
(digest_init): Add error.
(initialized_elementwise_p): Allow compatible types.

gcc/testsuite/:
* gcc.dg/c23-enum-7.c: Remove warning.
* gcc.dg/c23-tag-1.c: New test.
* gcc.dg/c23-tag-2.c: New deactivated test.
* gcc.dg/c23-tag-3.c: New test.
* gcc.dg/c23-tag-4.c: New test.
* gcc.dg/c23-tag-5.c: New deactivated test.
* gcc.dg/c23-tag-6.c: New test.
* gcc.dg/c23-tag-7.c: New test.
* gcc.dg/c23-tag-8.c: New test.
* gcc.dg/gnu23-tag-1.c: New test.
* gcc.dg/gnu23-tag-2.c: New test.
* gcc.dg/gnu23-tag-3.c: New test.
* gcc.dg/gnu23-tag-4.c: New test.
---
 gcc/c/c-decl.cc| 62 ---
 gcc/c/c-tree.h |  1 +
 gcc/c/c-typeck.cc  | 38 +
 gcc/testsuite/gcc.dg/c23-enum-7.c  |  6 +--
 gcc/testsuite/gcc.dg/c23-tag-1.c   | 67 ++
 gcc/testsuite/gcc.dg/c23-tag-2.c   | 43 +++
 gcc/testsuite/gcc.dg/c23-tag-3.c   | 16 +++
 gcc/testsuite/gcc.dg/c23-tag-4.c   | 26 
 gcc/testsuite/gcc.dg/c23-tag-5.c   | 33 +++
 gcc/testsuite/gcc.dg/c23-tag-6.c   | 25 +++
 gcc/testsuite/gcc.dg/c23-tag-7.c   | 12 ++
 gcc/testsuite/gcc.dg/c23-tag-8.c   | 10 +
 gcc/testsuite/gcc.dg/gnu23-tag-1.c | 10 +
 gcc/testsuite/gcc.dg/gnu23-tag-2.c | 19 +
 gcc/testsuite/gcc.dg/gnu23-tag-3.c | 28 +
 gcc/testsuite/gcc.dg/gnu23-tag-4.c | 31 ++
 16 files changed, 411 insertions(+), 16 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-1.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-2.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-3.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-4.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-5.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-6.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-7.c
 create mode 100644 gcc/testsuite/gcc.dg/c23-tag-8.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-1.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-2.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-3.c
 create mode 100644 gcc/testsuite/gcc.dg/gnu23-tag-4.c

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 64d3a941cb9..194dd595334 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -2039,6 +2039,28 @@ locate_old_decl (tree decl)
decl, TREE_TYPE (decl));
 }
 
+
+/* Subroutine of finish_struct.  For a tagged type, it finds the
+   declaration for a visible tag declared in the the same scope
+   if such a declaration exists.  */
+static tree
+previous_tag (tree type)
+{
+  struct c_binding *b = NULL;
+  tree name = TYPE_NAME (type);
+
+  if (name)
+b = I_TAG_BINDING (name);
+
+  if (b)
+b = b->shadowed;
+
+  if (b && B_IN_CURRENT_SCOPE (b))
+return b->decl;
+
+  return NULL_TREE;
+}
+
 /* Subroutine of duplicate_decls.  Compare NEWDECL to OLDDECL.
Returns true if the caller should proceed to merge the two, false
if OLDDECL should simply be discarded.  As a side effect, issues
@@ -8573,11 +8595,14 @@ get_parm_info (bool ellipsis, tree expr)
  if (TREE_CODE (decl) != UNION_TYPE || b->id != NULL_TREE)
{
  if (b->id)
-   /* The %s will be one of 'struct', 'union', or 'enum'.  */
-   warning_at (b->locus, 0,
-   "%<%s %E%> declared inside parameter list"
-   " will not be visible outside of this definition or"
-   " declaration", keyword, b->id);
+   {
+ /* The %s will be one of 'struct', 'union', or 'enum'.  */
+ if (!flag_isoc23)
+   warning_at (b->locus, 0,
+   "%<%s %E%> declared inside parameter list"
+   " will not be visible outside of this 
definition or"
+   " declaration", keyword, b->id);
+   }
  else
/* The %s will be one of 'struct', 'union', or 'enum'.  */
warning_at (b->locus, 0,
@@ -8782,6 +8807,14 @@ start_struct (location_t loc, enum tree_code code, tree 
name,
 
   if (name != NULL_TREE)
 ref = lookup_tag (code, name, true, &refloc);
+
+  /* For C23, even if we already have a completed definition,
+ we do not use it. We will check for consistency later.
+ If we are in a nested red

c23 type compatibility rules, v3

2023-11-16 Thread Martin Uecker


Joseph,

this is another revised series for the C23 rules for type
compatibility.

1/4 c23: tag compatibility rules for struct and unions
2/4 c23: tag compatibility rules for enums
3/4 c23: aliasing of compatible tagged types
4/4 c23: construct composite type for tagged types


The first two were revised to address the nesting (and
other) issues you pointed out.

For 3 and 4 I only changed c2x to c23 and moved some
tests around. 3 wasn't reviewed so far and 4 still
needs some more work from my side.


Bootstrapped and regression tested on x86_64.


Martin








Re: [PATCH] Reduce false positives for -Wnonnull for VLA parameters [PR98541]

2023-11-06 Thread Martin Uecker
Am Montag, dem 06.11.2023 um 21:01 -0700 schrieb Jeff Law:
> 
> On 11/6/23 20:58, Hans-Peter Nilsson wrote:
> > > From: Martin Uecker 
> > > Date: Tue, 31 Oct 2023 20:05:09 +0100
> > 
> > >  Reduce false positives for -Wnonnull for VLA parameters [PR98541]
> > >  
> > >  This patch limits the warning about NULL arguments to VLA
> > >  parameters declared [static n].
> > >  
> > >  PR c/98541
> > >  
> > >  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.
> > 
> > This patch caused a testsuite regression: there's now an
> > "excess error" failure for gcc.dg/Wnonnull-4.c for 32-bit
> > targets (and 64-bit targets testing with a "-m32" option)
> > after your r14-5115-g6e9ee44d96e5.  It's logged as PR112419.
> It caused failures for just about every target ;(  Presumably it worked 
> on x86_64...

I do not think this is a true regression
just a problem with the test on 32-bit which somehow surfaced
due to the change.

The excess error is:

FAIL: gcc.dg/Wnonnull-4.c (test for excess errors)
Excess errors:
/home/tcwg-buildslave/workspace/tcwg_gnu_6/abe/snapshots/gcc.git~master/gcc/testsuite/gcc.dg/Wnonnull-4.c:144:3:
 warning: 'fda_n_5' specified size 4294967256 exceeds maximum object size
2147483647 [-Wstringop-overflow=]

I think the warning was suppressed before due to the other (nonnull)
warning which I removed in this case.

I think the simple fix might be to to turn off -Wstringop-overflow.

Link to the change:
https://gcc.gnu.org/git/gitweb.cgi?p=gcc.git;h=6e9ee44d96e5bda8808dd9d8ccf58d2525383f6b


Martin







> 
> jeff



Re: RFC: the proposal to resolve the missing dependency issue for counted_by attribute

2023-11-02 Thread Martin Uecker
Am Freitag, dem 03.11.2023 um 07:22 +0100 schrieb Jakub Jelinek:
> On Fri, Nov 03, 2023 at 07:07:36AM +0100, Martin Uecker wrote:
> > Am Donnerstag, dem 02.11.2023 um 17:28 -0700 schrieb Bill Wendling:
> > > On Thu, Nov 2, 2023 at 1:36 PM Qing Zhao  wrote:
> > > > 
> > > > Thanks a lot for raising these issues.
> > > > 
> > > > If I understand correctly,  the major question we need to answer is:
> > > > 
> > > > For the following example: (Jakub mentioned this  in an early message)
> > > > 
> > > >   1 struct S { int a; char b __attribute__((counted_by (a))) []; };
> > > >   2 struct S s;
> > > >   3 s.a = 5;
> > > >   4 char *p = &s.b[2];
> > > >   5 int i1 = __builtin_dynamic_object_size (p, 0);
> > > >   6 s.a = 3;
> > > >   7 int i2 = __builtin_dynamic_object_size (p, 0);
> > > > 
> > > > Should the 2nd __bdos call (line 7) get
> > > > A. the latest value of s.a (line 6) for it’s size?
> > > > Or  B. the value when the s.b was referenced (line 3, line 4)?
> > > > 
> > > I personally think it should be (A). The user is specifically
> > > indicating that the size has somehow changed, and the compiler should
> > > behave accordingly.
> > 
> > 
> > One potential problem for A apart from the potential impact on
> > optimization is that the information may get lost more
> > easily. Consider:
> > 
> > char *p = &s.b[2];
> > f(&s);
> > int i = __bdos(p, 0);
> > 
> > If the compiler can not see into 'f', the information is lost
> > because f may have changed the size.
> 
> Why?  It doesn't really matter.  The options are
> A. p is at &s.b[2] associated with &s.a and int type (or size of int
>or whatever); .ACCESS_WITH_SIZE can't be pure, but sure, for aliasing
>POV we can describe it with more detail that it doesn't modify anything
>in the pointed structure, just escapes the pointer; __bdos can stay
>leaf I believe; and when expanding __bdos later on, it would just
>dereference the associated pointer at that point (note, __bdos is
>pure, so it has vuse but not vdef and can load from memory); if
>f changes s.a, no problem, __bdos will load the changed value in there

Ah, I right. Because of the reload it doesn't matter. 
Thank you for the explanation!

Martin

> B. if .ACCESS_WITH_SIZE associates the pointer with the s.a value from that
>point, .ACCESS_WITH_SIZE can be const, but obviously if f changes s.a,
>__bdos later will use s.a value from the &s.b[2] spot



Re: RFC: the proposal to resolve the missing dependency issue for counted_by attribute

2023-11-02 Thread Martin Uecker
Am Donnerstag, dem 02.11.2023 um 17:28 -0700 schrieb Bill Wendling:
> On Thu, Nov 2, 2023 at 1:36 PM Qing Zhao  wrote:
> > 
> > Thanks a lot for raising these issues.
> > 
> > If I understand correctly,  the major question we need to answer is:
> > 
> > For the following example: (Jakub mentioned this  in an early message)
> > 
> >   1 struct S { int a; char b __attribute__((counted_by (a))) []; };
> >   2 struct S s;
> >   3 s.a = 5;
> >   4 char *p = &s.b[2];
> >   5 int i1 = __builtin_dynamic_object_size (p, 0);
> >   6 s.a = 3;
> >   7 int i2 = __builtin_dynamic_object_size (p, 0);
> > 
> > Should the 2nd __bdos call (line 7) get
> > A. the latest value of s.a (line 6) for it’s size?
> > Or  B. the value when the s.b was referenced (line 3, line 4)?
> > 
> I personally think it should be (A). The user is specifically
> indicating that the size has somehow changed, and the compiler should
> behave accordingly.


One potential problem for A apart from the potential impact on
optimization is that the information may get lost more
easily. Consider:

char *p = &s.b[2];
f(&s);
int i = __bdos(p, 0);

If the compiler can not see into 'f', the information is lost
because f may have changed the size.

And if I understand it correctly, if the pointers escapes
with .ACCESS_WITH_SIZE, then this is already true for:

char *p = &s.b[2];
g();
int i = __bdos(p, 0);


If we make it UB to change the size, then I guess we could
also delay this choice.  Or we implement B but have a UBSan
option based on A that only verifies at run-time that the size 
did not change.


Martin


> 
> > A should be more convenient for the user to use the dynamic array feature.
> > With B, the user has to modify the source code (to add code to “re-obtain”
> > the pointer after the size was adjusted at line 6) as mentioned by Richard.
> > 
> > This depends on how we design the new internal function .ACCESS_WITH_SIZE
> > 
> > 1. Size is passed by value to .ACCESS_WITH_SIZE as we currently designed.
> > 
> > PTR = .ACCESS_WITH_SIZE (PTR, SIZE, ACCESS_MODE)
> > 
> > 2. Size is passed by reference to .ACCESS_WITH_SIZE as Jakub suggested.
> > 
> > PTR = .ACCESS_WITH_SIZE(PTR, &SIZE, TYPEOFSIZE, ACCESS_MODE)
> > 
> > With 1, We can only provide B, the user needs to modify the source code to 
> > get the full feature of dynamic array;
> > With 2, We can provide  A, the user will get full support to the dynamic 
> > array without restrictions in the source code.
> > 
> My understanding of ACCESS_WITH_SIZE is that it's there to add an
> explicit reference to SIZE so that the optimizers won't reorder the
> code incorrectly. If that's the case, then it should act as if
> ACCESS_WITH_SIZE wasn't even there (i.e. it's just a pointer
> dereference into the FAM). We get that with (2) it appears. It would
> be a major headache to make the user go throughout their code base to
> ensure that SIZE was either unmodified, or if it was that extra code
> must be added to ensure the expected behavior.
> 
> > However, We have to pay additional cost for supporting A by using 2, which 
> > includes:
> > 
> > 1. .ACCESS_WITH_SIZE will become an escape point, which will further impact 
> > the IPA optimizations, more runtime overhead.
> > Then .ACCESS_WTH_SIZE will not be CONST, right? But it will still be 
> > PURE?
> > 
> > 2. __builtin_dynamic_object_size will NOT be LEAF anymore.  This will also 
> > impact some IPA optimizations, more runtime overhead.
> > 
> > I think the following are the factors that make the decision:
> > 
> > 1. How big the performance impact?
> > 2. How important the dynamic array feature? Is adding some user 
> > restrictions as Richard mentioned feasible to support this feature?
> > 
> > Maybe we can implement 1 first, if the full support to the dynamic array is 
> > needed, we can add 2 then?
> > Or, we can implement both, and compare the performance difference, then 
> > decide?
> > 
> > Qing
> > 



Re: RFC: the proposal to resolve the missing dependency issue for counted_by attribute

2023-11-02 Thread Martin Uecker
Am Donnerstag, dem 02.11.2023 um 13:50 + schrieb Qing Zhao:
> 
> > On Nov 2, 2023, at 3:57 AM, Richard Biener  
> > wrote:
> > 
> > On Wed, Nov 1, 2023 at 3:47 PM Qing Zhao  wrote:
> > > 
> > > 
> > > 
> > > > On Oct 31, 2023, at 6:14 PM, Joseph Myers  
> > > > wrote:
> > > > 
> > > > On Tue, 31 Oct 2023, Qing Zhao wrote:
> > > > 
> > > > > 2.3 A new semantic requirement in the user documentation of 
> > > > > "counted_by"
> > > > > 
> > > > > For the following structure including a FAM with a counted_by 
> > > > > attribute:
> > > > > 
> > > > > struct A
> > > > > {
> > > > >  size_t size;
> > > > >  char buf[] __attribute__((counted_by(size)));
> > > > > };
> > > > > 
> > > > > for any object with such type:
> > > > > 
> > > > > struct A *obj = __builtin_malloc (sizeof(struct A) + sz * 
> > > > > sizeof(char));
> > > > > 
> > > > > The setting to the size field should be done before the first 
> > > > > reference
> > > > > to the FAM field.
> > > > > 
> > > > > Such requirement to the user will guarantee that the first reference 
> > > > > to
> > > > > the FAM knows the size of the FAM.
> > > > > 
> > > > > We need to add this additional requirement to the user document.
> > > > 
> > > > Make sure the manual is very specific about exactly when size is
> > > > considered to be an accurate representation of the space available for 
> > > > buf
> > > > (given that, after malloc or realloc, it's going to be temporarily
> > > > inaccurate).  If the intent is that inaccurate size at such a time means
> > > > undefined behavior, say so explicitly.
> > > 
> > > Yes, good point. We need to define this clearly in the beginning.
> > > We need to explicit say that
> > > 
> > > the size of the FAM is defined by the latest “counted_by” value. And it’s 
> > > an undefined behavior when the size field is not defined when the FAM is 
> > > referenced.
> > > 
> > > Is the above good enough?
> > > 
> > > 
> > > > 
> > > > > 2.4 Replace FAM field accesses with the new function ACCESS_WITH_SIZE
> > > > > 
> > > > > In C FE:
> > > > > 
> > > > > for every reference to a FAM, for example, "obj->buf" in the small 
> > > > > example,
> > > > > check whether the corresponding FIELD_DECL has a "counted_by" 
> > > > > attribute?
> > > > > if YES, replace the reference to "obj->buf" with a call to
> > > > > .ACCESS_WITH_SIZE (obj->buf, obj->size, -1);
> > > > 
> > > > This seems plausible - but you should also consider the case of static
> > > > initializers - remember the GNU extension for statically allocated 
> > > > objects
> > > > with flexible array members (unless you're not allowing it with
> > > > counted_by).
> > > > 
> > > > static struct A x = { sizeof "hello", "hello" };
> > > > static char *y = &x.buf;
> > > > 
> > > > I'd expect that to be valid - and unless you say such a usage is 
> > > > invalid,
> > > 
> > > At this moment, I think that this should be valid.
> > > 
> > > I,e, the following:
> > > 
> > > struct A
> > > {
> > > size_t size;
> > > char buf[] __attribute__((counted_by(size)));
> > > };
> > > 
> > > static struct A x = {sizeof "hello", "hello”};
> > > 
> > > Should be valid, and x.size represents the number of elements of x.buf.
> > > Both x.size and x.buf are initialized statically.
> > > 
> > > > you should avoid the replacement in such a static initializer context 
> > > > when
> > > > the FAM reference is to an object with a constant address (if
> > > > .ACCESS_WITH_SIZE would not act as an lvalue whose address is a constant
> > > > expression; if it works fine as a constant-address lvalue, then the
> > > > replacement would be OK).
> > > 
> > > Then if such usage for the “counted_by” is valid, we need to replace the 
> > > FAM
> > > reference by a call to  .ACCESS_WITH_SIZE as well.
> > > Otherwise the “counted_by” relationship will be lost to the Middle end.
> > > 
> > > With the current definition of .ACCESS_WITH_SIZE
> > > 
> > > PTR = .ACCESS_WITH_SIZE (PTR, SIZE, ACCESS_MODE)
> > > 
> > > Isn’t the PTR (return value of the call) a LVALUE?
> > 
> > You probably want to specify that when a pointer to the array is taken the
> > pointer has to be to the first array element (or do we want to mangle the
> > 'size' accordingly for the instrumentation?).
> 
> Yes. Will add this into the user documentation.

This shouldn't be necessary. The object-size pass
can track pointer arithmeti if it comes after
inserting the .ACCESS_WITH_SIZE.

https://godbolt.org/z/fvc3aoPfd

> 
> >  You also want to specify that
> > the 'size' associated with such pointer is assumed to be unchanging and
> > after changing the size such pointer has to be re-obtained.
> 
> What do you mean by “re-obtained”? 
> 
> >  Plus that
> > changes to the allocated object/size have to be performed through an
> > lvalue where the containing type and thus the 'counted_by' attribute is
> > visible.
> 
> Through an lvalue with the containing type?
> 
> Yes, will add this too. 

I do not understand this.  It shouldn't matter how
it is

Re: Help: which routine in C FE I should look at for the reference to a FAM field?

2023-11-01 Thread Martin Uecker
Am Mittwoch, dem 01.11.2023 um 18:14 + schrieb Qing Zhao:
> Joseph and Martin,
> 
> For the task to replace every reference to a FAM field with an call to 
> .ACCESS_WITH_SIZE, 
> Where in the C FE I should look at?
> 
> Thanks a lot for the help.
> 
> 

build_component_ref in c_decl.cc

Martin

> Qing



Re: [PING] [C PATCH, v2] Add Walloc-size to warn about insufficient size in allocations [PR71219]

2023-11-01 Thread Martin Uecker
Am Dienstag, dem 31.10.2023 um 22:19 + schrieb Joseph Myers:
> On Tue, 31 Oct 2023, Martin Uecker wrote:
> 
> > > +   if (TREE_CODE (arg) == INTEGER_CST
> > > +   && tree_int_cst_lt (arg, TYPE_SIZE_UNIT (ttl)))
> 
> What if TYPE_SIZE_UNIT (ttl) is not an INTEGER_CST?  I don't see any tests 
> of the case of assigning to a pointer to a variably sized type.
> 

Right. Thanks! Revised version attached.

Martin



c: Add Walloc-size to warn about insufficient size in allocations [PR71219]

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

PR c/71219
gcc:
* doc/invoke.texi: Document -Walloc-size option.

gcc/c-family:

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

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

gcc/testsuite:

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

diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 44b9c862c14..29d3d789a49 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -331,6 +331,10 @@ Walloca
 C ObjC C++ ObjC++ Var(warn_alloca) Warning
 Warn on any use of alloca.
 
+Walloc-size
+C ObjC Var(warn_alloc_size) Warning LangEnabledBy(C ObjC, Wextra)
+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 0de4662bfc6..16fadfb5468 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -7347,6 +7347,34 @@ 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 that are not big enough for the target
+type.  */
+  tree fndecl;
+  if (warn_alloc_size
+ && 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
+ && INTEGER_CST == TREE_CODE (TYPE_SIZE_UNIT (ttl))
+ && tree_int_cst_lt (arg, TYPE_SIZE_UNIT (ttl)))
+warning_at (location, OPT_Walloc_size, "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 5a9284d635c..815a33d4b87 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -8138,6 +8138,16 @@ 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-size
+@opindex Walloc-size
+@item -Walloc-size
+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-size-1.c 
b/gcc/testsuite/gcc.dg/Walloc-size-1.c
new file mode 100644
index 000..61806f58192
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Walloc-size-1.c
@@ -0,0 +1,36 @@
+/* Tests the warnings for insufficient allocation size.
+   { dg-do compile }
+   { dg-options "-Walloc-size" }
+ * */
+#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-

Re: RFC: the proposal to resolve the missing dependency issue for counted_by attribute

2023-11-01 Thread Martin Uecker
Am Mittwoch, dem 01.11.2023 um 14:47 + schrieb Qing Zhao:
> 
> > On Oct 31, 2023, at 6:14 PM, Joseph Myers  wrote:
> > 
> > On Tue, 31 Oct 2023, Qing Zhao wrote:
> > 
> > > 2.3 A new semantic requirement in the user documentation of "counted_by"
> > > 
> > > For the following structure including a FAM with a counted_by attribute:
> > > 
> > >  struct A
> > >  {
> > >   size_t size;
> > >   char buf[] __attribute__((counted_by(size)));
> > >  };
> > > 
> > > for any object with such type:
> > > 
> > >  struct A *obj = __builtin_malloc (sizeof(struct A) + sz * sizeof(char));
> > > 
> > > The setting to the size field should be done before the first reference 
> > > to the FAM field.
> > > 
> > > Such requirement to the user will guarantee that the first reference to 
> > > the FAM knows the size of the FAM.
> > > 
> > > We need to add this additional requirement to the user document.
> > 
> > Make sure the manual is very specific about exactly when size is 
> > considered to be an accurate representation of the space available for buf 
> > (given that, after malloc or realloc, it's going to be temporarily 
> > inaccurate).  If the intent is that inaccurate size at such a time means 
> > undefined behavior, say so explicitly.
> 
> Yes, good point. We need to define this clearly in the beginning. 
> We need to explicit say that 
> 
> the size of the FAM is defined by the latest “counted_by” value. And it’s an 
> undefined behavior when the size field is not defined when the FAM is 
> referenced.

It is defined by the latest "counted_by" value before x.buf
is referenced, but not the latest before x.buf is dereferenced.

> 
> Is the above good enough?
> 
> 
> > 
> > > 2.4 Replace FAM field accesses with the new function ACCESS_WITH_SIZE
> > > 
> > > In C FE:
> > > 
> > > for every reference to a FAM, for example, "obj->buf" in the small 
> > > example,
> > >  check whether the corresponding FIELD_DECL has a "counted_by" attribute?
> > >  if YES, replace the reference to "obj->buf" with a call to
> > >  .ACCESS_WITH_SIZE (obj->buf, obj->size, -1); 
> > 
> > This seems plausible - but you should also consider the case of static 
> > initializers - remember the GNU extension for statically allocated objects 
> > with flexible array members (unless you're not allowing it with 
> > counted_by).
> > 
> > static struct A x = { sizeof "hello", "hello" };
> > static char *y = &x.buf;
> > 
> > I'd expect that to be valid - and unless you say such a usage is invalid, 
> 
> At this moment, I think that this should be valid.
> 
> I,e, the following:
> 
> struct A
> {
>  size_t size;
>  char buf[] __attribute__((counted_by(size)));
> };
> 
> static struct A x = {sizeof "hello", "hello”};
> 
> Should be valid, and x.size represents the number of elements of x.buf. 
> Both x.size and x.buf are initialized statically. 

Joseph is talking about the compile-time initialization of y.

> 
> > you should avoid the replacement in such a static initializer context when 
> > the FAM reference is to an object with a constant address (if 
> > .ACCESS_WITH_SIZE would not act as an lvalue whose address is a constant 
> > expression; if it works fine as a constant-address lvalue, then the 
> > replacement would be OK).
> 
> Then if such usage for the “counted_by” is valid, we need to replace the FAM 
> reference by a call to  .ACCESS_WITH_SIZE as well.
> Otherwise the “counted_by” relationship will be lost to the Middle end. 
> 
> With the current definition of .ACCESS_WITH_SIZE
> 
> PTR = .ACCESS_WITH_SIZE (PTR, SIZE, ACCESS_MODE)
> 
> Isn’t the PTR (return value of the call) a LVALUE? 

The question is whether we get an address constant
that can be used for compile-time initialization.

I think it would be good to collect a list of test
cases and to include this example.

Martin

> 
> Qing
> > 
> > -- 
> > Joseph S. Myers
> > jos...@codesourcery.com
> 



RFC [PATCH] c: Add missing cases where vla sizes are not instrumented by UBSan [PR98608]

2023-11-01 Thread Martin Uecker



Here is a patch that adds the missing cases for vla size instrumentation.
This now includes all cases where a type with size < 0 is created,
which is already UB and not just cases where a VLA is allocated.  But
a VLA can be allocated based on an typedef, which is also now
indirectly protected in this way.

I moved the instrumentation from the size itself as its own term into 
the expression that evaluate size expressions for side effects. This
avoids confusing other warning code that looks at the size expressions
(-Wvla-parameter).

There is one open question though:  How to to treat n == 0? 

Here I preliminary changed this to n > 0 (also for the existing case),
because when also detecting n == 0 this tools especially when
instrumenting all the types becomes basically useless because of 
the very common (and unproblematic) use of n == 0.  

But strictly speaking n == 0 is also UB and as pointed out in  PR98609
the error message is then not entirely accurate because it says
non-positive and not negative. I do not think it is confusing though
because it is still always correct.

One could consider splitting it up into vla-bound / vla-bound-strict,
but changing the error message would require further upstream changes
and dealing with this far exceeds the time I can afford contributing
to this this.

Another complication is that we ran out of bits for sanitizer flags in
unsigned int, so this would also require more changes.

Any advice?


I think it would be important to have complete UBSan coverage for all
size and bounds issues related to VM types and it would be nice to
get this in GCC 14. (I find this extremely useful in my projects).

Martin




c: Add missing cases where vla sizes are not instrumented by UBSan [PR98608]

Add vla-bound instrumentation for all VLAs including VLAs in parameters
and fields, but allow zero-sized errors.

Bootstrapped and regression tested on x86.

PR c/98608

gcc/c:
* c-decl.cc (grokdeclarator): Instrument all VLAs.

gcc/c-family:
* c-ubsan.cc (ubsan_instrument_vla): Do not include zero length.

gcc/testsuite:
* gcc.dg/ubsan/pr89608.c: New test.
* gcc.dg/ubsan/vla-1.c: New test.
* gcc.dg/ubsan/vla-2.c: New test.
* gcc.dg/ubsan/vla-3.c: New test.
* c-c++-common/ubsan/vla-1.c: Adapt.

diff --git a/gcc/c-family/c-ubsan.cc b/gcc/c-family/c-ubsan.cc
index b2c58c65d97..8983ede0166 100644
--- a/gcc/c-family/c-ubsan.cc
+++ b/gcc/c-family/c-ubsan.cc
@@ -313,7 +313,7 @@ ubsan_instrument_vla (location_t loc, tree size)
   tree type = TREE_TYPE (size);
   tree t, tt;
 
-  t = fold_build2 (LE_EXPR, boolean_type_node, size, build_int_cst (type, 0));
+  t = fold_build2 (LT_EXPR, boolean_type_node, size, build_int_cst (type, 0));
   if (flag_sanitize_trap & SANITIZE_VLA)
 tt = build_call_expr_loc (loc, builtin_decl_explicit (BUILT_IN_TRAP), 0);
   else
diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 7a145bed281..752a65d6729 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -7201,16 +7201,20 @@ grokdeclarator (const struct c_declarator *declarator,
   with known value.  */
this_size_varies = size_varies = true;
warn_variable_length_array (name, size);
-   if (sanitize_flags_p (SANITIZE_VLA)
-   && current_function_decl != NULL_TREE
-   && decl_context == NORMAL)
+   if (sanitize_flags_p (SANITIZE_VLA))
  {
/* Evaluate the array size only once.  */
size = save_expr (size);
size = c_fully_fold (size, false, NULL);
-   size = fold_build2 (COMPOUND_EXPR, TREE_TYPE (size),
-   ubsan_instrument_vla (loc, size),
-   size);
+   tree instr = ubsan_instrument_vla (loc, size);
+   /* We have to build this in the right order, so
+  instrumentation is done before the size can
+  be used in other parameters.  */
+   if (*expr)
+ *expr = build2 (COMPOUND_EXPR, TREE_TYPE (instr),
+ *expr, instr);
+   else
+ *expr = instr;
  }
  }
 
diff --git a/gcc/testsuite/c-c++-common/ubsan/vla-1.c 
b/gcc/testsuite/c-c++-common/ubsan/vla-1.c
index c97465edae1..cc441ffc80b 100644
--- a/gcc/testsuite/c-c++-common/ubsan/vla-1.c
+++ b/gcc/testsuite/c-c++-common/ubsan/vla-1.c
@@ -110,9 +110,7 @@ main (void)
 /* { dg-output "\[^\n\r]*variable length array bound evaluates to non-positive 
value -1\[^\n\r]*(\n|\r\n|\r)" } */
 /* { dg-output "\[^\n\r]*variable length array bound evaluates to non-positive 
value 

[PATCH] Reduce false positives for -Wnonnull for VLA parameters [PR98541]

2023-10-31 Thread Martin Uecker


This is a revised part of previously posted patch which
I split up. C FE changes which another false positive
were already merged, but I still need approval for this
 middle-end change.  It would be nice to get this in,
because it fixes some rather annoying (for me atleast)
false positive warnings with no easy workaround.

In the following example,

int foo(int n, float matrix[n], float opt[n]);
foo(n, matrix, NULL);

GCC warns about NULL iff n > 0.  This is problematic for
several reasons:
1. It causes false positives (and I turn off -Wnonnull
in one of my projects for this reason)
2. It is inconsistent with regular arrays where there is no
warning in this case.
3. The size parameter is sometimes shared (as in this example)
so passing zero to avoid the warning is only possible by
making the code more complex.
4. Passing zero as a workaround is technically UB.


(The original author of the warning code, Martin S seemed to 
agree with this change according to this discussion in Bugzilla.)



Reduce false positives for -Wnonnull for VLA parameters [PR98541]

This patch limits the warning about NULL arguments to VLA
parameters declared [static n].

PR c/98541

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.

diff --git a/gcc/gimple-ssa-warn-access.cc b/gcc/gimple-ssa-warn-access.cc
index e439d1b9b68..8b734295f09 100644
--- a/gcc/gimple-ssa-warn-access.cc
+++ b/gcc/gimple-ssa-warn-access.cc
@@ -3477,27 +3477,14 @@ pass_waccess::maybe_check_access_sizes (rdwr_map *rwm, 
tree fndecl, tree fntype,
 
   if (integer_zerop (ptr))
{
- if (sizidx >= 0 && tree_int_cst_sgn (sizrng[0]) > 0)
+ if (!access.second.internal_p
+ && sizidx >= 0 && tree_int_cst_sgn (sizrng[0]) > 0)
{
  /* Warn about null pointers with positive sizes.  This is
 different from also declaring the pointer argument with
 attribute nonnull when the function accepts null pointers
 only when the corresponding size is zero.  */
- if (access.second.internal_p)
-   {
- const std::string argtypestr
-   = access.second.array_as_string (ptrtype);
-
- if (warning_at (loc, OPT_Wnonnull,
- "argument %i of variable length "
- "array %s is null but "
- "the corresponding bound argument "
- "%i value is %s",
- ptridx + 1, argtypestr.c_str (),
- sizidx + 1, sizstr))
-   arg_warned = OPT_Wnonnull;
-   }
- else if (warning_at (loc, OPT_Wnonnull,
+ if (warning_at (loc, OPT_Wnonnull,
   "argument %i is null but "
   "the corresponding size argument "
   "%i value is %s",
diff --git a/gcc/testsuite/gcc.dg/Wnonnull-4.c 
b/gcc/testsuite/gcc.dg/Wnonnull-4.c
index 2c1c45a9856..1f14fbba45d 100644
--- a/gcc/testsuite/gcc.dg/Wnonnull-4.c
+++ b/gcc/testsuite/gcc.dg/Wnonnull-4.c
@@ -27,9 +27,9 @@ void test_fca_n (int r_m1)
   T (  0);
 
   // Verify positive bounds.
-  T (  1);  // { dg-warning "argument 2 of variable length array 
'char\\\[n]' is null but the corresponding bound argument 1 value is 1" }
-  T (  9);  // { dg-warning "argument 2 of variable length array 
'char\\\[n]' is null but the corresponding bound argument 1 value is 9" }
-  T (max);  // { dg-warning "argument 2 of variable length array 
'char\\\[n]' is null but the corresponding bound argument 1 value is \\d+" }
+  T (  1);  // { dg-bogus "argument 2 of variable length array 
'char\\\[n]' is null but the corresponding bound argument 1 value is 1" }
+  T (  9);  // { dg-bogus "argument 2 of variable length array 
'char\\\[n]' is null but the corresponding bound argument 1 value is 9" }
+  T (max);  // { dg-bogus "argument 2 of variable length array 
'char\\\[n]' is null but the corresponding bound argument 1 value is \\d+" }
 }
 
 
@@ -55,9 +55,9 @@ void test_fsa_x_n (int r_m1)
   T (  0);
 
   // Verify positive bounds.
-  T (  1);  // { dg-warning "argument 2 of variable length array 
'short int\\\[]\\\[n]' is null but the corresponding bound argument 1 value is 
1" }
-  T (  9);  // { dg-warning "argument 2 of variable length array 
'short int\\\[]\\\[n]' is null but the corresponding bound argument 1 value is 
9" }
-  T (max);  // { dg-warning "argument 2 of variable length array 
'short int\\\[]\\\[n]' is null

[PING] [C PATCH, v2] Add Walloc-size to warn about insufficient size in allocations [PR71219]

2023-10-31 Thread Martin Uecker
Am Montag, dem 18.09.2023 um 23:26 +0200 schrieb Martin Uecker:
> 
> Compared to the previous version I changed the name of the
> warning to "Walloc-size" which matches "Wanalyzer-allocation-size"
> but is still in line with the other -Walloc-something warnings
> we have. I also added it to Wextra.
> 
> I found PR71219 that requests the warning and points out that 
> it is recommended by the C secure coding guidelines and added
> the PR to the commit log  (although the version with cast is not
> diagnosed so far.)  
> 
> I did not have time to implement the extensions suggested
> on the list,  i.e. warn when the size is not a multiple
> of the size of the type and warn for if the size is not
> suitable for a flexible array member. (this is also a bit
> more complicated than it seems)
> 
> Bootstrapped and regression tested on x86_64.
> 
> 
> Martin
> 
> 
> Add option Walloc-size that warns about allocations that have
> insufficient storage for the target type of the pointer the
> storage is assigned to.
> 
>   PR c/71219
> gcc:
>   * doc/invoke.texi: Document -Walloc-size option.
> 
> gcc/c-family:
> 
>   * c.opt (Walloc-size): New option.
> 
> gcc/c:
>   * c-typeck.cc (convert_for_assignment): Add warning.
> 
> gcc/testsuite:
> 
>   * gcc.dg/Walloc-size-1.c: New test.
> ---
>  gcc/c-family/c.opt   |  4 
>  gcc/c/c-typeck.cc| 27 +
>  gcc/doc/invoke.texi  | 10 
>  gcc/testsuite/gcc.dg/Walloc-size-1.c | 36 
>  4 files changed, 77 insertions(+)
>  create mode 100644 gcc/testsuite/gcc.dg/Walloc-size-1.c
> 
> diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
> index 7348ad42ee0..9ba08a1fb6d 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-size
> +C ObjC Var(warn_alloc_size) 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 e2bfd2caf85..c759c6245ed 100644
> --- a/gcc/c/c-typeck.cc
> +++ b/gcc/c/c-typeck.cc
> @@ -7384,6 +7384,33 @@ 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 that are not big enough for the target
> +  type.  */
> +  tree fndecl;
> +  if (warn_alloc_size
> +   && 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_size, "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 33befee7d6b..a4fbcf5e1b5 100644
> --- a/gcc/doc/invoke.texi
> +++ b/gcc/doc/invoke.texi
> @@ -8086,6 +8086,16 @@ 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-size
> +@opindex Walloc-size
> +@item -Walloc-size
> +Warn about calls to allocation functions decorated 

Re: [PATCH] tree-optimization/109334: Improve computation for access attribute

2023-10-28 Thread Martin Uecker


Thanks, Sid!

(one comment below)

Am Donnerstag, dem 26.10.2023 um 07:51 -0400 schrieb Siddhesh Poyarekar:
> On 2023-10-26 04:37, Martin Uecker wrote:

> 
> > /* ... and either PARM is void * or has a type that is complete and 
> > has a
> >  constant size... */
> > && ((typesize && poly_int_tree_p (typesize))
> > @@ -1587,10 +1587,14 @@ parm_object_size (struct object_size_info *osi, 
> > tree var)
> > unsigned argpos = 0;
> >   
> > /* ... then walk through the parameters to pick the size parameter 
> > and
> > -safely scale it by the type size if needed.  */
> > +safely scale it by the type size if needed.
> > +
> > +TODO: we could also compute the size of VLAs where the size is
> > +given by a function parameter.  */
> 
> Isn't this testcase h() in builtin-dynamic-object-size-20.c?  If you're 
> referring to testcase i(), then maybe "where the size is given by a 
> non-trivial function of a function parameter, e.g.
> fn (size_t n, char buf[dummy(n)])."

h() is supported.  For i() we would need something as
__builtin_access__with_size to record the result of dummy().

But the comment refers to the simpler case:

fn (size_t n, char (*buf)[n])
[[gnu::access(read_write, 2, 1)]]

This doesn't work because buf[n] does not have constant
size, but it could be made to work more easily because
the size is directly given by a function argument.

Martin


> 
> > for (arg = fnargs; arg; arg = TREE_CHAIN (arg), ++argpos)
> > -   if (argpos == access->sizarg && INTEGRAL_TYPE_P (TREE_TYPE (arg)))
> > +   if (argpos == access->sizarg)
> >   {
> > +   gcc_assert (INTEGRAL_TYPE_P (TREE_TYPE (arg)));
> > sz = get_or_create_ssa_default_def (cfun, arg);
> > if (sz != NULL_TREE)
> >   {
> > 
> 
> We rely on the frontend to make sure that the arg at sizarg is an 
> integral type.  OK.
> 
> Overall the change looks OK with a few nits I pointed out above.
> 
> Thanks,
> Sid



Re: HELP: Will the reordering happen? Re: [V3][PATCH 0/3] New attribute "counted_by" to annotate bounds for C99 FAM(PR108896)

2023-10-27 Thread Martin Uecker
Am Freitag, dem 27.10.2023 um 14:32 + schrieb Qing Zhao:
> 
> > On Oct 27, 2023, at 3:21 AM, Martin Uecker  wrote:
> > 
> > Am Donnerstag, dem 26.10.2023 um 19:57 + schrieb Qing Zhao:
> > > I guess that what Kees wanted, ""fill the array without knowing the 
> > > actual final size" code pattern”, as following:
> > > 
> > > > >   struct foo *f;
> > > > >   char *p;
> > > > >   int i;
> > > > > 
> > > > >   f = alloc(maximum_possible);
> > > > >   f->count = 0;
> > > > >   p = f->buf;
> > > > > 
> > > > >   for (i; data_is_available() && i < maximum_possible; i++) {
> > > > >   f->count ++;
> > > > >   p[i] = next_data_item();
> > > > >   }
> > > 
> > > actually is a dynamic array, or more accurately, Bounded-size dynamic 
> > > array: ( but not a dynamic allocated array as we discussed so far)
> > > 
> > > https://en.wikipedia.org/wiki/Dynamic_array
> > > 
> > > This dynamic array, also is called growable array, or resizable array, 
> > > whose size can 
> > > be changed during the lifetime. 
> > > 
> > > For VLA or FAM, I believe that they are both dynamic allocated array, 
> > > i.e, even though the size is not know at the compilation time, but the 
> > > size
> > > will be fixed after the array is allocated. 
> > > 
> > > I am not sure whether C has support to such Dynamic array? Or whether 
> > > it’s easy to provide dynamic array support in C?
> > 
> > It is possible to support dynamic arrays in C even with
> > good checking, but not safely using the pattern above
> > where you derive a pointer which you later use independently.
> > 
> > While we could track the connection to the original struct,
> > the necessary synchronization between the counter and the
> > access to the buffer is difficult.  I do not see how this
> > could be supported with reasonable effort and cost.
> > 
> > 
> > But with this restriction in mind, we can do a lot in C.
> > For example, see my experimental (!) container library
> > which has vector type.
> > https://github.com/uecker/noplate/blob/main/test.c
> > You can get an array view for the vector (which then
> > also can decay to a pointer), so it interoperates nicely
> > with C but you can get good bounds checking.
> > 
> > 
> > But once you derive a pointer and pass it on, it gets
> > difficult.  But if you want safety, you just have to 
> > to simply avoid this in code. 
> 
> So, for the following modified code: (without the additional pointer “p”)
> 
> struct foo
> {
>  size_t count;
>  char buf[] __attribute__((counted_by(count)));
> };
> 
> struct foo *f;
> int i;  
> 
> f = alloc(maximum_possible);
> f->count = 0;
> 
> for (i; data_is_available() && i < maximum_possible; i++) {
>   f->count ++;  
>   f->buf[i] = next_data_item();
> }   
> 
> The support for dynamic array should be possible? 

With the design we discussed this should work because
__builtin_with_access (or whatever) it reads:

f = alloc(maximum_possible);
f->count = 0;

for (i; data_is_available() && i < maximum_possible; i++) {
  f->count ++;  
  __builtin_with_access(f->buf, f->count)[i] = next_data_item();
}   

> 
> 
> > 
> > What we could potentially do is add restrictions so 
> > that the access to buf always has to go via x->buf 
> > or you get at least a warning.
> 
> Are the following two restrictions to the user enough:
> 
> 1. The access to buf should always go via x->buf, 
> no assignment to another independent pointer 
> and access buf through this new pointer.

Yes, maybe. One could also try to be smarter.

For example, one warn only when &f->buf is
assigned to another pointer and one of the
following conditions is fulfilled:

- the pointer escapes from the local context 

- there is a store to f->counter in the
local context that does not dominate &f->buf.

Then Kees' example would work too in most cases.

But I would probably wait until we have some
initial experience with this feature.

Martin

> 2.  User need to keep the synchronization between
>   the counter and the access to the buffer all the time.



> 
> 


Re: HELP: Will the reordering happen? Re: [V3][PATCH 0/3] New attribute "counted_by" to annotate bounds for C99 FAM(PR108896)

2023-10-27 Thread Martin Uecker
Am Donnerstag, dem 26.10.2023 um 19:57 + schrieb Qing Zhao:
> I guess that what Kees wanted, ""fill the array without knowing the actual 
> final size" code pattern”, as following:
> 
> > >   struct foo *f;
> > >   char *p;
> > >   int i;
> > > 
> > >   f = alloc(maximum_possible);
> > >   f->count = 0;
> > >   p = f->buf;
> > > 
> > >   for (i; data_is_available() && i < maximum_possible; i++) {
> > >   f->count ++;
> > >   p[i] = next_data_item();
> > >   }
> 
> actually is a dynamic array, or more accurately, Bounded-size dynamic array: 
> ( but not a dynamic allocated array as we discussed so far)
> 
> https://en.wikipedia.org/wiki/Dynamic_array
> 
> This dynamic array, also is called growable array, or resizable array, whose 
> size can 
> be changed during the lifetime. 
> 
> For VLA or FAM, I believe that they are both dynamic allocated array, i.e, 
> even though the size is not know at the compilation time, but the size
> will be fixed after the array is allocated. 
> 
> I am not sure whether C has support to such Dynamic array? Or whether it’s 
> easy to provide dynamic array support in C?

It is possible to support dynamic arrays in C even with
good checking, but not safely using the pattern above
where you derive a pointer which you later use independently.

While we could track the connection to the original struct,
the necessary synchronization between the counter and the
access to the buffer is difficult.  I do not see how this
could be supported with reasonable effort and cost.
 

But with this restriction in mind, we can do a lot in C.
For example, see my experimental (!) container library
which has vector type.
https://github.com/uecker/noplate/blob/main/test.c
You can get an array view for the vector (which then
also can decay to a pointer), so it interoperates nicely
with C but you can get good bounds checking.


But once you derive a pointer and pass it on, it gets
difficult.  But if you want safety, you just have to 
to simply avoid this in code. 

What we could potentially do is add restrictions so 
that the access to buf always has to go via x->buf 
or you get at least a warning.

Martin




> 
> Qing
> 
> 
> > On Oct 26, 2023, at 12:45 PM, Martin Uecker  wrote:
> > 
> > Am Donnerstag, dem 26.10.2023 um 09:13 -0700 schrieb Kees Cook:
> > > On Thu, Oct 26, 2023 at 10:15:10AM +0200, Martin Uecker wrote:
> > > > but not this:
> > > > 
> > 
> > x->count = 11;
> > > > char *p = &x->buf;
> > > > x->count = 1;
> > > > p[10] = 1; // !
> > > 
> > > This seems fine to me -- it's how I'd expect it to work: "10" is beyond
> > > "1".
> > 
> > Note that the store would be allowed.
> > 
> > > 
> > > > (because the pointer is passed around the
> > > > store to the counter)
> > > > 
> > > > and also here the second store is then irrelevant
> > > > for the access:
> > > > 
> > > > x->count = 10;
> > > > char* p = &x->buf;
> > > > ...
> > > > x->count = 1; // somewhere else
> > > > 
> > > > p[9] = 1; // ok, because count matter when buf was accesssed.
> > > 
> > > This is less great, but I can understand why it happens. "p" loses the
> > > association with "x". It'd be nice if "p" had to way to retain that it
> > > was just an alias for x->buf, so future p access would check count.
> > 
> > The problem is not to discover that p is an alias to x->buf, 
> > but that it seems difficult to make sure that stores to 
> > x->count are not reordered relative to the final access to
> > p[i] you want to check, so that you then get the right value.
> > 
> > > 
> > > But this appears to be an existing limitation in other areas where an
> > > assignment will cause the loss of object association. (I've run into
> > > this before.) It's just more surprising in the above example because in
> > > the past the loss of association would cause __bdos() to revert back to
> > > "SIZE_MAX" results ("I don't know the size") rather than an "outdated"
> > > size, which may get us into unexpected places...
> > > 
> > > > IMHO this makes sense also from the user side and
> > > > are the desirable semantics we discussed before.
> > > > 
> > > > But can you take a look at

Re: HELP: Will the reordering happen? Re: [V3][PATCH 0/3] New attribute "counted_by" to annotate bounds for C99 FAM(PR108896)

2023-10-26 Thread Martin Uecker
Am Donnerstag, dem 26.10.2023 um 16:41 + schrieb Qing Zhao:
> 
> > On Oct 26, 2023, at 5:20 AM, Martin Uecker  wrote:
> > 
> > Am Donnerstag, dem 26.10.2023 um 10:45 +0200 schrieb Richard Biener:
> > > On Wed, Oct 25, 2023 at 8:16 PM Martin Uecker  wrote:
> > > > 
> > > > Am Mittwoch, dem 25.10.2023 um 13:13 +0200 schrieb Richard Biener:
> > > > > 
> > > > > > Am 25.10.2023 um 12:47 schrieb Martin Uecker :
> > > > > > 
> > > > > > Am Mittwoch, dem 25.10.2023 um 06:25 -0400 schrieb Siddhesh 
> > > > > > Poyarekar:
> > > > > > > > On 2023-10-25 04:16, Martin Uecker wrote:
> > > > > > > > Am Mittwoch, dem 25.10.2023 um 08:43 +0200 schrieb Richard 
> > > > > > > > Biener:
> > > > > > > > > 
> > > > > > > > > > Am 24.10.2023 um 22:38 schrieb Martin Uecker 
> > > > > > > > > > :
> > > > > > > > > > 
> > > > > > > > > > Am Dienstag, dem 24.10.2023 um 20:30 + schrieb Qing 
> > > > > > > > > > Zhao:
> > > > > > > > > > > Hi, Sid,
> > > > > > > > > > > 
> > > > > > > > > > > Really appreciate for your example and detailed 
> > > > > > > > > > > explanation. Very helpful.
> > > > > > > > > > > I think that this example is an excellent example to show 
> > > > > > > > > > > (almost) all the issues we need to consider.
> > > > > > > > > > > 
> > > > > > > > > > > I slightly modified this example to make it to be 
> > > > > > > > > > > compilable and run-able, as following:
> > > > > > > > > > > (but I still cannot make the incorrect reordering or DSE 
> > > > > > > > > > > happening, anyway, the potential reordering possibility 
> > > > > > > > > > > is there…)
> > > > > > > > > > > 
> > > > > > > > > > > 1 #include 
> > > > > > > > > > > 2 struct A
> > > > > > > > > > > 3 {
> > > > > > > > > > > 4  size_t size;
> > > > > > > > > > > 5  char buf[] __attribute__((counted_by(size)));
> > > > > > > > > > > 6 };
> > > > > > > > > > > 7
> > > > > > > > > > > 8 static size_t
> > > > > > > > > > > 9 get_size_from (void *ptr)
> > > > > > > > > > > 10 {
> > > > > > > > > > > 11  return __builtin_dynamic_object_size (ptr, 1);
> > > > > > > > > > > 12 }
> > > > > > > > > > > 13
> > > > > > > > > > > 14 void
> > > > > > > > > > > 15 foo (size_t sz)
> > > > > > > > > > > 16 {
> > > > > > > > > > > 17  struct A *obj = __builtin_malloc (sizeof(struct A) + 
> > > > > > > > > > > sz * sizeof(char));
> > > > > > > > > > > 18  obj->size = sz;
> > > > > > > > > > > 19  obj->buf[0] = 2;
> > > > > > > > > > > 20  __builtin_printf (“%d\n", get_size_from (obj->buf));
> > > > > > > > > > > 21  return;
> > > > > > > > > > > 22 }
> > > > > > > > > > > 23
> > > > > > > > > > > 24 int main ()
> > > > > > > > > > > 25 {
> > > > > > > > > > > 26  foo (20);
> > > > > > > > > > > 27  return 0;
> > > > > > > > > > > 28 }
> > > > > > > > > > > 
> > > > > > > 
> > > > > > > 
> > > > > > > 
> > > > > > > > > When it’s set I suppose.  Turn
> > > > > > > > > 
> > > > > > > > > X.l = n;
> > > > > > > > > 
> > > > > > > > > Into
> > > > > > > >

Re: HELP: Will the reordering happen? Re: [V3][PATCH 0/3] New attribute "counted_by" to annotate bounds for C99 FAM(PR108896)

2023-10-26 Thread Martin Uecker
Am Donnerstag, dem 26.10.2023 um 09:13 -0700 schrieb Kees Cook:
> On Thu, Oct 26, 2023 at 10:15:10AM +0200, Martin Uecker wrote:
> > but not this:
> > 

x->count = 11;
> > char *p = &x->buf;
> > x->count = 1;
> > p[10] = 1; // !
> 
> This seems fine to me -- it's how I'd expect it to work: "10" is beyond
> "1".

Note that the store would be allowed.

> 
> > (because the pointer is passed around the
> > store to the counter)
> > 
> > and also here the second store is then irrelevant
> > for the access:
> > 
> > x->count = 10;
> > char* p = &x->buf;
> > ...
> > x->count = 1; // somewhere else
> > 
> > p[9] = 1; // ok, because count matter when buf was accesssed.
> 
> This is less great, but I can understand why it happens. "p" loses the
> association with "x". It'd be nice if "p" had to way to retain that it
> was just an alias for x->buf, so future p access would check count.

The problem is not to discover that p is an alias to x->buf, 
but that it seems difficult to make sure that stores to 
x->count are not reordered relative to the final access to
p[i] you want to check, so that you then get the right value.

> 
> But this appears to be an existing limitation in other areas where an
> assignment will cause the loss of object association. (I've run into
> this before.) It's just more surprising in the above example because in
> the past the loss of association would cause __bdos() to revert back to
> "SIZE_MAX" results ("I don't know the size") rather than an "outdated"
> size, which may get us into unexpected places...
> 
> > IMHO this makes sense also from the user side and
> > are the desirable semantics we discussed before.
> > 
> > But can you take a look at this?
> > 
> > 
> > This should simulate it fairly well:
> > https://godbolt.org/z/xq89aM7Gr
> > 
> > (the call to the noinline function would go away,
> > but not necessarily its impact on optimization)
> 
> Yeah, this example should be a very rare situation: a leaf function is
> changing the characteristics of the struct but returning a buffer within
> it to the caller. The more likely glitch would be from:
> 
> int main()
> {
>   struct foo *f = foo_alloc(7);
>   char *p = FAM_ACCESS(f, size, buf);
> 
>   printf("%ld\n", __builtin_dynamic_object_size(p, 0));
>   test1(f); // or just "f->count = 10;" no function call needed
>   printf("%ld\n", __builtin_dynamic_object_size(p, 0));
> 
>   return 0;
> }
> 
> which reports:
> 7
> 7
> 
> instead of:
> 7
> 10
> 
> This kind of "get an alias" situation is pretty common in the kernel
> as a way to have a convenient "handle" to the array. In the case of a
> "fill the array without knowing the actual final size" code pattern,
> things would immediately break:
> 
>   struct foo *f;
>   char *p;
>   int i;
> 
>   f = alloc(maximum_possible);
>   f->count = 0;
>   p = f->buf;
> 
>   for (i; data_is_available() && i < maximum_possible; i++) {
>   f->count ++;
>   p[i] = next_data_item();
>   }
> 
> Now perhaps the problem here is that "count" cannot be used for a count
> of "logically valid members in the array" but must always be a count of
> "allocated member space in the array", which I guess is tolerable, but
> isn't ideal -- I'd like to catch logic bugs in addition to allocation
> bugs, but the latter is certainly much more important to catch.

Maybe we could have a warning when f->buf is not directly
accessed.

Martin

> 



Re: HELP: Will the reordering happen? Re: [V3][PATCH 0/3] New attribute "counted_by" to annotate bounds for C99 FAM(PR108896)

2023-10-26 Thread Martin Uecker
Am Donnerstag, dem 26.10.2023 um 17:48 +0200 schrieb Richard Biener:
> 
> > Am 26.10.2023 um 16:58 schrieb Qing Zhao :
> > 
> > 
> > 
> > > On Oct 26, 2023, at 4:56 AM, Richard Biener  
> > > wrote:
> > > 
> > > > On Thu, Oct 26, 2023 at 7:22 AM Jakub Jelinek  wrote:
> > > > 
> > > > On Wed, Oct 25, 2023 at 07:03:43PM +, Qing Zhao wrote:
> > > > > For the code generation impact:
> > > > > 
> > > > > turning the original  x.buf
> > > > > to a builtin function call
> > > > > __builtin_with_access_and_size(x,buf, x.L,-1)
> > > > > 
> > > > > might inhibit some optimizations from happening before the builtin is
> > > > > evaluated into object size info (phase  .objsz1).  I guess there 
> > > > > might be
> > > > > some performance impact.
> > > > > 
> > > > > However, if we mark this builtin as PURE, NOTRROW, etc, then the 
> > > > > negative
> > > > > performance impact will be reduced to minimum?
> > > > 
> > > > You can't drop it during objsz1 pass though, otherwise __bdos wouldn't
> > > > be able to figure out the dynamic sizes in case of normal (non-early)
> > > > inlining - caller takes address of a counted_by array, passes it down
> > > > to callee which is only inlined late and uses __bdos, or callee takes 
> > > > address
> > > > and returns it and caller uses __bdos, etc. - so it would need to be 
> > > > objsz2.
> > > > 
> > > > And while the builtin (or if it is an internal detail rather than user
> > > > accessible builtin an internal function) could be even 
> > > > const/nothrow/leaf if
> > > > the arguments contain the loads from the structure 2 fields, I'm afraid 
> > > > it
> > > > will still have huge code generation impact, prevent tons of pre-IPA
> > > > optimizations.  And it will need some work to handle it properly during
> > > > inlining heuristics, because in GIMPLE the COMPONENT_REF loads aren't 
> > > > gimple
> > > > values, so it wouldn't be just the builtin/internal-fn call to be 
> > > > ignored,
> > > > but also the count load from memory.
> > > 
> > > I think we want to track the value, not the "memory" in the builtin call,
> > > so GIMPLE would be
> > > 
> > > _1 = x.L;
> > > .. = __builtin_with_access_and_size (&x.buf, _1, -1);
> > 
> > Before adding the __builtin_with_access_and_size, the code is:
> > 
> > &x.buf
> > 
> > After inserting the built-in, it becomes:
> > 
> > _1 = x.L;
> > __builtin_with_access_and_size (&x.buf, _1, -1).
> > 
> > 
> > So, the # of total instructions, the # of LOADs, and the # of calls will 
> > all be increased.
> > There will be impact to the inlining decision definitely.
> 
> Note we have to make sure, if x is a pointer and we want to instrument 
> &x->buf that we
> Can dereference x.  Possibly doing
> 
> _1 = x ? x->Len : -1;
> 
> I’m not sure the C standard makes accessing x->Len unconditionally not 
> undefined behavior when &x->buf is computed.  Definitely it’s a violation of 
> the abstract machine of Len is volatile qualified (but we can reject such 
> counted_by or instantiations as volatile qualified types).

I believe it is implicit UB to do &x->buf if there is
no object *x because the wording assumes the existence
of an object.  In that case accessing x->L should
be fine too.  

In practice the access may trap  for other reasons 
(mprotect etc.),  but I guess this is acceptable,
but should probably be documented...

We might need the x?  to not run into trouble with
those offsetof  implementations written using null
pointer.  Although in this case maybe one could
hope that the load will get optimized anyway ...

Martin

> 
> Richard 
> 
> > 
> > > 
> > > also please make sure to use an internal function for
> > > __builtin_with_access_and_size,
> > > I don't think we want to expose this to users - it's an implementation 
> > > detail.
> > 
> > Okay, will define it as an internal function (add it to internal-fn.def). 
> > -:)
> > 
> > Qing
> > > 
> > > Richard.
> > > 
> > > > 
> > > >   Jakub
> > > > 
> > 



Re: HELP: Will the reordering happen? Re: [V3][PATCH 0/3] New attribute "counted_by" to annotate bounds for C99 FAM(PR108896)

2023-10-26 Thread Martin Uecker
Am Donnerstag, dem 26.10.2023 um 11:20 +0200 schrieb Martin Uecker:
> Am Donnerstag, dem 26.10.2023 um 10:45 +0200 schrieb Richard Biener:
> > On Wed, Oct 25, 2023 at 8:16 PM Martin Uecker  wrote:
> > > 
> > > Am Mittwoch, dem 25.10.2023 um 13:13 +0200 schrieb Richard Biener:
> > > > 
> > > > > Am 25.10.2023 um 12:47 schrieb Martin Uecker :
> > > > > 
> > > > > Am Mittwoch, dem 25.10.2023 um 06:25 -0400 schrieb Siddhesh 
> > > > > Poyarekar:
> > > > > > > On 2023-10-25 04:16, Martin Uecker wrote:
> > > > > > > Am Mittwoch, dem 25.10.2023 um 08:43 +0200 schrieb Richard Biener:
> > > > > > > > 
> > > > > > > > > Am 24.10.2023 um 22:38 schrieb Martin Uecker 
> > > > > > > > > :
> > > > > > > > > 
> > > > > > > > > Am Dienstag, dem 24.10.2023 um 20:30 + schrieb Qing Zhao:
> > > > > > > > > > Hi, Sid,
> > > > > > > > > > 
> > > > > > > > > > Really appreciate for your example and detailed 
> > > > > > > > > > explanation. Very helpful.
> > > > > > > > > > I think that this example is an excellent example to show 
> > > > > > > > > > (almost) all the issues we need to consider.
> > > > > > > > > > 
> > > > > > > > > > I slightly modified this example to make it to be 
> > > > > > > > > > compilable and run-able, as following:
> > > > > > > > > > (but I still cannot make the incorrect reordering or DSE 
> > > > > > > > > > happening, anyway, the potential reordering possibility is 
> > > > > > > > > > there…)
> > > > > > > > > > 
> > > > > > > > > >  1 #include 
> > > > > > > > > >  2 struct A
> > > > > > > > > >  3 {
> > > > > > > > > >  4  size_t size;
> > > > > > > > > >  5  char buf[] __attribute__((counted_by(size)));
> > > > > > > > > >  6 };
> > > > > > > > > >  7
> > > > > > > > > >  8 static size_t
> > > > > > > > > >  9 get_size_from (void *ptr)
> > > > > > > > > > 10 {
> > > > > > > > > > 11  return __builtin_dynamic_object_size (ptr, 1);
> > > > > > > > > > 12 }
> > > > > > > > > > 13
> > > > > > > > > > 14 void
> > > > > > > > > > 15 foo (size_t sz)
> > > > > > > > > > 16 {
> > > > > > > > > > 17  struct A *obj = __builtin_malloc (sizeof(struct A) + sz 
> > > > > > > > > > * sizeof(char));
> > > > > > > > > > 18  obj->size = sz;
> > > > > > > > > > 19  obj->buf[0] = 2;
> > > > > > > > > > 20  __builtin_printf (“%d\n", get_size_from (obj->buf));
> > > > > > > > > > 21  return;
> > > > > > > > > > 22 }
> > > > > > > > > > 23
> > > > > > > > > > 24 int main ()
> > > > > > > > > > 25 {
> > > > > > > > > > 26  foo (20);
> > > > > > > > > > 27  return 0;
> > > > > > > > > > 28 }
> > > > > > > > > > 
> > > > > > 
> > > > > > 
> > > > > > 
> > > > > > > > When it’s set I suppose.  Turn
> > > > > > > > 
> > > > > > > > X.l = n;
> > > > > > > > 
> > > > > > > > Into
> > > > > > > > 
> > > > > > > > X.l = __builtin_with_size (x.buf, n);
> > > > > > > 
> > > > > > > It would turn
> > > > > > > 
> > > > > > > some_variable = (&) x.buf
> > > > > > > 
> > > > > > > into
> > > > > > > 
> > > > > > > some_variable = __builtin_with_size ( (&) x.buf. x.len)
> > > &

Re: HELP: Will the reordering happen? Re: [V3][PATCH 0/3] New attribute "counted_by" to annotate bounds for C99 FAM(PR108896)

2023-10-26 Thread Martin Uecker
Am Donnerstag, dem 26.10.2023 um 10:45 +0200 schrieb Richard Biener:
> On Wed, Oct 25, 2023 at 8:16 PM Martin Uecker  wrote:
> > 
> > Am Mittwoch, dem 25.10.2023 um 13:13 +0200 schrieb Richard Biener:
> > > 
> > > > Am 25.10.2023 um 12:47 schrieb Martin Uecker :
> > > > 
> > > > Am Mittwoch, dem 25.10.2023 um 06:25 -0400 schrieb Siddhesh Poyarekar:
> > > > > > On 2023-10-25 04:16, Martin Uecker wrote:
> > > > > > Am Mittwoch, dem 25.10.2023 um 08:43 +0200 schrieb Richard Biener:
> > > > > > > 
> > > > > > > > Am 24.10.2023 um 22:38 schrieb Martin Uecker :
> > > > > > > > 
> > > > > > > > Am Dienstag, dem 24.10.2023 um 20:30 + schrieb Qing Zhao:
> > > > > > > > > Hi, Sid,
> > > > > > > > > 
> > > > > > > > > Really appreciate for your example and detailed explanation. 
> > > > > > > > > Very helpful.
> > > > > > > > > I think that this example is an excellent example to show 
> > > > > > > > > (almost) all the issues we need to consider.
> > > > > > > > > 
> > > > > > > > > I slightly modified this example to make it to be compilable 
> > > > > > > > > and run-able, as following:
> > > > > > > > > (but I still cannot make the incorrect reordering or DSE 
> > > > > > > > > happening, anyway, the potential reordering possibility is 
> > > > > > > > > there…)
> > > > > > > > > 
> > > > > > > > >  1 #include 
> > > > > > > > >  2 struct A
> > > > > > > > >  3 {
> > > > > > > > >  4  size_t size;
> > > > > > > > >  5  char buf[] __attribute__((counted_by(size)));
> > > > > > > > >  6 };
> > > > > > > > >  7
> > > > > > > > >  8 static size_t
> > > > > > > > >  9 get_size_from (void *ptr)
> > > > > > > > > 10 {
> > > > > > > > > 11  return __builtin_dynamic_object_size (ptr, 1);
> > > > > > > > > 12 }
> > > > > > > > > 13
> > > > > > > > > 14 void
> > > > > > > > > 15 foo (size_t sz)
> > > > > > > > > 16 {
> > > > > > > > > 17  struct A *obj = __builtin_malloc (sizeof(struct A) + sz * 
> > > > > > > > > sizeof(char));
> > > > > > > > > 18  obj->size = sz;
> > > > > > > > > 19  obj->buf[0] = 2;
> > > > > > > > > 20  __builtin_printf (“%d\n", get_size_from (obj->buf));
> > > > > > > > > 21  return;
> > > > > > > > > 22 }
> > > > > > > > > 23
> > > > > > > > > 24 int main ()
> > > > > > > > > 25 {
> > > > > > > > > 26  foo (20);
> > > > > > > > > 27  return 0;
> > > > > > > > > 28 }
> > > > > > > > > 
> > > > > 
> > > > > 
> > > > > 
> > > > > > > When it’s set I suppose.  Turn
> > > > > > > 
> > > > > > > X.l = n;
> > > > > > > 
> > > > > > > Into
> > > > > > > 
> > > > > > > X.l = __builtin_with_size (x.buf, n);
> > > > > > 
> > > > > > It would turn
> > > > > > 
> > > > > > some_variable = (&) x.buf
> > > > > > 
> > > > > > into
> > > > > > 
> > > > > > some_variable = __builtin_with_size ( (&) x.buf. x.len)
> > > > > > 
> > > > > > 
> > > > > > So the later access to x.buf and not the initialization
> > > > > > of a member of the struct (which is too early).
> > > > > > 
> > > > > 
> > > > > Hmm, so with Qing's example above, are you suggesting the 
> > > > > transformation
> > > > > be to foo like so:
> > > > > 
> > > > > 14 void
> > > >

[PATCH] tree-optimization/109334: Improve computation for access attribute

2023-10-26 Thread Martin Uecker



Hi Sid and Jakub,

here is the patch discussed in PR 109334.

Martin



tree-optimization/109334: Improve computation for access attribute

The fix for PR104970 restricted size computations to the case
where the access attribute was specified explicitly (no VLA).
It also restricted it to void pointers or elements with constant
sizes.  The second restriction is enough to fix the original bug.
Revert the first change to again allow size computations for VLA
parameters and for VLA parameters together with an explicit access
attribute.

gcc/ChangeLog:

PR tree-optimization/109334
* tree-object-size.cc (parm_object_size): Allow size
computation for explicit access attributes.

gcc/testsuite/ChangeLog:

PR tree-optimization/109334
* gcc.dg/builtin-dynamic-object-size-20.c
(test_parmsz_simple3): Supported again.
(test_parmsz_external4): New test.
* gcc.dg/builtin-dynamic-object-size-20.c: New test.
* gcc.dg/pr104970.c: New test.

diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c 
b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
index 6da04202ffe..07e3da6f254 100644
--- a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
+++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-0.c
@@ -455,7 +455,6 @@ test_parmsz_simple2 (size_t sz, char obj[])
   return __builtin_dynamic_object_size (obj, 0);
 }
 
-/* Implicitly constructed access attributes not supported yet.  */
 size_t
 __attribute__ ((noinline))
 test_parmsz_simple3 (size_t sz, char obj[sz])
@@ -527,6 +526,13 @@ test_parmsz_internal3 (size_t sz1, size_t sz2, double 
obj[sz1][sz2])
   return __builtin_dynamic_object_size (obj, 0);
 }
 
+size_t
+__attribute__ ((noinline))
+test_parmsz_internal4 (size_t sz1, size_t sz2, double obj[sz1 + 1][4])
+{
+  return __builtin_dynamic_object_size (obj, 0);
+}
+
 /* Loops.  */
 
 size_t
@@ -721,8 +727,8 @@ main (int argc, char **argv)
   if (test_parmsz_simple2 (__builtin_strlen (argv[0]) + 1, argv[0])
   != __builtin_strlen (argv[0]) + 1)
 FAIL ();
-  /* Only explicitly added access attributes are supported for now.  */
-  if (test_parmsz_simple3 (__builtin_strlen (argv[0]) + 1, argv[0]) != -1)
+  if (test_parmsz_simple3 (__builtin_strlen (argv[0]) + 1, argv[0]) 
+  != __builtin_strlen (argv[0]) + 1)
 FAIL ();
   int arr[42];
   if (test_parmsz_scaled (arr, 42) != sizeof (arr))
@@ -759,6 +765,8 @@ main (int argc, char **argv)
 FAIL ();
   if (test_parmsz_internal3 (4, 4, obj) != -1)
 FAIL ();
+  if (test_parmsz_internal4 (3, 4, obj) != -1)
+FAIL ();
   if (test_loop (arr, 42, 0, 32, 1) != 10 * sizeof (int))
 FAIL ();
   if (test_loop (arr, 42, 32, -1, -1) != 0)
diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-20.c 
b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-20.c
new file mode 100644
index 000..2c8e07dd98d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-20.c
@@ -0,0 +1,49 @@
+/* PR 109334 
+ * { dg-do run }
+ * { dg-options "-O1" } */
+
+
+[[gnu::noinline,gnu::noipa]]
+int f(int n, int buf[n])
+[[gnu::access(read_only, 2, 1)]]
+{
+return __builtin_dynamic_object_size(buf, 0);
+}
+
+[[gnu::noinline,gnu::noipa]]
+int g(int n, int buf[])
+[[gnu::access(read_only, 2, 1)]]
+{
+return __builtin_dynamic_object_size(buf, 0);
+}
+
+[[gnu::noinline,gnu::noipa]]
+int h(int n, int buf[n])
+{
+return __builtin_dynamic_object_size(buf, 0);
+}
+
+int dummy(int x) { return x + 1; }
+
+[[gnu::noinline,gnu::noipa]]
+int i(int n, int buf[dummy(n)])
+{
+return __builtin_dynamic_object_size(buf, 0);
+}
+
+int main()
+{
+int n = 10;
+int buf[n];
+if (n * sizeof(int) != f(n, buf))
+__builtin_abort();
+if (n * sizeof(int) != g(n, buf))
+__builtin_abort();
+if (n * sizeof(int) != h(n, buf))
+__builtin_abort();
+
+(void)i(n, buf);
+ 
+return 0;
+}
+
diff --git a/gcc/testsuite/gcc.dg/pr104970.c b/gcc/testsuite/gcc.dg/pr104970.c
new file mode 100644
index 000..e24a7f22dfb
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr104970.c
@@ -0,0 +1,13 @@
+/* { dg-do compile } */
+/* { dg-options "-O1 -D_FORTIFY_SOURCE=2" } */
+
+__inline void
+memset2(void *__dest, int __ch, long __len) {
+  long __trans_tmp_1 = __builtin_dynamic_object_size(__dest, 0);
+  __builtin___memset_chk(__dest, __ch, __len, __trans_tmp_1);
+}
+
+void
+mleye(int l, double E[][l]) { memset2(E, 0, sizeof(double)); }
+
+
diff --git a/gcc/tree-object-size.cc b/gcc/tree-object-size.cc
index a62af050056..28f27adf9ca 100644
--- a/gcc/tree-object-size.cc
+++ b/gcc/tree-object-size.cc
@@ -1575,8 +1575,8 @@ parm_object_size (struct object_size_info *osi, tree var)
   tree typesize = TYPE_SIZE_UNIT (TREE_TYPE (TREE_TYPE (parm)));
   tree sz = NULL_TREE;
 
-  /* If we have an explicit access attribute with a usable size argument... */
-  if (access &&

Re: HELP: Will the reordering happen? Re: [V3][PATCH 0/3] New attribute "counted_by" to annotate bounds for C99 FAM(PR108896)

2023-10-26 Thread Martin Uecker
Am Mittwoch, dem 25.10.2023 um 15:32 -0700 schrieb Kees Cook:
> On Wed, Oct 25, 2023 at 10:27:41PM +, Qing Zhao wrote:
> > 
> > 
> > > On Oct 25, 2023, at 6:06 PM, Kees Cook  wrote:
> > > 
> > > On Wed, Oct 25, 2023 at 01:27:29PM +, Qing Zhao wrote:
> > > > A.  Add an additional argument, the size parameter,  to __bdos, 
> > > > A.1, during FE;
> > > > A.2, during gimplification phase;
> > > 
> > > I just wanted to clarify that this is all just an "internal" detail,
> > > yes?
> > 
> > YES!
> 
> Okay, I thought so, but I just wanted to double-check. :)
> 
> > > For example, the Linux kernel can still use __bdos() without knowing
> > > the count member ahead of time (otherwise it kind of defeats the purpose).
> > Don’t quite understand this, could you clarify? 
> 
> I was just trying to explain why a chance would be a problem. But it
> doesn't matter, so nevermind. :)
> 
> > (Anyway, the bottom line is no change to the user interface, we just 
> > discuss the internal implementation inside GCC) -:)
> 
> Great! I'll go back to lurking. :)
> 
> Thanks!
> 

While it is about the internal implementation, it would
potentially affect the semantics of the attribute:

This would work:

x->count = 10;
char *p = &x->buf;

but not this:

char *p = &x->buf;
x->count = 1;
p[10] = 1; // !

(because the pointer is passed around the
store to the counter)

and also here the second store is then irrelevant
for the access:

x->count = 10;
char* p = &x->buf;
...
x->count = 1; // somewhere else

p[9] = 1; // ok, because count matter when buf was accesssed.


IMHO this makes sense also from the user side and
are the desirable semantics we discussed before.

But can you take a look at this?


This should simulate it fairly well:
https://godbolt.org/z/xq89aM7Gr

(the call to the noinline function would go away,
but not necessarily its impact on optimization)

Martin






Re: HELP: Will the reordering happen? Re: [V3][PATCH 0/3] New attribute "counted_by" to annotate bounds for C99 FAM(PR108896)

2023-10-25 Thread Martin Uecker
Am Mittwoch, dem 25.10.2023 um 13:13 +0200 schrieb Richard Biener:
> 
> > Am 25.10.2023 um 12:47 schrieb Martin Uecker :
> > 
> > Am Mittwoch, dem 25.10.2023 um 06:25 -0400 schrieb Siddhesh Poyarekar:
> > > > On 2023-10-25 04:16, Martin Uecker wrote:
> > > > Am Mittwoch, dem 25.10.2023 um 08:43 +0200 schrieb Richard Biener:
> > > > > 
> > > > > > Am 24.10.2023 um 22:38 schrieb Martin Uecker :
> > > > > > 
> > > > > > Am Dienstag, dem 24.10.2023 um 20:30 + schrieb Qing Zhao:
> > > > > > > Hi, Sid,
> > > > > > > 
> > > > > > > Really appreciate for your example and detailed explanation. Very 
> > > > > > > helpful.
> > > > > > > I think that this example is an excellent example to show 
> > > > > > > (almost) all the issues we need to consider.
> > > > > > > 
> > > > > > > I slightly modified this example to make it to be compilable and 
> > > > > > > run-able, as following:
> > > > > > > (but I still cannot make the incorrect reordering or DSE 
> > > > > > > happening, anyway, the potential reordering possibility is there…)
> > > > > > > 
> > > > > > >  1 #include 
> > > > > > >  2 struct A
> > > > > > >  3 {
> > > > > > >  4  size_t size;
> > > > > > >  5  char buf[] __attribute__((counted_by(size)));
> > > > > > >  6 };
> > > > > > >  7
> > > > > > >  8 static size_t
> > > > > > >  9 get_size_from (void *ptr)
> > > > > > > 10 {
> > > > > > > 11  return __builtin_dynamic_object_size (ptr, 1);
> > > > > > > 12 }
> > > > > > > 13
> > > > > > > 14 void
> > > > > > > 15 foo (size_t sz)
> > > > > > > 16 {
> > > > > > > 17  struct A *obj = __builtin_malloc (sizeof(struct A) + sz * 
> > > > > > > sizeof(char));
> > > > > > > 18  obj->size = sz;
> > > > > > > 19  obj->buf[0] = 2;
> > > > > > > 20  __builtin_printf (“%d\n", get_size_from (obj->buf));
> > > > > > > 21  return;
> > > > > > > 22 }
> > > > > > > 23
> > > > > > > 24 int main ()
> > > > > > > 25 {
> > > > > > > 26  foo (20);
> > > > > > > 27  return 0;
> > > > > > > 28 }
> > > > > > > 
> > > 
> > > 
> > > 
> > > > > When it’s set I suppose.  Turn
> > > > > 
> > > > > X.l = n;
> > > > > 
> > > > > Into
> > > > > 
> > > > > X.l = __builtin_with_size (x.buf, n);
> > > > 
> > > > It would turn
> > > > 
> > > > some_variable = (&) x.buf
> > > > 
> > > > into
> > > > 
> > > > some_variable = __builtin_with_size ( (&) x.buf. x.len)
> > > > 
> > > > 
> > > > So the later access to x.buf and not the initialization
> > > > of a member of the struct (which is too early).
> > > > 
> > > 
> > > Hmm, so with Qing's example above, are you suggesting the transformation 
> > > be to foo like so:
> > > 
> > > 14 void
> > > 15 foo (size_t sz)
> > > 16 {
> > > 16.5  void * _1;
> > > 17  struct A *obj = __builtin_malloc (sizeof(struct A) + sz * 
> > > sizeof(char));
> > > 18  obj->size = sz;
> > > 19  obj->buf[0] = 2;
> > > 19.5  _1 = __builtin_with_size (obj->buf, obj->size);
> > > 20  __builtin_printf (“%d\n", get_size_from (_1));
> > > 21  return;
> > > 22 }
> > > 
> > > If yes then this could indeed work.  I think I got thrown off by the 
> > > reference to __bdos.
> > 
> > Yes. I think it is important not to evaluate the size at the
> > access to buf and not the allocation, because the point is to 
> > recover it from the size member even when the compiler can't 
> > see the original allocation.
> 
> But if the access is through a pointer without the attribute visible
> even the Frontend cannot recover?  

Yes, if the access is using a struct-with-

Re: HELP: Will the reordering happen? Re: [V3][PATCH 0/3] New attribute "counted_by" to annotate bounds for C99 FAM(PR108896)

2023-10-25 Thread Martin Uecker
Am Mittwoch, dem 25.10.2023 um 06:25 -0400 schrieb Siddhesh Poyarekar:
> On 2023-10-25 04:16, Martin Uecker wrote:
> > Am Mittwoch, dem 25.10.2023 um 08:43 +0200 schrieb Richard Biener:
> > > 
> > > > Am 24.10.2023 um 22:38 schrieb Martin Uecker :
> > > > 
> > > > Am Dienstag, dem 24.10.2023 um 20:30 + schrieb Qing Zhao:
> > > > > Hi, Sid,
> > > > > 
> > > > > Really appreciate for your example and detailed explanation. Very 
> > > > > helpful.
> > > > > I think that this example is an excellent example to show (almost) 
> > > > > all the issues we need to consider.
> > > > > 
> > > > > I slightly modified this example to make it to be compilable and 
> > > > > run-able, as following:
> > > > > (but I still cannot make the incorrect reordering or DSE happening, 
> > > > > anyway, the potential reordering possibility is there…)
> > > > > 
> > > > >   1 #include 
> > > > >   2 struct A
> > > > >   3 {
> > > > >   4  size_t size;
> > > > >   5  char buf[] __attribute__((counted_by(size)));
> > > > >   6 };
> > > > >   7
> > > > >   8 static size_t
> > > > >   9 get_size_from (void *ptr)
> > > > > 10 {
> > > > > 11  return __builtin_dynamic_object_size (ptr, 1);
> > > > > 12 }
> > > > > 13
> > > > > 14 void
> > > > > 15 foo (size_t sz)
> > > > > 16 {
> > > > > 17  struct A *obj = __builtin_malloc (sizeof(struct A) + sz * 
> > > > > sizeof(char));
> > > > > 18  obj->size = sz;
> > > > > 19  obj->buf[0] = 2;
> > > > > 20  __builtin_printf (“%d\n", get_size_from (obj->buf));
> > > > > 21  return;
> > > > > 22 }
> > > > > 23
> > > > > 24 int main ()
> > > > > 25 {
> > > > > 26  foo (20);
> > > > > 27  return 0;
> > > > > 28 }
> > > > > 
> 
> 
> 
> > > When it’s set I suppose.  Turn
> > > 
> > > X.l = n;
> > > 
> > > Into
> > > 
> > > X.l = __builtin_with_size (x.buf, n);
> > 
> > It would turn
> > 
> > some_variable = (&) x.buf
> > 
> > into
> > 
> > some_variable = __builtin_with_size ( (&) x.buf. x.len)
> > 
> > 
> > So the later access to x.buf and not the initialization
> > of a member of the struct (which is too early).
> > 
> 
> Hmm, so with Qing's example above, are you suggesting the transformation 
> be to foo like so:
> 
> 14 void
> 15 foo (size_t sz)
> 16 {
> 16.5  void * _1;
> 17  struct A *obj = __builtin_malloc (sizeof(struct A) + sz * sizeof(char));
> 18  obj->size = sz;
> 19  obj->buf[0] = 2;
> 19.5  _1 = __builtin_with_size (obj->buf, obj->size);
> 20  __builtin_printf (“%d\n", get_size_from (_1));
> 21  return;
> 22 }
> 
> If yes then this could indeed work.  I think I got thrown off by the 
> reference to __bdos.

Yes. I think it is important not to evaluate the size at the
access to buf and not the allocation, because the point is to 
recover it from the size member even when the compiler can't 
see the original allocation.

Evaluating at this point requires that the size is correctly set
before the access to the FAM and the user has to make sure 
this is the case. But to me this requirement would make sense.

Semantically, it could aöso make sense to evaluate the size at a
later time.  But then the reordering becomes problematic again.

Also I think this would make this feature generally more useful.
For example, it could work also for others pointers in the struct
and not just for FAMs.  In this case, the struct may already be
freed when  BDOS is called, so it might also not possible to
access the size member at a later time.

Martin


> 



Re: HELP: Will the reordering happen? Re: [V3][PATCH 0/3] New attribute "counted_by" to annotate bounds for C99 FAM(PR108896)

2023-10-25 Thread Martin Uecker
Am Mittwoch, dem 25.10.2023 um 12:25 +0200 schrieb Richard Biener:
> 
> > Am 25.10.2023 um 10:16 schrieb Martin Uecker :
> > 
> > Am Mittwoch, dem 25.10.2023 um 08:43 +0200 schrieb Richard Biener:
> > > 
> > > > > Am 24.10.2023 um 22:38 schrieb Martin Uecker :
> > > > 
> > > > Am Dienstag, dem 24.10.2023 um 20:30 + schrieb Qing Zhao:
> > > > > Hi, Sid,
> > > > > 
> > > > > Really appreciate for your example and detailed explanation. Very 
> > > > > helpful.
> > > > > I think that this example is an excellent example to show (almost) 
> > > > > all the issues we need to consider.
> > > > > 
> > > > > I slightly modified this example to make it to be compilable and 
> > > > > run-able, as following: 
> > > > > (but I still cannot make the incorrect reordering or DSE happening, 
> > > > > anyway, the potential reordering possibility is there…)
> > > > > 
> > > > > 1 #include 
> > > > > 2 struct A
> > > > > 3 {
> > > > > 4  size_t size;
> > > > > 5  char buf[] __attribute__((counted_by(size)));
> > > > > 6 };
> > > > > 7 
> > > > > 8 static size_t
> > > > > 9 get_size_from (void *ptr)
> > > > > 10 {
> > > > > 11  return __builtin_dynamic_object_size (ptr, 1);
> > > > > 12 }
> > > > > 13 
> > > > > 14 void
> > > > > 15 foo (size_t sz)
> > > > > 16 {
> > > > > 17  struct A *obj = __builtin_malloc (sizeof(struct A) + sz * 
> > > > > sizeof(char));
> > > > > 18  obj->size = sz;
> > > > > 19  obj->buf[0] = 2;
> > > > > 20  __builtin_printf (“%d\n", get_size_from (obj->buf));
> > > > > 21  return;
> > > > > 22 }
> > > > > 23 
> > > > > 24 int main ()
> > > > > 25 {
> > > > > 26  foo (20);
> > > > > 27  return 0;
> > > > > 28 }
> > > > > 
> > > > > With my GCC, it was compiled and worked:
> > > > > [opc@qinzhao-ol8u3-x86 ]$  /home/opc/Install/latest-d/bin/gcc -O1 t5.c
> > > > > [opc@qinzhao-ol8u3-x86 ]$ ./a.out
> > > > > 20
> > > > > Situation 1: With O1 and above, the routine “get_size_from” was 
> > > > > inlined into “foo”, therefore, the call to __bdos is in the same 
> > > > > routine as the instantiation of the object, and the TYPE information 
> > > > > and the attached counted_by attribute information in the TYPE of the 
> > > > > object can be USED by the __bdos call to compute the final object 
> > > > > size. 
> > > > > 
> > > > > [opc@qinzhao-ol8u3-x86]$  /home/opc/Install/latest-d/bin/gcc -O0  t5.c
> > > > > [opc@qinzhao-ol8u3-x86 ]$ ./a.out
> > > > > -1
> > > > > Situation 2: With O0, the routine “get_size_from” was NOT inlined 
> > > > > into “foo”, therefore, the call to __bdos is Not in the same routine 
> > > > > as the instantiation of the object, As a result, the TYPE info and 
> > > > > the attached counted_by info of the object can NOT be USED by the 
> > > > > __bdos call. 
> > > > > 
> > > > > Keep in mind of the above 2 situations, we will refer them in below:
> > > > > 
> > > > > 1. First,  the problem we are trying to resolve is:
> > > > > 
> > > > > (Your description):
> > > > > 
> > > > > > the reordering of __bdos w.r.t. initialization of the size 
> > > > > > parameter but to also account for DSE of the assignment, we can 
> > > > > > abstract this problem to that of DFA being unable to see implicit 
> > > > > > use of the size parameter in the __bdos call.
> > > > > 
> > > > > basically is correct.  However, with the following exception:
> > > > > 
> > > > > The implicit use of the size parameter in the __bdos call is not 
> > > > > always there, it ONLY exists WHEN the __bdos is able to evaluated to 
> > > > > an expression of the size parameter in the “objsz” phase, i.e., the 
> > > > > “Situation 1” of the above example. 
> > > > > In the “Situation 2”, when the __bdos does not see the TYPE of the 
> 

Re: HELP: Will the reordering happen? Re: [V3][PATCH 0/3] New attribute "counted_by" to annotate bounds for C99 FAM(PR108896)

2023-10-25 Thread Martin Uecker
Am Mittwoch, dem 25.10.2023 um 08:43 +0200 schrieb Richard Biener:
> 
> > Am 24.10.2023 um 22:38 schrieb Martin Uecker :
> > 
> > Am Dienstag, dem 24.10.2023 um 20:30 + schrieb Qing Zhao:
> > > Hi, Sid,
> > > 
> > > Really appreciate for your example and detailed explanation. Very helpful.
> > > I think that this example is an excellent example to show (almost) all 
> > > the issues we need to consider.
> > > 
> > > I slightly modified this example to make it to be compilable and 
> > > run-able, as following: 
> > > (but I still cannot make the incorrect reordering or DSE happening, 
> > > anyway, the potential reordering possibility is there…)
> > > 
> > >  1 #include 
> > >  2 struct A
> > >  3 {
> > >  4  size_t size;
> > >  5  char buf[] __attribute__((counted_by(size)));
> > >  6 };
> > >  7 
> > >  8 static size_t
> > >  9 get_size_from (void *ptr)
> > > 10 {
> > > 11  return __builtin_dynamic_object_size (ptr, 1);
> > > 12 }
> > > 13 
> > > 14 void
> > > 15 foo (size_t sz)
> > > 16 {
> > > 17  struct A *obj = __builtin_malloc (sizeof(struct A) + sz * 
> > > sizeof(char));
> > > 18  obj->size = sz;
> > > 19  obj->buf[0] = 2;
> > > 20  __builtin_printf (“%d\n", get_size_from (obj->buf));
> > > 21  return;
> > > 22 }
> > > 23 
> > > 24 int main ()
> > > 25 {
> > > 26  foo (20);
> > > 27  return 0;
> > > 28 }
> > > 
> > > With my GCC, it was compiled and worked:
> > > [opc@qinzhao-ol8u3-x86 ]$  /home/opc/Install/latest-d/bin/gcc -O1 t5.c
> > > [opc@qinzhao-ol8u3-x86 ]$ ./a.out
> > > 20
> > > Situation 1: With O1 and above, the routine “get_size_from” was inlined 
> > > into “foo”, therefore, the call to __bdos is in the same routine as the 
> > > instantiation of the object, and the TYPE information and the attached 
> > > counted_by attribute information in the TYPE of the object can be USED by 
> > > the __bdos call to compute the final object size. 
> > > 
> > > [opc@qinzhao-ol8u3-x86]$  /home/opc/Install/latest-d/bin/gcc -O0  t5.c
> > > [opc@qinzhao-ol8u3-x86 ]$ ./a.out
> > > -1
> > > Situation 2: With O0, the routine “get_size_from” was NOT inlined into 
> > > “foo”, therefore, the call to __bdos is Not in the same routine as the 
> > > instantiation of the object, As a result, the TYPE info and the attached 
> > > counted_by info of the object can NOT be USED by the __bdos call. 
> > > 
> > > Keep in mind of the above 2 situations, we will refer them in below:
> > > 
> > > 1. First,  the problem we are trying to resolve is:
> > > 
> > > (Your description):
> > > 
> > > > the reordering of __bdos w.r.t. initialization of the size parameter 
> > > > but to also account for DSE of the assignment, we can abstract this 
> > > > problem to that of DFA being unable to see implicit use of the size 
> > > > parameter in the __bdos call.
> > > 
> > > basically is correct.  However, with the following exception:
> > > 
> > > The implicit use of the size parameter in the __bdos call is not always 
> > > there, it ONLY exists WHEN the __bdos is able to evaluated to an 
> > > expression of the size parameter in the “objsz” phase, i.e., the 
> > > “Situation 1” of the above example. 
> > > In the “Situation 2”, when the __bdos does not see the TYPE of the real 
> > > object,  it does not see the counted_by information from the TYPE, 
> > > therefore,  it is not able to evaluate the size of the object through the 
> > > counted_by information.  As a result, the implicit use of the size 
> > > parameter in the __bdos call does NOT exist at all.  The optimizer can 
> > > freely reorder the initialization of the size parameter with the __bdos 
> > > call since there is no data flow dependency between these two. 
> > > 
> > > With this exception in mind, we can see that your proposed “option 2” 
> > > (making the type of size “volatile”) is too conservative, it will  
> > > disable many optimizations  unnecessarily, even though it’s safe and 
> > > simple to implement. 
> > > 
> > > As a compiler optimization person for many many years, I really don’t 
> > > want to take this approach at this moment.  -:)
> > > 
> > > 2. Some facts I’d like to

Re: HELP: Will the reordering happen? Re: [V3][PATCH 0/3] New attribute "counted_by" to annotate bounds for C99 FAM(PR108896)

2023-10-24 Thread Martin Uecker
Am Dienstag, dem 24.10.2023 um 22:51 + schrieb Qing Zhao:
> 
> > On Oct 24, 2023, at 4:38 PM, Martin Uecker  wrote:
> > 
> > Am Dienstag, dem 24.10.2023 um 20:30 + schrieb Qing Zhao:
> > > Hi, Sid,
> > > 
> > > Really appreciate for your example and detailed explanation. Very helpful.
> > > I think that this example is an excellent example to show (almost) all 
> > > the issues we need to consider.
> > > 
> > > I slightly modified this example to make it to be compilable and 
> > > run-able, as following: 
> > > (but I still cannot make the incorrect reordering or DSE happening, 
> > > anyway, the potential reordering possibility is there…)
> > > 
> > >  1 #include 
> > >  2 struct A
> > >  3 {
> > >  4  size_t size;
> > >  5  char buf[] __attribute__((counted_by(size)));
> > >  6 };
> > >  7 
> > >  8 static size_t
> > >  9 get_size_from (void *ptr)
> > > 10 {
> > > 11  return __builtin_dynamic_object_size (ptr, 1);
> > > 12 }
> > > 13 
> > > 14 void
> > > 15 foo (size_t sz)
> > > 16 {
> > > 17  struct A *obj = __builtin_malloc (sizeof(struct A) + sz * 
> > > sizeof(char));
> > > 18  obj->size = sz;
> > > 19  obj->buf[0] = 2;
> > > 20  __builtin_printf (“%d\n", get_size_from (obj->buf));
> > > 21  return;
> > > 22 }
> > > 23 
> > > 24 int main ()
> > > 25 {
> > > 26  foo (20);
> > > 27  return 0;
> > > 28 }
> > > 
> > > With my GCC, it was compiled and worked:
> > > [opc@qinzhao-ol8u3-x86 ]$  /home/opc/Install/latest-d/bin/gcc -O1 t5.c
> > > [opc@qinzhao-ol8u3-x86 ]$ ./a.out
> > > 20
> > > Situation 1: With O1 and above, the routine “get_size_from” was inlined 
> > > into “foo”, therefore, the call to __bdos is in the same routine as the 
> > > instantiation of the object, and the TYPE information and the attached 
> > > counted_by attribute information in the TYPE of the object can be USED by 
> > > the __bdos call to compute the final object size. 
> > > 
> > > [opc@qinzhao-ol8u3-x86]$  /home/opc/Install/latest-d/bin/gcc -O0  t5.c
> > > [opc@qinzhao-ol8u3-x86 ]$ ./a.out
> > > -1
> > > Situation 2: With O0, the routine “get_size_from” was NOT inlined into 
> > > “foo”, therefore, the call to __bdos is Not in the same routine as the 
> > > instantiation of the object, As a result, the TYPE info and the attached 
> > > counted_by info of the object can NOT be USED by the __bdos call. 
> > > 
> > > Keep in mind of the above 2 situations, we will refer them in below:
> > > 
> > > 1. First,  the problem we are trying to resolve is:
> > > 
> > > (Your description):
> > > 
> > > > the reordering of __bdos w.r.t. initialization of the size parameter 
> > > > but to also account for DSE of the assignment, we can abstract this 
> > > > problem to that of DFA being unable to see implicit use of the size 
> > > > parameter in the __bdos call.
> > > 
> > > basically is correct.  However, with the following exception:
> > > 
> > > The implicit use of the size parameter in the __bdos call is not always 
> > > there, it ONLY exists WHEN the __bdos is able to evaluated to an 
> > > expression of the size parameter in the “objsz” phase, i.e., the 
> > > “Situation 1” of the above example. 
> > > In the “Situation 2”, when the __bdos does not see the TYPE of the real 
> > > object,  it does not see the counted_by information from the TYPE, 
> > > therefore,  it is not able to evaluate the size of the object through the 
> > > counted_by information.  As a result, the implicit use of the size 
> > > parameter in the __bdos call does NOT exist at all.  The optimizer can 
> > > freely reorder the initialization of the size parameter with the __bdos 
> > > call since there is no data flow dependency between these two. 
> > > 
> > > With this exception in mind, we can see that your proposed “option 2” 
> > > (making the type of size “volatile”) is too conservative, it will  
> > > disable many optimizations  unnecessarily, even though it’s safe and 
> > > simple to implement. 
> > > 
> > > As a compiler optimization person for many many years, I really don’t 
> > > want to take this approach at this moment.  -:)
> > > 
> > > 2. Some facts I’d like to

Re: HELP: Will the reordering happen? Re: [V3][PATCH 0/3] New attribute "counted_by" to annotate bounds for C99 FAM(PR108896)

2023-10-24 Thread Martin Uecker
Am Dienstag, dem 24.10.2023 um 20:30 + schrieb Qing Zhao:
> Hi, Sid,
> 
> Really appreciate for your example and detailed explanation. Very helpful.
> I think that this example is an excellent example to show (almost) all the 
> issues we need to consider.
> 
> I slightly modified this example to make it to be compilable and run-able, as 
> following: 
> (but I still cannot make the incorrect reordering or DSE happening, anyway, 
> the potential reordering possibility is there…)
> 
>   1 #include 
>   2 struct A
>   3 {
>   4  size_t size;
>   5  char buf[] __attribute__((counted_by(size)));
>   6 };
>   7 
>   8 static size_t
>   9 get_size_from (void *ptr)
>  10 {
>  11  return __builtin_dynamic_object_size (ptr, 1);
>  12 }
>  13 
>  14 void
>  15 foo (size_t sz)
>  16 {
>  17  struct A *obj = __builtin_malloc (sizeof(struct A) + sz * sizeof(char));
>  18  obj->size = sz;
>  19  obj->buf[0] = 2;
>  20  __builtin_printf (“%d\n", get_size_from (obj->buf));
>  21  return;
>  22 }
>  23 
>  24 int main ()
>  25 {
>  26  foo (20);
>  27  return 0;
>  28 }
> 
> With my GCC, it was compiled and worked:
> [opc@qinzhao-ol8u3-x86 ]$  /home/opc/Install/latest-d/bin/gcc -O1 t5.c
> [opc@qinzhao-ol8u3-x86 ]$ ./a.out
> 20
> Situation 1: With O1 and above, the routine “get_size_from” was inlined into 
> “foo”, therefore, the call to __bdos is in the same routine as the 
> instantiation of the object, and the TYPE information and the attached 
> counted_by attribute information in the TYPE of the object can be USED by the 
> __bdos call to compute the final object size. 
> 
> [opc@qinzhao-ol8u3-x86]$  /home/opc/Install/latest-d/bin/gcc -O0  t5.c
> [opc@qinzhao-ol8u3-x86 ]$ ./a.out
> -1
> Situation 2: With O0, the routine “get_size_from” was NOT inlined into “foo”, 
> therefore, the call to __bdos is Not in the same routine as the instantiation 
> of the object, As a result, the TYPE info and the attached counted_by info of 
> the object can NOT be USED by the __bdos call. 
> 
> Keep in mind of the above 2 situations, we will refer them in below:
> 
> 1. First,  the problem we are trying to resolve is:
> 
> (Your description):
> 
> >  the reordering of __bdos w.r.t. initialization of the size parameter but 
> > to also account for DSE of the assignment, we can abstract this problem to 
> > that of DFA being unable to see implicit use of the size parameter in the 
> > __bdos call.
> 
> basically is correct.  However, with the following exception:
> 
> The implicit use of the size parameter in the __bdos call is not always 
> there, it ONLY exists WHEN the __bdos is able to evaluated to an expression 
> of the size parameter in the “objsz” phase, i.e., the “Situation 1” of the 
> above example. 
>  In the “Situation 2”, when the __bdos does not see the TYPE of the real 
> object,  it does not see the counted_by information from the TYPE, therefore, 
>  it is not able to evaluate the size of the object through the counted_by 
> information.  As a result, the implicit use of the size parameter in the 
> __bdos call does NOT exist at all.  The optimizer can freely reorder the 
> initialization of the size parameter with the __bdos call since there is no 
> data flow dependency between these two. 
> 
> With this exception in mind, we can see that your proposed “option 2” (making 
> the type of size “volatile”) is too conservative, it will  disable many 
> optimizations  unnecessarily, even though it’s safe and simple to implement. 
> 
> As a compiler optimization person for many many years, I really don’t want to 
> take this approach at this moment.  -:)
> 
> 2. Some facts I’d like to mention:
> 
> A.  The incorrect reordering (or CSE) potential ONLY exists in the TREE 
> optimization stage. During RTL stage,  the __bdos call has already been 
> replaced by an expression of the size parameter or a constant, the data 
> dependency is explicitly in the IR already.  I believe that the data analysis 
> in RTL stage should pick up the data dependency correctly, No special 
> handling is needed in RTL.
> 
> B. If the __bdos call cannot see the real object , it has no way to get the 
> “counted_by” field from the TYPE of the real object. So, if we try to add the 
> implicit use of the “counted_by” field to the __bdos call, the object 
> instantiation should be in the same routine as the __bdos call.  Both the FE 
> and the gimplification phase are too early to do this work. 
> 
> 2. Then, what’s the best approach to resolve this problem:
> 
> There were several suggestions so far:
> 
> A.  Add an additional argument, the size parameter,  to __bdos, 
>   A.1, during FE;
>   A.2, during gimplification phase;
> B.  Encode the implicit USE  in the type of size, to make the size “volatile”;
> C.  Encode the implicit USE  in the type of buf, then update the optimization 
> passes to use this implicit USE encoded in the type of buf.
> 
> As I explained in the above, 
> ** Approach A (both A.1 and A.2) does not work;
> ** Approa

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

2023-10-23 Thread Martin Uecker
Am Montag, dem 23.10.2023 um 12:52 -0700 schrieb Kees Cook:
> On Fri, Oct 20, 2023 at 09:54:05PM +0200, Martin Uecker wrote:
> > Am Freitag, dem 20.10.2023 um 18:48 + schrieb Qing Zhao:
> > > 
> > > > On Oct 20, 2023, at 2:34 PM, Kees Cook  wrote:
> > > > 
> > > > On Fri, Oct 20, 2023 at 11:50:11AM +0200, Martin Uecker wrote:
> > > > > Am Donnerstag, dem 19.10.2023 um 16:33 -0700 schrieb Kees Cook:
> > > > > > On Wed, Oct 18, 2023 at 09:11:43PM +, Qing Zhao wrote:
> > > > > > > As I replied to Martin in another email, I plan to do the 
> > > > > > > following to resolve this issue:
> > > > > > > 
> > > > > > > 1. No specification for signed or unsigned for counted_by field.
> > > > > > > 2. Add a sanitizer option -fsanitize=counted-by-bound to catch 
> > > > > > > the cases when the size of the counted-by is not positive.
> > > > > > 
> > > > > > I don't understand why this needs to be a runtime sanitizer. The
> > > > > > signedness is known at compile time, so I would expect a -W option.
> > > > > 
> > > > > The signedness of the type but not of the value.
> > > > > 
> > > > > But I would not want to have a warning for signed 
> > > > > counter  types by default because I would prefer
> > > > > to use signed types (for various reasons including
> > > > > better overflow detection).
> > > > > 
> > > > > > Or
> > > > > > do you mean you'd split up -fsanitize=bounds between unsigned and 
> > > > > > signed
> > > > > > indexes? I'd find that kind of awkward for the kernel... but I feel 
> > > > > > like
> > > > > > I've misunderstood something. :)
> > > > > > 
> > > > > > -Kees
> > > > > 
> > > > > The idea would be to detect at run-time the case
> > > > > if  x->buf  is used at a time where   x->counter 
> > > > > is negative and also when x->counter * sizeof(x->buf[0])
> > > > > overflows or is too big.
> > > > > 
> > > > > This would be similar to
> > > > > 
> > > > > int a[n];
> > > > > 
> > > > > where it is detected at run-time if n is not-positive.
> > > > 
> > > > Right. I guess what I mean to say is that I would expect this case to
> > > > already be caught by -fsanitize=bounds -- I don't see a reason to add an
> > > > additional sanitizer option.
> > > > 
> > > > struct foo {
> > > > int count;
> > > > int array[] __counted_by(count);
> > > > };
> > > > 
> > > > foo->count = 5;
> > > > foo->array[0] = 1;  // ok
> > > > foo->array[10] = 1; // -fsanitize=bounds will catch this
> > > > foo->array[-10] = 1;// -fsanitize=bounds will catch this too
> > > > 
> > > > 
> > > 
> > > just checked this testing case with my GCC, and YES, -fsanitize=bounds 
> > > indeed caught this error:
> > > 
> > > ttt_1.c:31:12: runtime error: index 10 out of bounds for type 'char [*]'
> > > ttt_1.c:32:12: runtime error: index -10 out of bounds for type 'char [*]’
> > > 
> > 
> > Yes, but I thought we were discussing the case where count is
> > set to a negative value:
> > 
> > foo->count = -1;
> > int x = foo->array[3]; // UBSan should diagnose this
> 
> Oh right, I keep thinking about it backwards.
> 
> Yeah, we can't trap the "count" assignment, because it may be getting used
> for other purposes. But yeah, access to "array" should trap if "count"
> is negative.
> 
> > And also the case when foo->array becomes too big.
> 
> How do you mean?

count * sizeof(member) could overflow or otherwise be
bigger than allowed.

Martin




Re: HELP: Will the reordering happen? Re: [V3][PATCH 0/3] New attribute "counted_by" to annotate bounds for C99 FAM(PR108896)

2023-10-23 Thread Martin Uecker
Am Montag, dem 23.10.2023 um 19:00 + schrieb Qing Zhao:
> 
> > On Oct 23, 2023, at 2:31 PM, Martin Uecker  wrote:
> > 
> > Am Montag, dem 23.10.2023 um 20:06 +0200 schrieb Martin Uecker:
> > > Am Montag, dem 23.10.2023 um 16:37 + schrieb Qing Zhao:
> > > > 
> > > > > On Oct 23, 2023, at 11:57 AM, Richard Biener 
> > > > >  wrote:
> > > > > 
> > > > > 
> > > > > 
> > > > > > Am 23.10.2023 um 16:56 schrieb Qing Zhao :
> > > > > > 
> > > > > > 
> > > > > > 
> > > > > > > On Oct 23, 2023, at 3:57 AM, Richard Biener 
> > > > > > >  wrote:
> > > > > > > 
> > > > > > > > On Fri, Oct 20, 2023 at 10:41 PM Qing Zhao 
> > > > > > > >  wrote:
> > > > > > > > 
> > > > > > > > 
> > > > > > > > 
> > > > > > > > > On Oct 20, 2023, at 3:10 PM, Siddhesh Poyarekar 
> > > > > > > > >  wrote:
> > > > > > > > > 
> > > > > > > > > On 2023-10-20 14:38, Qing Zhao wrote:
> > > > > > > > > > How about the following:
> > > > > > > > > > Add one more parameter to __builtin_dynamic_object_size(), 
> > > > > > > > > > i.e
> > > > > > > > > > __builtin_dynamic_object_size (_1,1,array_annotated->foo)?
> > > > > > > > > > When we see the structure field has counted_by attribute.
> > > > > > > > > 
> > > > > > > > > Or maybe add a barrier preventing any assignments to 
> > > > > > > > > array_annotated->foo from being reordered below the __bdos 
> > > > > > > > > call? Basically an __asm__ with array_annotated->foo in the 
> > > > > > > > > clobber list ought to do it I think.
> > > > > > > > 
> > > > > > > > Maybe just adding the array_annotated->foo to the use list of 
> > > > > > > > the call to __builtin_dynamic_object_size should be enough?
> > > > > > > > 
> > > > > > > > But I am not sure how to implement this in the TREE level, is 
> > > > > > > > there a USE_LIST/CLOBBER_LIST for each call?  Then I can just 
> > > > > > > > simply add the counted_by field “array_annotated->foo” to the 
> > > > > > > > USE_LIST of the call to __bdos?
> > > > > > > > 
> > > > > > > > This might be the simplest solution?
> > > > > > > 
> > > > > > > If the dynamic object size is derived of a field then I think you 
> > > > > > > need to
> > > > > > > put the "load" of that memory location at the point (as argument)
> > > > > > > of the __bos call right at parsing time.  I know that's awkward 
> > > > > > > because
> > > > > > > you try to play tricks "discovering" that field only late, but 
> > > > > > > that's not
> > > > > > > going to work.
> > > > > > 
> > > > > > Is it better to do this at gimplification phase instead of FE? 
> > > > > > 
> > > > > > VLA decls are handled in gimplification phase, the size calculation 
> > > > > > and call to alloca are all generated during this phase. 
> > > > > > (gimplify_vla_decl).
> > > > > > 
> > > > > > For __bdos calls, we can add an additional argument if the object’s 
> > > > > > first argument’s type include the counted_by attribute, i.e
> > > > > > 
> > > > > > ***During gimplification, 
> > > > > > For a call to __builtin_dynamic_object_size (ptr, type)
> > > > > > Check whether the type of ptr includes counted_by attribute, if so, 
> > > > > > change the call to
> > > > > > __builtin_dynamic_object_size (ptr, type, counted_by field)
> > > > > > 
> > > > > > Then the correct data dependence should be represented well in the 
> > > > > > IR.
> > > > > > 
> > > > > > **During object size phase,
> > > > > > 

Re: HELP: Will the reordering happen? Re: [V3][PATCH 0/3] New attribute "counted_by" to annotate bounds for C99 FAM(PR108896)

2023-10-23 Thread Martin Uecker
Am Montag, dem 23.10.2023 um 14:43 -0400 schrieb Siddhesh Poyarekar:
> On 2023-10-23 14:06, Martin Uecker wrote:
> > We should aim for a good integration with the BDOS pass, so
> > that it can propagate the information further, e.g. the
> > following should work:
> > 
> > struct { int L; char buf[] __counted_by(L) } x;
> > x.L = N;
> > x.buf = ...;
> > char *p = &x->f;
> > __bdos(p) -> N
> > 
> > So we need to be smart on how we provide the size
> > information for x->f to the backend.
> > 
> > This would also be desirable for the language extension.
> 
> This is essentially why there need to be frontend rules constraining 
> reordering and reachability semantics of x.L, thus restricting DSE and 
> reordering for it. 

Yes, this too.

>  This is not really a __bdos/__bos question, because 
> that bit is trivial; if the structure is visible, the value is simply 
> x.L.  This is also why adding a reference to x.L in __bos/__bdos is not 
> sufficient or even possible in, e.g. the above case you note.

The value x.L may change in time. I would argue that it needs
to be the value of x.L at the time where x.buf (not x->f, sorry) 
is accessed.  So the FE needs to evaluate x.L when x.buf is
accessed and store the value somewhere where __bdos can find
it later.  In the type information would make sense.

But I am not sure how to do this in the best way so that this 
information is not removed later when not used explicitely
before __bdos tries to look at it.

Martin





Re: HELP: Will the reordering happen? Re: [V3][PATCH 0/3] New attribute "counted_by" to annotate bounds for C99 FAM(PR108896)

2023-10-23 Thread Martin Uecker
Am Montag, dem 23.10.2023 um 20:06 +0200 schrieb Martin Uecker:
> Am Montag, dem 23.10.2023 um 16:37 + schrieb Qing Zhao:
> > 
> > > On Oct 23, 2023, at 11:57 AM, Richard Biener  
> > > wrote:
> > > 
> > > 
> > > 
> > > > Am 23.10.2023 um 16:56 schrieb Qing Zhao :
> > > > 
> > > > 
> > > > 
> > > > > On Oct 23, 2023, at 3:57 AM, Richard Biener 
> > > > >  wrote:
> > > > > 
> > > > > > On Fri, Oct 20, 2023 at 10:41 PM Qing Zhao  
> > > > > > wrote:
> > > > > > 
> > > > > > 
> > > > > > 
> > > > > > > On Oct 20, 2023, at 3:10 PM, Siddhesh Poyarekar 
> > > > > > >  wrote:
> > > > > > > 
> > > > > > > On 2023-10-20 14:38, Qing Zhao wrote:
> > > > > > > > How about the following:
> > > > > > > > Add one more parameter to __builtin_dynamic_object_size(), i.e
> > > > > > > > __builtin_dynamic_object_size (_1,1,array_annotated->foo)?
> > > > > > > > When we see the structure field has counted_by attribute.
> > > > > > > 
> > > > > > > Or maybe add a barrier preventing any assignments to 
> > > > > > > array_annotated->foo from being reordered below the __bdos call? 
> > > > > > > Basically an __asm__ with array_annotated->foo in the clobber 
> > > > > > > list ought to do it I think.
> > > > > > 
> > > > > > Maybe just adding the array_annotated->foo to the use list of the 
> > > > > > call to __builtin_dynamic_object_size should be enough?
> > > > > > 
> > > > > > But I am not sure how to implement this in the TREE level, is there 
> > > > > > a USE_LIST/CLOBBER_LIST for each call?  Then I can just simply add 
> > > > > > the counted_by field “array_annotated->foo” to the USE_LIST of the 
> > > > > > call to __bdos?
> > > > > > 
> > > > > > This might be the simplest solution?
> > > > > 
> > > > > If the dynamic object size is derived of a field then I think you 
> > > > > need to
> > > > > put the "load" of that memory location at the point (as argument)
> > > > > of the __bos call right at parsing time.  I know that's awkward 
> > > > > because
> > > > > you try to play tricks "discovering" that field only late, but that's 
> > > > > not
> > > > > going to work.
> > > > 
> > > > Is it better to do this at gimplification phase instead of FE? 
> > > > 
> > > > VLA decls are handled in gimplification phase, the size calculation and 
> > > > call to alloca are all generated during this phase. (gimplify_vla_decl).
> > > > 
> > > > For __bdos calls, we can add an additional argument if the object’s 
> > > > first argument’s type include the counted_by attribute, i.e
> > > > 
> > > > ***During gimplification, 
> > > > For a call to __builtin_dynamic_object_size (ptr, type)
> > > > Check whether the type of ptr includes counted_by attribute, if so, 
> > > > change the call to
> > > > __builtin_dynamic_object_size (ptr, type, counted_by field)
> > > > 
> > > > Then the correct data dependence should be represented well in the IR.
> > > > 
> > > > **During object size phase,
> > > > 
> > > > The call to __builtin_dynamic_object_size will become an expression 
> > > > includes the counted_by field or -1/0 when we cannot decide the size, 
> > > > the correct data dependence will be kept even the call to 
> > > > __builtin_dynamic_object_size is gone. 
> > > 
> > > But the whole point of the BOS pass is to derive information that is not 
> > > available at parsing time, and that’s the cases you are after.  The case 
> > > where the connection to the field with the length is apparent during 
> > > parsing is easy - you simply insert a load of the value before the BOS 
> > > call.
> > 
> > Yes, this is true. 
> > I prefer to implement this in gimplification phase since I am more familiar 
> > with the code there.. (I think that implementing it in gimplification 
> > should be very similar as implemen

Re: HELP: Will the reordering happen? Re: [V3][PATCH 0/3] New attribute "counted_by" to annotate bounds for C99 FAM(PR108896)

2023-10-23 Thread Martin Uecker
Am Montag, dem 23.10.2023 um 16:37 + schrieb Qing Zhao:
> 
> > On Oct 23, 2023, at 11:57 AM, Richard Biener  
> > wrote:
> > 
> > 
> > 
> > > Am 23.10.2023 um 16:56 schrieb Qing Zhao :
> > > 
> > > 
> > > 
> > > > On Oct 23, 2023, at 3:57 AM, Richard Biener 
> > > >  wrote:
> > > > 
> > > > > On Fri, Oct 20, 2023 at 10:41 PM Qing Zhao  
> > > > > wrote:
> > > > > 
> > > > > 
> > > > > 
> > > > > > On Oct 20, 2023, at 3:10 PM, Siddhesh Poyarekar 
> > > > > >  wrote:
> > > > > > 
> > > > > > On 2023-10-20 14:38, Qing Zhao wrote:
> > > > > > > How about the following:
> > > > > > > Add one more parameter to __builtin_dynamic_object_size(), i.e
> > > > > > > __builtin_dynamic_object_size (_1,1,array_annotated->foo)?
> > > > > > > When we see the structure field has counted_by attribute.
> > > > > > 
> > > > > > Or maybe add a barrier preventing any assignments to 
> > > > > > array_annotated->foo from being reordered below the __bdos call? 
> > > > > > Basically an __asm__ with array_annotated->foo in the clobber list 
> > > > > > ought to do it I think.
> > > > > 
> > > > > Maybe just adding the array_annotated->foo to the use list of the 
> > > > > call to __builtin_dynamic_object_size should be enough?
> > > > > 
> > > > > But I am not sure how to implement this in the TREE level, is there a 
> > > > > USE_LIST/CLOBBER_LIST for each call?  Then I can just simply add the 
> > > > > counted_by field “array_annotated->foo” to the USE_LIST of the call 
> > > > > to __bdos?
> > > > > 
> > > > > This might be the simplest solution?
> > > > 
> > > > If the dynamic object size is derived of a field then I think you need 
> > > > to
> > > > put the "load" of that memory location at the point (as argument)
> > > > of the __bos call right at parsing time.  I know that's awkward because
> > > > you try to play tricks "discovering" that field only late, but that's 
> > > > not
> > > > going to work.
> > > 
> > > Is it better to do this at gimplification phase instead of FE? 
> > > 
> > > VLA decls are handled in gimplification phase, the size calculation and 
> > > call to alloca are all generated during this phase. (gimplify_vla_decl).
> > > 
> > > For __bdos calls, we can add an additional argument if the object’s first 
> > > argument’s type include the counted_by attribute, i.e
> > > 
> > > ***During gimplification, 
> > > For a call to __builtin_dynamic_object_size (ptr, type)
> > > Check whether the type of ptr includes counted_by attribute, if so, 
> > > change the call to
> > > __builtin_dynamic_object_size (ptr, type, counted_by field)
> > > 
> > > Then the correct data dependence should be represented well in the IR.
> > > 
> > > **During object size phase,
> > > 
> > > The call to __builtin_dynamic_object_size will become an expression 
> > > includes the counted_by field or -1/0 when we cannot decide the size, the 
> > > correct data dependence will be kept even the call to 
> > > __builtin_dynamic_object_size is gone. 
> > 
> > But the whole point of the BOS pass is to derive information that is not 
> > available at parsing time, and that’s the cases you are after.  The case 
> > where the connection to the field with the length is apparent during 
> > parsing is easy - you simply insert a load of the value before the BOS call.
> 
> Yes, this is true. 
> I prefer to implement this in gimplification phase since I am more familiar 
> with the code there.. (I think that implementing it in gimplification should 
> be very similar as implementing it in FE? Or do I miss anything here?)
> 
> Joseph, if implement this in FE, where in the FE I should look at? 
> 

We should aim for a good integration with the BDOS pass, so
that it can propagate the information further, e.g. the 
following should work:

struct { int L; char buf[] __counted_by(L) } x;
x.L = N;
x.buf = ...;
char *p = &x->f;
__bdos(p) -> N

So we need to be smart on how we provide the size
information for x->f to the backend. 

This would also be desirable for the language extension. 

Martin


> Thanks a lot for the help.
> 
> Qing
> 
> >  For the late case there’s no way to invent data flow dependence without 
> > inadvertently pessimizing optimization.
> > 
> > Richard 
> > 
> > > 
> > > > 
> > > > A related issue is that assignment to the field and storage allocation
> > > > are not tied together
> > > 
> > > Yes, this is different from VLA, in which, the size assignment and the 
> > > storage allocation are generated and tied together by the compiler.
> > > 
> > > For the flexible array member, the storage allocation and the size 
> > > assignment are all done by the user. So, We need to clarify such 
> > > requirement  in the document to guide user to write correct code.  And 
> > > also, we might need to provide tools (warnings and sanitizer option) to 
> > > help users to catch such coding error.
> > > 
> > > > - if there's no use of the size data we might
> > > > remove the store of it as dead.
> > > 
> > > Yes, when __bdos cannot decide 

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

2023-10-21 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.

c: Synthesize nonnull attribute for parameters declared with static 
[PR110815]

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.

PR c/102558
PR 102556
PR c/110815

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 b70d67dc47b..b8e89d01088 100644
--- a/gcc/gimple-ssa-warn-access.cc
+++ b/gcc/gimple-ssa-warn-access.cc
@@ -3491,16 +3491,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" } 

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

2023-10-20 Thread Martin Uecker
Am Freitag, dem 20.10.2023 um 18:48 + schrieb Qing Zhao:
> 
> > On Oct 20, 2023, at 2:34 PM, Kees Cook  wrote:
> > 
> > On Fri, Oct 20, 2023 at 11:50:11AM +0200, Martin Uecker wrote:
> > > Am Donnerstag, dem 19.10.2023 um 16:33 -0700 schrieb Kees Cook:
> > > > On Wed, Oct 18, 2023 at 09:11:43PM +, Qing Zhao wrote:
> > > > > As I replied to Martin in another email, I plan to do the following 
> > > > > to resolve this issue:
> > > > > 
> > > > > 1. No specification for signed or unsigned for counted_by field.
> > > > > 2. Add a sanitizer option -fsanitize=counted-by-bound to catch the 
> > > > > cases when the size of the counted-by is not positive.
> > > > 
> > > > I don't understand why this needs to be a runtime sanitizer. The
> > > > signedness is known at compile time, so I would expect a -W option.
> > > 
> > > The signedness of the type but not of the value.
> > > 
> > > But I would not want to have a warning for signed 
> > > counter  types by default because I would prefer
> > > to use signed types (for various reasons including
> > > better overflow detection).
> > > 
> > > > Or
> > > > do you mean you'd split up -fsanitize=bounds between unsigned and signed
> > > > indexes? I'd find that kind of awkward for the kernel... but I feel like
> > > > I've misunderstood something. :)
> > > > 
> > > > -Kees
> > > 
> > > The idea would be to detect at run-time the case
> > > if  x->buf  is used at a time where   x->counter 
> > > is negative and also when x->counter * sizeof(x->buf[0])
> > > overflows or is too big.
> > > 
> > > This would be similar to
> > > 
> > > int a[n];
> > > 
> > > where it is detected at run-time if n is not-positive.
> > 
> > Right. I guess what I mean to say is that I would expect this case to
> > already be caught by -fsanitize=bounds -- I don't see a reason to add an
> > additional sanitizer option.
> > 
> > struct foo {
> > int count;
> > int array[] __counted_by(count);
> > };
> > 
> > foo->count = 5;
> > foo->array[0] = 1;  // ok
> > foo->array[10] = 1; // -fsanitize=bounds will catch this
> > foo->array[-10] = 1;// -fsanitize=bounds will catch this too
> > 
> > 
> 
> just checked this testing case with my GCC, and YES, -fsanitize=bounds indeed 
> caught this error:
> 
> ttt_1.c:31:12: runtime error: index 10 out of bounds for type 'char [*]'
> ttt_1.c:32:12: runtime error: index -10 out of bounds for type 'char [*]’
> 

Yes, but I thought we were discussing the case where count is
set to a negative value:

foo->count = -1;
int x = foo->array[3]; // UBSan should diagnose this

And also the case when foo->array becomes too big.

Martin





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

2023-10-20 Thread Martin Uecker
Am Donnerstag, dem 19.10.2023 um 16:33 -0700 schrieb Kees Cook:
> On Wed, Oct 18, 2023 at 09:11:43PM +, Qing Zhao wrote:
> > As I replied to Martin in another email, I plan to do the following to 
> > resolve this issue:
> > 
> > 1. No specification for signed or unsigned for counted_by field.
> > 2. Add a sanitizer option -fsanitize=counted-by-bound to catch the cases 
> > when the size of the counted-by is not positive.
> 
> I don't understand why this needs to be a runtime sanitizer. The
> signedness is known at compile time, so I would expect a -W option.

The signedness of the type but not of the value.

But I would not want to have a warning for signed 
counter  types by default because I would prefer
to use signed types (for various reasons including
better overflow detection).

>  Or
> do you mean you'd split up -fsanitize=bounds between unsigned and signed
> indexes? I'd find that kind of awkward for the kernel... but I feel like
> I've misunderstood something. :)
> 
> -Kees

The idea would be to detect at run-time the case
if  x->buf  is used at a time where   x->counter 
is negative and also when x->counter * sizeof(x->buf[0])
overflows or is too big.

This would be similar to

int a[n];

where it is detected at run-time if n is not-positive.

Martin






[C PATCH] error for function with external and internal linkage [PR111708]

2023-10-14 Thread Martin Uecker


Bootstrapped and regression tested on x86_64.


c: error for function with external and internal linkage [PR111708]

Declaring a function with both external and internal linkage
in the same TU is translation-time UB.  Add an error for this
case as already done for objects.

PR c/111708

gcc/c/Changelog:

* c-decl.cc (grokdeclarator): Add error.

gcc/testsuite/Changelog:

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

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 5822faf01b4..52490a784d0 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -8032,6 +8032,28 @@ grokdeclarator (const struct c_declarator *declarator,
TREE_THIS_VOLATILE (decl) = 1;
  }
  }
+
+   /* C99 6.2.2p7: It is invalid (compile-time undefined
+  behavior) to create an 'extern' declaration for a
+  function if there is a global declaration that is
+  'static' and the global declaration is not visible.
+  (If the static declaration _is_ currently visible,
+  the 'extern' declaration is taken to refer to that decl.) */
+   if (!initialized
+   && storage_class != csc_static
+   && storage_class != csc_auto
+   && current_scope != file_scope)
+ {
+   tree global_decl  = identifier_global_value (declarator->u.id.id);
+   tree visible_decl = lookup_name (declarator->u.id.id);
+
+   if (global_decl
+   && global_decl != visible_decl
+   && VAR_OR_FUNCTION_DECL_P (global_decl)
+   && !TREE_PUBLIC (global_decl))
+ error_at (loc, "function previously declared % "
+   "redeclared %");
+ }
   }
 else
   {
diff --git a/gcc/testsuite/gcc.dg/pr111708-1.c 
b/gcc/testsuite/gcc.dg/pr111708-1.c
new file mode 100644
index 000..4af7f53d75f
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr111708-1.c
@@ -0,0 +1,42 @@
+/* { dg-do compile } */
+/* { dg-options "" } */
+
+extern int a(void);// external linkage (6.2.2p4)
+static int a(void);/* { dg-error "static declaration of 'a' follows 
non-static declaration" } */
+
+static int b(void);// internal linkage (6.2.2p3)
+extern int b(void);// internal linkage (6.2.2p4)
+
+static int h0(void);
+
+void s(void)
+{
+   extern int h0(void);// internal linkage (6.2.2p4),
+   extern int h0(void);// internal linkage (6.2.2p4), redeclaration, ok
+   extern int h2(void);// external linkage (6.2.2p4)
+   extern int h2(void);// external linkage (6.2.2p4), redeclaration, 
ok.
+}
+
+
+extern int i(void);// external linkage (6.2.2p4)
+static int j(void);// internal linkage (6.2.2p3)
+
+void bar(void)
+{
+   extern int i(void); // external linkage (6.2.2p4), ok
+}
+
+void foo(void)
+{
+   extern int j(void); // internal linkage (6.2.2p4), ok, internal
+}
+
+void x(void)
+{
+   int i(void);// no linkage (6.2.2p6)
+   int j;  // no linkage (6.2.2p6)
+   {
+   extern int j(void); /* { dg-error "function previously 
declared 'static' redeclared 'extern'" } */
+   }
+}
+
diff --git a/gcc/testsuite/gcc.dg/pr111708-2.c 
b/gcc/testsuite/gcc.dg/pr111708-2.c
new file mode 100644
index 000..065c0525c2e
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr111708-2.c
@@ -0,0 +1,21 @@
+/* { dg-do compile } */
+/* { dg-options "" } */
+/* { dg-require-effective-target trampolines } */
+
+static void pp(void)
+{
+   int pp;
+   {
+   auto void pp(void);
+   void pp(void) { }
+   }
+}
+
+static void q2(void);
+
+static void qq(void)
+{
+   auto void q2(void);
+   void q2(void) { }
+}
+



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

2023-10-06 Thread Martin Uecker
Am Freitag, dem 06.10.2023 um 06:50 -0400 schrieb Siddhesh Poyarekar:
> On 2023-10-06 01:11, Martin Uecker wrote:
> > Am Donnerstag, dem 05.10.2023 um 15:35 -0700 schrieb Kees Cook:
> > > On Thu, Oct 05, 2023 at 04:08:52PM -0400, Siddhesh Poyarekar wrote:
> > > > 2. How would you handle signedness of the size field?  The size gets
> > > > converted to sizetype everywhere it is used and overflows/underflows may
> > > > produce interesting results.  Do you want to limit the types to 
> > > > unsigned or
> > > > do you want to add a disclaimer in the docs?  The former seems like the
> > > > *right* thing to do given that it is a new feature; best to enforce the
> > > > cleaner habit at the outset.
> > > 
> > > The Linux kernel has a lot of "int" counters, so the goal is to catch
> > > negative offsets just like too-large offsets at runtime with the sanitizer
> > > and report 0 for __bdos. Refactoring all these to be unsigned is going
> > > to take time since at least some of them use the negative values as
> > > special values unrelated to array indexing. :(
> > > 
> > > So, perhaps if unsigned counters are worth enforcing, can this be a
> > > separate warning the kernel can turn off initially?
> > > 
> > 
> > I think unsigned counters are much more problematic than signed ones
> > because wraparound errors are more difficult to find.
> > 
> > With unsigned you could potentially diagnose wraparound, but only if we
> > add -fsanitize=unsigned-overflow *and* add mechanism to mark intentional
> > wraparound *and* everybody adds this annotation after carefully screening
> > their code *and* rewriting all operations such as (counter - 3) + 5
> > where the wraparound in the intermediate expression is harmless.
> > 
> > For this reason, I do not think we should ever enforce some rule that
> > the counter has to be unsigned.
> > 
> > What we could do, is detect *storing* negative values into the
> > counter at run-time using UBSan. (but if negative values are
> > used for special cases, one also should be able to turn this
> > off).
> 
> All of the object size detection relies on object sizes being sizetype. 
> The closest we could do with that is detect (sz != SIZE_MAX && sz > 
> size_t / 2), since allocators typically cannot allocate more than 
> SIZE_MAX / 2.

I was talking about the counter in:

struct {
  int counter;
  char buf[] __counted_by__((counter))
};

which could be checked to be positive either when stored to or 
when buf is used.

And yes, we could also check the size of buf.  Not sure what is
done for VLAs now, but I guess it could be similar.

Best,
Martin



> 
> Sid



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

2023-10-05 Thread Martin Uecker
Am Donnerstag, dem 05.10.2023 um 15:35 -0700 schrieb Kees Cook:
> On Thu, Oct 05, 2023 at 04:08:52PM -0400, Siddhesh Poyarekar wrote:
> > 2. How would you handle signedness of the size field?  The size gets
> > converted to sizetype everywhere it is used and overflows/underflows may
> > produce interesting results.  Do you want to limit the types to unsigned or
> > do you want to add a disclaimer in the docs?  The former seems like the
> > *right* thing to do given that it is a new feature; best to enforce the
> > cleaner habit at the outset.
> 
> The Linux kernel has a lot of "int" counters, so the goal is to catch
> negative offsets just like too-large offsets at runtime with the sanitizer
> and report 0 for __bdos. Refactoring all these to be unsigned is going
> to take time since at least some of them use the negative values as
> special values unrelated to array indexing. :(
> 
> So, perhaps if unsigned counters are worth enforcing, can this be a
> separate warning the kernel can turn off initially?
> 

I think unsigned counters are much more problematic than signed ones
because wraparound errors are more difficult to find.

With unsigned you could potentially diagnose wraparound, but only if we
add -fsanitize=unsigned-overflow *and* add mechanism to mark intentional
wraparound *and* everybody adds this annotation after carefully screening
their code *and* rewriting all operations such as (counter - 3) + 5
where the wraparound in the intermediate expression is harmless.

For this reason, I do not think we should ever enforce some rule that
the counter has to be unsigned.

What we could do, is detect *storing* negative values into the
counter at run-time using UBSan. (but if negative values are
used for special cases, one also should be able to turn this
off).

Martin







Re: [PATCH v2] C, ObjC: Add -Wunterminated-string-initialization

2023-10-01 Thread Martin Uecker


(I shortened the recipient list)

Am Sonntag, dem 01.10.2023 um 02:55 +0200 schrieb Alejandro Colomar:

> > 
...
> I ran the tests, and get some unexpected failure.  I used dg-warning,
> but maybe I used it wrong?  Here's the output:
> 
> ```
> output is:
> /home/alx/src/gnu/gcc/wustr/gcc/testsuite/gcc.dg/Wunterminated-string-initialization.c:5:14:
>  warning: initializer-string for array of 'char' is too long 
> [-Wunterminated-string-initi
> alization]
> 
> FAIL: gcc.dg/Wunterminated-string-initialization.c  (test for warnings, line 
> 5)
> ```
> 
> And here's the test:
> 
> ```
> /* { dg-do compile } */
> /* { dg-options "-Wunterminated-string-initialization" } */
> 
> char a1[] = "a";
> char a2[1] = "a"; /* { dg-warning "unterminated char sequence" } */
> char a3[2] = "a";
> ```
> 
> Why isn't it expecting the warning?

Because the text does not match the actual output above?
You should see an additional FAIL for an excess warning.

Martin






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

2023-09-24 Thread Martin Uecker
Am Mittwoch, dem 26.07.2023 um 18:06 +0200 schrieb 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.

c: Synthesize nonnull attribute for parameters declared with static 
[PR110815]

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.

PR c/102558
PR 102556
PR c/110815

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 b70d67dc47b..b8e89d01088 100644
--- a/gcc/gimple-ssa-warn-access.cc
+++ b/gcc/gimple-ssa-warn-access.cc
@@ -3491,16 +3491,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

[C PATCH, v2] Add Walloc-size to warn about insufficient size in allocations [PR71219]

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



Compared to the previous version I changed the name of the
warning to "Walloc-size" which matches "Wanalyzer-allocation-size"
but is still in line with the other -Walloc-something warnings
we have. I also added it to Wextra.

I found PR71219 that requests the warning and points out that 
it is recommended by the C secure coding guidelines and added
the PR to the commit log  (although the version with cast is not
diagnosed so far.)  

I did not have time to implement the extensions suggested
on the list,  i.e. warn when the size is not a multiple
of the size of the type and warn for if the size is not
suitable for a flexible array member. (this is also a bit
more complicated than it seems)

Bootstrapped and regression tested on x86_64.


Martin


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

PR c/71219
gcc:
* doc/invoke.texi: Document -Walloc-size option.

gcc/c-family:

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

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

gcc/testsuite:

* gcc.dg/Walloc-size-1.c: New test.
---
 gcc/c-family/c.opt   |  4 
 gcc/c/c-typeck.cc| 27 +
 gcc/doc/invoke.texi  | 10 
 gcc/testsuite/gcc.dg/Walloc-size-1.c | 36 
 4 files changed, 77 insertions(+)
 create mode 100644 gcc/testsuite/gcc.dg/Walloc-size-1.c

diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 7348ad42ee0..9ba08a1fb6d 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-size
+C ObjC Var(warn_alloc_size) 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 e2bfd2caf85..c759c6245ed 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -7384,6 +7384,33 @@ 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 that are not big enough for the target
+type.  */
+  tree fndecl;
+  if (warn_alloc_size
+ && 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_size, "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 33befee7d6b..a4fbcf5e1b5 100644
--- a/gcc/doc/invoke.texi
+++ b/gcc/doc/invoke.texi
@@ -8086,6 +8086,16 @@ 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-size
+@opindex Walloc-size
+@item -Walloc-size
+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-size-1.c 
b/gcc/testsuite/gcc.dg/Walloc-size-1.c
new file mode 100644
index 000..61806f58192
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/Walloc-size-1.c
@@ -0,0 +1,36 @@
+/* Tests the warnings for insufficient allocation size.
+   { dg-do compile }
+   { dg-options "-Walloc-size" }
+ * */
+#include 
+#include 
+
+struct 

Re: RFC: Introduce -fhardened to enable security-related flags

2023-09-16 Thread Martin Uecker
Am Freitag, dem 15.09.2023 um 11:11 -0400 schrieb Marek Polacek:
> On Wed, Aug 30, 2023 at 10:46:14AM +0200, Martin Uecker wrote:
> > > Improving the security of software has been a major trend in the recent
> > > years.  Fortunately, GCC offers a wide variety of flags that enable extra
> > > hardening.  These flags aren't enabled by default, though.  And since
> > > there are a lot of hardening flags, with more to come, it's been difficult
> > > to keep on top of them; more so for the users of GCC who ought not to be
> > > expected to keep track of all the new options.
> > > 
> > > To alleviate some of the problems I mentioned, we thought it would
> > > be useful to provide a new umbrella option that enables a reasonable set
> > > of hardening flags.  What's "reasonable" in this context is not easy to
> > > pin down.  Surely, there must be no ABI impact, the option cannot cause
> > > severe performance issues, and, I suspect, it should not cause build
> > > errors by enabling stricter compile-time errors (such as, -Wimplicit-int,
> > > -Wint-conversion).  Including a controversial option in -fhardened
> > > would likely cause that users would not use -fhardened at all.  It's
> > > roughly akin to -Wall or -O2 -- those also enable a reasonable set of
> > > options, and evolve over time, and are not kept in sync with other
> > > compilers.
> > > 
> > > Currently, -fhardened enables:
> > > 
> > >   -D_FORTIFY_SOURCE=3 (or =2 for older glibcs)
> > >   -D_GLIBCXX_ASSERTIONS
> > >   -ftrivial-auto-var-init=zero
> > >   -fPIE  -pie  -Wl,-z,relro,-z,now
> > >   -fstack-protector-strong
> > >   -fstack-clash-protection
> > >   -fcf-protection=full (x86 GNU/Linux only)
> > > 
> > > -fsanitize=undefined is specifically not enabled.  -fstrict-flex-arrays is
> > > also liable to break a lot of code so I didn't include it.
> > > 
> > > Appended is a proof-of-concept patch.  It doesn't implement 
> > > --help=hardened
> > > yet.  A fairly crucial point is that -fhardened will not override options
> > > that were specified on the command line (before or after -fhardened).  For
> > > example,
> > >  
> > >  -D_FORTIFY_SOURCE=1 -fhardened
> > > 
> > > means that _FORTIFY_SOURCE=1 will be used.  Similarly,
> > > 
> > >   -fhardened -fstack-protector
> > > 
> > > will not enable -fstack-protector-strong.
> > > 
> > > Thoughts?
> > 
> > I think this is a great idea!  Considering that it is difficult to
> > decide what shoud be activated and what not and the baseline should
> > not cause compile errors,  I wonder whether there should be higher
> > levels  similar to -O1,2,3 ? 
>  
> Thanks.  I would like to avoid any levels if at all possible; I think
> they would be confusing.
> 
> > Although it would be nice to have a one-letter or very short
> > option similar to -O2 or -Wall, but maybe this is not possible 
> > because all short ones are already taken. Of course, 
> > "-fhardening" would  already a huge  improvement to the 
> > current situation.
> 
> There are some free ones, like -Z, but I'm not confident I could take
> it :).
> 

It would send a message.

Today I can get crazy optimizations with 

-O3 

but for (somewhat) decent security, I need something
like:

 -D_FORTIFY_SOURCE=3 (or =2 for older glibcs)
  -D_GLIBCXX_ASSERTIONS
  -ftrivial-auto-var-init=pattern
  -fPIE  -pie  -Wl,-z,relro,-z,now
  -fstack-protector-strong
  -fstack-clash-protection
  -fcf-protection=full 
  -fsanitize=undefined
  -fsanitize-undefined-trap-on-error
  -Wall
  -Wextra

which also sends a message.

Martin





[C PATCH 1/6 v2] c: reorganize recursive type checking

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


Thanks Joseph, below is a a revised version of this patch
with slight additional changes to the comment of
tagged_types_tu_compatible_p.

ok for trunk? 

Martin

Am Mittwoch, dem 06.09.2023 um 20:59 + schrieb Joseph Myers:
> On Sat, 26 Aug 2023, Martin Uecker via Gcc-patches wrote:
> 
> > -static int
> > +static bool
> >  comp_target_types (location_t location, tree ttl, tree ttr)
> 
> The comment above this function should be updated to refer to returning 
> true, not to returning 1.  And other comments on common_pointer_type and 
> inside that function should be updated to refer to comp_target_types 
> returning true, not nonzero.
> 
> > @@ -1395,17 +1382,13 @@ free_all_tagged_tu_seen_up_to (const struct 
> > tagged_tu_seen_cache *tu_til)
> >  
> >  /* Return 1 if two 'struct', 'union', or 'enum' types T1 and T2 are
> > compatible.  If the two types are not the same (which has been
> > -   checked earlier), this can only happen when multiple translation
> > -   units are being compiled.  See C99 6.2.7 paragraph 1 for the exact
> > -   rules.  ENUM_AND_INT_P and DIFFERENT_TYPES_P are as in
> > -   comptypes_internal.  */
> > +   checked earlier).  */
> >  
> > -static int
> > +static bool
> >  tagged_types_tu_compatible_p (const_tree t1, const_tree t2,
> > - bool *enum_and_int_p, bool *different_types_p)
> > + struct comptypes_data* data)
> 
> Similarly, this comment should be updated for the new return type.  Also 
> the GNU style is "struct comptypes_data *data" with space before not after 
> '*'.
> 
> > @@ -1631,9 +1603,9 @@ tagged_types_tu_compatible_p (const_tree t1, 
> > const_tree t2,
> > Otherwise, the argument types must match.
> > ENUM_AND_INT_P and DIFFERENT_TYPES_P are as in comptypes_internal.  */
> >  
> > -static int
> > +static bool
> >  function_types_compatible_p (const_tree f1, const_tree f2,
> > -bool *enum_and_int_p, bool *different_types_p)
> > +struct comptypes_data *data)
> 
> Another comment to update for a changed return type.
> 
> >  /* Check two lists of types for compatibility, returning 0 for
> > -   incompatible, 1 for compatible, or 2 for compatible with
> > -   warning.  ENUM_AND_INT_P and DIFFERENT_TYPES_P are as in
> > -   comptypes_internal.  */
> > +   incompatible, 1 for compatible.  ENUM_AND_INT_P and
> > +   DIFFERENT_TYPES_P are as in comptypes_internal.  */
> >  
> > -static int
> > +static bool
> >  type_lists_compatible_p (const_tree args1, const_tree args2,
> > -bool *enum_and_int_p, bool *different_types_p)
> > +struct comptypes_data *data)
> 
> This one also needs updating to remove references to parameters that no 
> longer exist.
> 

c: reorganize recursive type checking

Reorganize recursive type checking to use a structure to
store information collected during the recursion and
returned to the caller (warning_needed, 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,
comptypes_internal): Add structure to interface, change
return type to bool, and adapt calls.
(comptarget_types): Change return type too bool.
(comptypes, comptypes_check_enum_int,
comptypes_check_different_types): Adapt calls.
---
 gcc/c/c-typeck.cc | 282 --
 1 file changed, 121 insertions(+), 161 deletions(-)

diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index e2bfd2caf85..e55e887da14 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 *);
-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 *);
+struct comptypes_data;
+static bool tagged_types_tu_compatible_p (const_tree, const_tree,
+ struct comptypes_data *);
+static bool comp_target_types (location_t, tree, tree);
+static bool function_types_compatible_p (const_tree, const_tree,
+struct comptypes_data *);
+static bool type_lists_compatible_p (const_tree, cons

Re: RFC: Introduce -fhardened to enable security-related flags

2023-08-30 Thread Martin Uecker
> Improving the security of software has been a major trend in the recent
> years.  Fortunately, GCC offers a wide variety of flags that enable extra
> hardening.  These flags aren't enabled by default, though.  And since
> there are a lot of hardening flags, with more to come, it's been difficult
> to keep on top of them; more so for the users of GCC who ought not to be
> expected to keep track of all the new options.
> 
> To alleviate some of the problems I mentioned, we thought it would
> be useful to provide a new umbrella option that enables a reasonable set
> of hardening flags.  What's "reasonable" in this context is not easy to
> pin down.  Surely, there must be no ABI impact, the option cannot cause
> severe performance issues, and, I suspect, it should not cause build
> errors by enabling stricter compile-time errors (such as, -Wimplicit-int,
> -Wint-conversion).  Including a controversial option in -fhardened
> would likely cause that users would not use -fhardened at all.  It's
> roughly akin to -Wall or -O2 -- those also enable a reasonable set of
> options, and evolve over time, and are not kept in sync with other
> compilers.
> 
> Currently, -fhardened enables:
> 
>   -D_FORTIFY_SOURCE=3 (or =2 for older glibcs)
>   -D_GLIBCXX_ASSERTIONS
>   -ftrivial-auto-var-init=zero
>   -fPIE  -pie  -Wl,-z,relro,-z,now
>   -fstack-protector-strong
>   -fstack-clash-protection
>   -fcf-protection=full (x86 GNU/Linux only)
> 
> -fsanitize=undefined is specifically not enabled.  -fstrict-flex-arrays is
> also liable to break a lot of code so I didn't include it.
> 
> Appended is a proof-of-concept patch.  It doesn't implement --help=hardened
> yet.  A fairly crucial point is that -fhardened will not override options
> that were specified on the command line (before or after -fhardened).  For
> example,
>  
>  -D_FORTIFY_SOURCE=1 -fhardened
> 
> means that _FORTIFY_SOURCE=1 will be used.  Similarly,
> 
>   -fhardened -fstack-protector
> 
> will not enable -fstack-protector-strong.
> 
> Thoughts?

I think this is a great idea!  Considering that it is difficult to
decide what shoud be activated and what not and the baseline should
not cause compile errors,  I wonder whether there should be higher
levels  similar to -O1,2,3 ? 

Although it would be nice to have a one-letter or very short
option similar to -O2 or -Wall, but maybe this is not possible 
because all short ones are already taken. Of course, 
"-fhardening" would  already a huge  improvement to the 
current situation.

Martin




[C PATCH] c: flag for tag compatibility rules

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


Add a flag to turn tag compatibility rules on or off
independent from the language version.

gcc/c-family:
* c.opt (flag_tag_compat): New flag.

gcc/c:
* c-decl.cc (diagnose_mismatched_decls, start_struct,
finish_struct, start_enum, finish_enum): Support flag.
* c-typeck.cc (composite_type_internal): Support flag.

gcc/doc:
* invoke.texi: Document flag.

gcc/testsuite:
* gcc.dg/asan/pr81470.c: Turn off tag compatibility.
* gcc.dg/c99-tag-1.c: Turn off tag compatibility.
* gcc.dg/c99-tag-2.c: Turn off tag compatibility.
* gcc.dg/decl-3.c: Turn off tag compatibility.
* gcc.dg/enum-redef-1.c: Turn off tag compatibility.
* gcc.dg/pr17188-1.c: Turn off tag compatibility.
* gcc.dg/pr18809-1.c: Turn off tag compatibility.
* gcc.dg/pr39084.c: Turn off tag compatibility.
* gcc.dg/pr79983.c: Turn off tag compatibility.
---
 gcc/c-family/c.opt  |  3 +++
 gcc/c/c-decl.cc | 12 ++--
 gcc/c/c-typeck.cc   |  2 +-
 gcc/doc/invoke.texi |  5 +
 gcc/testsuite/gcc.dg/asan/pr81460.c |  1 +
 gcc/testsuite/gcc.dg/c99-tag-1.c|  2 +-
 gcc/testsuite/gcc.dg/c99-tag-2.c|  2 +-
 gcc/testsuite/gcc.dg/decl-3.c   |  1 +
 gcc/testsuite/gcc.dg/enum-redef-1.c |  2 ++
 gcc/testsuite/gcc.dg/pr17188-1.c|  2 +-
 gcc/testsuite/gcc.dg/pr18809-1.c|  1 +
 gcc/testsuite/gcc.dg/pr39084.c  |  2 +-
 gcc/testsuite/gcc.dg/pr79983.c  |  2 +-
 13 files changed, 25 insertions(+), 12 deletions(-)

diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt
index 2242524cd3e..f95f12ba249 100644
--- a/gcc/c-family/c.opt
+++ b/gcc/c-family/c.opt
@@ -2214,6 +2214,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 2137ba8b845..6d1e0d5c382 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -2094,7 +2094,7 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
  given scope.  */
   if (TREE_CODE (olddecl) == CONST_DECL)
 {
-  if (flag_isoc2x
+  if ((flag_isoc2x || flag_tag_compat)
  && TYPE_NAME (DECL_CONTEXT (newdecl))
  && DECL_CONTEXT (newdecl) != DECL_CONTEXT (olddecl)
  && TYPE_NAME (DECL_CONTEXT (newdecl)) == TYPE_NAME (DECL_CONTEXT 
(olddecl)))
@@ -8723,7 +8723,7 @@ start_struct (location_t loc, enum tree_code code, tree 
name,
 
   /* For C2X, even if we already have a completed definition,
  we do not use it. We will check for consistency later.  */
-  if (flag_isoc2x && ref && TYPE_SIZE (ref))
+  if ((flag_isoc2x || flag_tag_compat) && ref && TYPE_SIZE (ref))
 ref = NULL_TREE;
 
   if (ref && TREE_CODE (ref) == code)
@@ -9515,7 +9515,7 @@ finish_struct (location_t loc, tree t, tree fieldlist, 
tree attributes,
 }
 
   /* Check for consistency with previous definition */
-  if (flag_isoc2x)
+  if (flag_isoc2x || flag_tag_compat)
 {
   tree vistype = previous_tag (t);
   if (vistype
@@ -9534,7 +9534,7 @@ finish_struct (location_t loc, tree t, tree fieldlist, 
tree attributes,
   C_TYPE_BEING_DEFINED (t) = 0;
 
   /* Set type canonical based on equivalence class.  */
-  if (flag_isoc2x)
+  if (flag_isoc2x || flag_tag_compat)
 {
   if (NULL == c_struct_htab)
c_struct_htab = hash_table::create_ggc (61);
@@ -9672,7 +9672,7 @@ start_enum (location_t loc, struct c_enum_contents 
*the_enum, tree name,
   if (name != NULL_TREE)
 enumtype = lookup_tag (ENUMERAL_TYPE, name, true, &enumloc);
 
-  if (flag_isoc2x && enumtype != NULL_TREE
+  if ((flag_isoc2x || flag_tag_compat) && enumtype != NULL_TREE
   && TREE_CODE (enumtype) == ENUMERAL_TYPE
   && TYPE_VALUES (enumtype) != NULL_TREE)
 enumtype = NULL_TREE;
@@ -9941,7 +9941,7 @@ finish_enum (tree enumtype, tree values, tree attributes)
 struct_parse_info->struct_types.safe_push (enumtype);
 
   /* Check for consistency with previous definition */
-  if (flag_isoc2x)
+  if (flag_isoc2x || flag_tag_compat)
 {
   tree vistype = previous_tag (enumtype);
   if (vistype
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 357367eab09..b99f0c3e2fd 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -512,7 +512,7 @@ composite_type_internal (tree t1, tree t2, struct 
composite_cache* cache)
 
 case RECORD_TYPE:
 case UNION_TYPE:
-  if (flag_isoc2x && !comptypes_same_p (t1, t2))
+  if ((flag_isoc2x || flag_tag_compat) && !comptypes_same_p (t1, t2))
{
  gcc_checking_assert (COMPLETE_TYPE_P (t1) && COMPLETE_TYPE_P (t2));
  gcc_checking_assert (comptypes (t1, t2));
diff --git a/gcc/doc/invoke.texi b/gcc/

[C PATCH 6/6] c23: construct composite type for tagged types

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



Support for constructing composite type for structs and unions
in C23.

gcc/c:
* c-typeck.cc (composite_type_internal): Adapted from
composite_type to support structs and unions.
(composite_type): New wrapper function.
(build_conditional_operator): Return composite type.

gcc/testsuite:
* gcc.dg/c2x-tag-composite-1.c: New test.
* gcc.dg/c2x-tag-composite-2.c: New test.
* gcc.dg/c2x-tag-composite-3.c: New test.
* gcc.dg/c2x-tag-composite-4.c: New test.
---
 gcc/c/c-typeck.cc  | 114 +
 gcc/testsuite/gcc.dg/c2x-tag-composite-1.c |  26 +
 gcc/testsuite/gcc.dg/c2x-tag-composite-2.c |  16 +++
 gcc/testsuite/gcc.dg/c2x-tag-composite-3.c |  17 +++
 gcc/testsuite/gcc.dg/c2x-tag-composite-4.c |  21 
 5 files changed, 176 insertions(+), 18 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-composite-1.c
 create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-composite-2.c
 create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-composite-3.c
 create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-composite-4.c

diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 2489fa1e3d1..357367eab09 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -381,8 +381,15 @@ build_functype_attribute_variant (tree ntype, tree otype, 
tree attrs)
nonzero; if that isn't so, this may crash.  In particular, we
assume that qualifiers match.  */
 
+struct composite_cache {
+  tree t1;
+  tree t2;
+  tree composite;
+  struct composite_cache* next;
+};
+
 tree
-composite_type (tree t1, tree t2)
+composite_type_internal (tree t1, tree t2, struct composite_cache* cache)
 {
   enum tree_code code1;
   enum tree_code code2;
@@ -425,7 +432,8 @@ composite_type (tree t1, tree t2)
   {
tree pointed_to_1 = TREE_TYPE (t1);
tree pointed_to_2 = TREE_TYPE (t2);
-   tree target = composite_type (pointed_to_1, pointed_to_2);
+   tree target = composite_type_internal (pointed_to_1,
+  pointed_to_2, cache);
 t1 = build_pointer_type_for_mode (target, TYPE_MODE (t1), false);
t1 = build_type_attribute_variant (t1, attributes);
return qualify_type (t1, t2);
@@ -433,7 +441,8 @@ composite_type (tree t1, tree t2)
 
 case ARRAY_TYPE:
   {
-   tree elt = composite_type (TREE_TYPE (t1), TREE_TYPE (t2));
+   tree elt = composite_type_internal (TREE_TYPE (t1), TREE_TYPE (t2),
+   cache);
int quals;
tree unqual_elt;
tree d1 = TYPE_DOMAIN (t1);
@@ -501,9 +510,61 @@ composite_type (tree t1, tree t2)
return build_type_attribute_variant (t1, attributes);
   }
 
-case ENUMERAL_TYPE:
 case RECORD_TYPE:
 case UNION_TYPE:
+  if (flag_isoc2x && !comptypes_same_p (t1, t2))
+   {
+ gcc_checking_assert (COMPLETE_TYPE_P (t1) && COMPLETE_TYPE_P (t2));
+ gcc_checking_assert (comptypes (t1, t2));
+
+ /* If a composite type for these two types is already under
+construction, return it.  */
+
+ for (struct composite_cache *c = cache; c != NULL; c = c->next)
+   if (c->t1 == t1 && c->t2 == t2)
+  return c->composite;
+
+ /* Otherwise, create a new type node and link it into the cache.  */
+
+ tree n = make_node (code1);
+ struct composite_cache cache2 = { t1, t2, n, cache };
+ cache = &cache2;
+
+ tree f1 = TYPE_FIELDS (t1);
+ tree f2 = TYPE_FIELDS (t2);
+ tree fields = NULL_TREE;
+
+ for (tree a = f1, b = f2; a && b;
+  a = DECL_CHAIN (a), b = DECL_CHAIN (b))
+   {
+ tree ta = TREE_TYPE (a);
+ tree tb = TREE_TYPE (b);
+
+ gcc_assert (DECL_NAME (a) == DECL_NAME (b));
+ gcc_assert (comptypes (ta, tb));
+
+ tree f = build_decl (input_location, FIELD_DECL, DECL_NAME (a),
+  composite_type_internal (ta, tb, cache));
+
+ DECL_FIELD_CONTEXT (f) = n;
+ DECL_CHAIN (f) = fields;
+ fields = f;
+   }
+
+ TYPE_NAME (n) = TYPE_NAME (t1);
+ TYPE_FIELDS (n) = nreverse (fields);
+ TYPE_ATTRIBUTES (n) = attributes;
+ layout_type (n);
+ n = build_type_attribute_variant (n, attributes);
+ n = qualify_type (n, t1);
+
+ gcc_checking_assert (comptypes (n, t1));
+ gcc_checking_assert (comptypes (n, t2));
+
+ return n;
+   }
+  /* FALLTHRU */
+case ENUMERAL_TYPE:
   if (attributes != NULL)
{
  /* Try harder not to create a new aggregate type.  */
@@ -518,7 +579,8 @@ composite_type (tree t1, tree t2)
   /* Function types: prefer the one that specified arg types.
 If both do, merge the arg types.  Also merge the return types.  */
   {
-   tree valtype = composite_type (TREE_TYPE (t1), TREE

[C PATCH 5/6] c23: aliasing of compatible tagged types

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



Tell the backend which types are equivalent by setting
TYPE_CANONICAL to one struct in the set of equivalent
structs. Structs are considered equivalent by ignoring
all sizes of arrays nested in types below field level.

gcc/c:
* c-decl.cc (c_struct_hasher): Hash stable for struct
types.
(c_struct_hasher::hash, c_struct_hasher::equal): New functions.
(finish_struct): Set TYPE_CANONICAL to first struct in
equivalence class.
* c-objc-common.cc (c_get_alias_set): Let structs or
unions with variable size alias anything.
* c-tree.h (comptypes_equiv): New prototype.
* c-typeck.cc (comptypes_equiv): New function.
(comptypes_internal): Implement equivalence mode.
(tagged_types_tu_compatible): Implement equivalence mode.

gcc/testsuite:
* gcc.dg/c2x-tag-2.c: Remove xfail.
* gcc.dg/c2x-tag-6.c: Remove xfail.
* gcc.dg/c2x-tag-alias-1.c: New test.
* gcc.dg/c2x-tag-alias-2.c: New test.
* gcc.dg/c2x-tag-alias-3.c: New test.
* gcc.dg/c2x-tag-alias-4.c: New test.
* gcc.dg/c2x-tag-alias-5.c: New test.
* gcc.dg/c2x-tag-alias-6.c: New test.
* gcc.dg/c2x-tag-alias-7.c: New test.
* gcc.dg/c2x-tag-alias-8.c: New test.
---
 gcc/c/c-decl.cc| 48 +
 gcc/c/c-objc-common.cc |  5 ++
 gcc/c/c-tree.h |  1 +
 gcc/c/c-typeck.cc  | 31 
 gcc/testsuite/gcc.dg/c2x-tag-2.c   |  2 +-
 gcc/testsuite/gcc.dg/c2x-tag-6.c   |  2 +-
 gcc/testsuite/gcc.dg/c2x-tag-alias-1.c | 48 +
 gcc/testsuite/gcc.dg/c2x-tag-alias-2.c | 73 +++
 gcc/testsuite/gcc.dg/c2x-tag-alias-3.c | 48 +
 gcc/testsuite/gcc.dg/c2x-tag-alias-4.c | 73 +++
 gcc/testsuite/gcc.dg/c2x-tag-alias-5.c | 30 
 gcc/testsuite/gcc.dg/c2x-tag-alias-6.c | 77 
 gcc/testsuite/gcc.dg/c2x-tag-alias-7.c | 98 ++
 gcc/testsuite/gcc.dg/c2x-tag-alias-8.c | 90 +++
 14 files changed, 624 insertions(+), 2 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-alias-1.c
 create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-alias-2.c
 create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-alias-3.c
 create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-alias-4.c
 create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-alias-5.c
 create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-alias-6.c
 create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-alias-7.c
 create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-alias-8.c

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index b514e8a35ee..2137ba8b845 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -603,6 +603,36 @@ public:
   auto_vec typedefs_seen;
 };
 
+
+/* Hash table for structs and unions.  */
+struct c_struct_hasher : ggc_ptr_hash
+{
+  static hashval_t hash (tree t);
+  static bool equal (tree, tree);
+};
+
+/* Hash an RECORD OR UNION.  */
+hashval_t
+c_struct_hasher::hash (tree type)
+{
+  inchash::hash hstate;
+
+  hstate.add_int (TREE_CODE (type));
+  hstate.add_object (TYPE_NAME (type));
+
+  return hstate.end ();
+}
+
+/* Compare two RECORD or UNION types.  */
+bool
+c_struct_hasher::equal (tree t1,  tree t2)
+{
+  return comptypes_equiv_p (t1, t2);
+}
+
+/* All tagged typed so that TYPE_CANONICAL can be set correctly.  */
+static GTY (()) hash_table *c_struct_htab;
+
 /* 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;
@@ -9503,6 +9533,24 @@ finish_struct (location_t loc, tree t, tree fieldlist, 
tree attributes,
 
   C_TYPE_BEING_DEFINED (t) = 0;
 
+  /* Set type canonical based on equivalence class.  */
+  if (flag_isoc2x)
+{
+  if (NULL == c_struct_htab)
+   c_struct_htab = hash_table::create_ggc (61);
+
+  hashval_t hash = c_struct_hasher::hash (t);
+
+  tree *e = c_struct_htab->find_slot_with_hash (t, hash, INSERT);
+  if (*e)
+   TYPE_CANONICAL (t) = *e;
+  else
+   {
+ TYPE_CANONICAL (t) = t;
+ *e = t;
+   }
+}
+
   tree incomplete_vars = C_TYPE_INCOMPLETE_VARS (TYPE_MAIN_VARIANT (t));
   for (x = TYPE_MAIN_VARIANT (t); x; x = TYPE_NEXT_VARIANT (x))
 {
diff --git a/gcc/c/c-objc-common.cc b/gcc/c/c-objc-common.cc
index e4aed61ed00..992225bbb29 100644
--- a/gcc/c/c-objc-common.cc
+++ b/gcc/c/c-objc-common.cc
@@ -389,6 +389,11 @@ c_get_alias_set (tree t)
   if (TREE_CODE (t) == ENUMERAL_TYPE)
 return get_alias_set (ENUM_UNDERLYING_TYPE (t));
 
+  /* Structs with variable size can alias different incompatible
+ structs.  Let them alias anything.   */
+  if (RECORD_OR_UNION_TYPE_P (t) && C_TYPE_VARIABLE_SIZE (t))
+return 0;
+
   return c_common_get_alias_set (t);
 }
 
diff --git a/gcc/c/c-tree.h b/gcc/c/c-tree.h
index 511fd9ee0e5..1a8e8f072bd 100644
--- a/gcc/c/c-tree.h
+++ b/gcc/c/c-tree.h

[C PATCH 4/6] c23: tag compatibility rules for enums

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



Allow redefinition of enum types and enumerators.

gcc/c:
* c-decl.cc (start_num): Allow redefinition.
(finish_enum): Diagnose conflicts.
(build_enumerator): Set context.
(diagnose_mismatched_decls): Diagnose conflicting enumerators.
(push_decl): Preserve context for enumerators.

gcc/testsuide/:
* gcc.dg/c2x-tag-enum-1.c: New test.
* gcc.dg/c2x-tag-enum-2.c: New test.
* gcc.dg/c2x-tag-enum-3.c: New test.
* gcc.dg/c2x-tag-enum-4.c: New test.
---
 gcc/c/c-decl.cc   | 47 --
 gcc/c/c-typeck.cc |  5 ++-
 gcc/testsuite/gcc.dg/c2x-tag-enum-1.c | 56 +++
 gcc/testsuite/gcc.dg/c2x-tag-enum-2.c | 23 +++
 gcc/testsuite/gcc.dg/c2x-tag-enum-3.c |  7 
 gcc/testsuite/gcc.dg/c2x-tag-enum-4.c | 22 +++
 6 files changed, 155 insertions(+), 5 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-enum-1.c
 create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-enum-2.c
 create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-enum-3.c
 create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-enum-4.c

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index c5c6a853fa9..b514e8a35ee 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -2064,9 +2064,24 @@ diagnose_mismatched_decls (tree newdecl, tree olddecl,
  given scope.  */
   if (TREE_CODE (olddecl) == CONST_DECL)
 {
-  auto_diagnostic_group d;
-  error ("redeclaration of enumerator %q+D", newdecl);
-  locate_old_decl (olddecl);
+  if (flag_isoc2x
+ && TYPE_NAME (DECL_CONTEXT (newdecl))
+ && DECL_CONTEXT (newdecl) != DECL_CONTEXT (olddecl)
+ && TYPE_NAME (DECL_CONTEXT (newdecl)) == TYPE_NAME (DECL_CONTEXT 
(olddecl)))
+   {
+ if (!simple_cst_equal (DECL_INITIAL (olddecl), DECL_INITIAL 
(newdecl)))
+   {
+ auto_diagnostic_group d;
+ error ("conflicting redeclaration of enumerator %q+D", newdecl);
+ locate_old_decl (olddecl);
+   }
+   }
+  else
+   {
+ auto_diagnostic_group d;
+ error ("redeclaration of enumerator %q+D", newdecl);
+ locate_old_decl (olddecl);
+   }
   return false;
 }
 
@@ -3227,8 +3242,11 @@ pushdecl (tree x)
 
   /* Must set DECL_CONTEXT for everything not at file scope or
  DECL_FILE_SCOPE_P won't work.  Local externs don't count
- unless they have initializers (which generate code).  */
+ unless they have initializers (which generate code).  We
+ also exclude CONST_DECLs because enumerators will get the
+ type of the enum as context.  */
   if (current_function_decl
+  && TREE_CODE (x) != CONST_DECL
   && (!VAR_OR_FUNCTION_DECL_P (x)
  || DECL_INITIAL (x) || !TREE_PUBLIC (x)))
 DECL_CONTEXT (x) = current_function_decl;
@@ -9606,9 +9624,15 @@ start_enum (location_t loc, struct c_enum_contents 
*the_enum, tree name,
   if (name != NULL_TREE)
 enumtype = lookup_tag (ENUMERAL_TYPE, name, true, &enumloc);
 
+  if (flag_isoc2x && enumtype != NULL_TREE
+  && TREE_CODE (enumtype) == ENUMERAL_TYPE
+  && TYPE_VALUES (enumtype) != NULL_TREE)
+enumtype = NULL_TREE;
+
   if (enumtype == NULL_TREE || TREE_CODE (enumtype) != ENUMERAL_TYPE)
 {
   enumtype = make_node (ENUMERAL_TYPE);
+  TYPE_SIZE (enumtype) = NULL_TREE;
   pushtag (loc, name, enumtype);
   if (fixed_underlying_type != NULL_TREE)
{
@@ -9868,6 +9892,20 @@ finish_enum (tree enumtype, tree values, tree attributes)
   && !in_sizeof && !in_typeof && !in_alignof)
 struct_parse_info->struct_types.safe_push (enumtype);
 
+  /* Check for consistency with previous definition */
+  if (flag_isoc2x)
+{
+  tree vistype = previous_tag (enumtype);
+  if (vistype
+ && TREE_CODE (vistype) == TREE_CODE (enumtype)
+ && !C_TYPE_BEING_DEFINED (vistype))
+   {
+ TYPE_STUB_DECL (vistype) = TYPE_STUB_DECL (enumtype);
+ if (!comptypes_same_p (enumtype, vistype))
+   error("conflicting redefinition of enum %qT", enumtype);
+   }
+}
+
   C_TYPE_BEING_DEFINED (enumtype) = 0;
 
   return enumtype;
@@ -10047,6 +10085,7 @@ build_enumerator (location_t decl_loc, location_t loc,
 
   decl = build_decl (decl_loc, CONST_DECL, name, TREE_TYPE (value));
   DECL_INITIAL (decl) = value;
+  DECL_CONTEXT (decl) = the_enum->enum_type;
   pushdecl (decl);
 
   return tree_cons (decl, value, NULL_TREE);
diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index 802c727d9d3..2b79cbba950 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -1396,6 +1396,9 @@ tagged_types_tu_compatible_p (const_tree t1, const_tree 
t2,
 {
 case ENUMERAL_TYPE:
   {
+   if (!comptypes (ENUM_UNDERLYING_TYPE (t1), ENUM_UNDERLYING_TYPE (t2)))
+ return false;
+
/* Speed up the case where the type values are in the same order.  */
tree tv1 = TYPE_VALUES (t1);
  

[C PATCH 3/6] c23: tag compatibility rules for struct and unions

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



Implement redeclaration and compatibility rules for
structures and unions in C23.

gcc/c/:
* c-decl.cc (previous_tag): New function.
(get_parm_info): Turn off warning for C2X.
(start_struct): Allow redefinitons.
(finish_struct): Diagnose conflicts.
* c-tree.h (comptypes_same_p): Add prototype.
* c-typeck.cc (comptypes_same_p): New function
(comptypes_internal): Activate comparison of tagged
types (convert_for_assignment): Ingore qualifiers.
(digest_init): Add error.
(initialized_elementwise_p): Allow compatible types.

gcc/testsuite/:
* gcc.dg/c2x-enum-7.c: Remove warning.
* gcc.dg/c2x-tag-1.c: New test.
* gcc.dg/c2x-tag-2.c: New test.
* gcc.dg/c2x-tag-3.c: New test.
* gcc.dg/c2x-tag-4.c: New test.
* gcc.dg/c2x-tag-5.c: New test.
* gcc.dg/c2x-tag-6.c: New test.
* gcc.dg/c2x-tag-7.c: New test.
* gcc.dg/c2x-tag-8.c: New test.
* gcc.dg/c2x-tag-9.c: New test.
* gcc.dg/c2x-tag-10.c: New test.
---
 gcc/c/c-decl.cc   | 56 ++---
 gcc/c/c-tree.h|  1 +
 gcc/c/c-typeck.cc | 38 +
 gcc/testsuite/gcc.dg/c2x-enum-7.c |  6 +--
 gcc/testsuite/gcc.dg/c2x-tag-1.c  | 68 +++
 gcc/testsuite/gcc.dg/c2x-tag-10.c | 31 ++
 gcc/testsuite/gcc.dg/c2x-tag-2.c  | 43 +++
 gcc/testsuite/gcc.dg/c2x-tag-3.c  | 16 
 gcc/testsuite/gcc.dg/c2x-tag-4.c  | 19 +
 gcc/testsuite/gcc.dg/c2x-tag-5.c  | 26 
 gcc/testsuite/gcc.dg/c2x-tag-6.c  | 34 
 gcc/testsuite/gcc.dg/c2x-tag-7.c  | 28 +
 gcc/testsuite/gcc.dg/c2x-tag-8.c  | 25 
 gcc/testsuite/gcc.dg/c2x-tag-9.c  | 12 ++
 14 files changed, 387 insertions(+), 16 deletions(-)
 create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-1.c
 create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-10.c
 create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-2.c
 create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-3.c
 create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-4.c
 create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-5.c
 create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-6.c
 create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-7.c
 create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-8.c
 create mode 100644 gcc/testsuite/gcc.dg/c2x-tag-9.c

diff --git a/gcc/c/c-decl.cc b/gcc/c/c-decl.cc
index 1f9eb44dbaa..c5c6a853fa9 100644
--- a/gcc/c/c-decl.cc
+++ b/gcc/c/c-decl.cc
@@ -1993,6 +1993,24 @@ locate_old_decl (tree decl)
decl, TREE_TYPE (decl));
 }
 
+static tree
+previous_tag (tree type)
+{
+  struct c_binding *b = NULL;
+  tree name = TYPE_NAME (type);
+
+  if (name)
+b = I_TAG_BINDING (name);
+
+  if (b)
+b = b->shadowed;
+
+  if (b && B_IN_CURRENT_SCOPE (b))
+return b->decl;
+
+  return NULL_TREE;
+}
+
 /* Subroutine of duplicate_decls.  Compare NEWDECL to OLDDECL.
Returns true if the caller should proceed to merge the two, false
if OLDDECL should simply be discarded.  As a side effect, issues
@@ -8442,11 +8460,14 @@ get_parm_info (bool ellipsis, tree expr)
  if (TREE_CODE (decl) != UNION_TYPE || b->id != NULL_TREE)
{
  if (b->id)
-   /* The %s will be one of 'struct', 'union', or 'enum'.  */
-   warning_at (b->locus, 0,
-   "%<%s %E%> declared inside parameter list"
-   " will not be visible outside of this definition or"
-   " declaration", keyword, b->id);
+   {
+ /* The %s will be one of 'struct', 'union', or 'enum'.  */
+ if (!flag_isoc2x)
+   warning_at (b->locus, 0,
+   "%<%s %E%> declared inside parameter list"
+   " will not be visible outside of this 
definition or"
+   " declaration", keyword, b->id);
+   }
  else
/* The %s will be one of 'struct', 'union', or 'enum'.  */
warning_at (b->locus, 0,
@@ -8651,6 +8672,12 @@ start_struct (location_t loc, enum tree_code code, tree 
name,
 
   if (name != NULL_TREE)
 ref = lookup_tag (code, name, true, &refloc);
+
+  /* For C2X, even if we already have a completed definition,
+ we do not use it. We will check for consistency later.  */
+  if (flag_isoc2x && ref && TYPE_SIZE (ref))
+ref = NULL_TREE;
+
   if (ref && TREE_CODE (ref) == code)
 {
   if (TYPE_STUB_DECL (ref))
@@ -9439,6 +9466,25 @@ finish_struct (location_t loc, tree t, tree fieldlist, 
tree attributes,
   warning_at (loc, 0, "union cannot be made transparent");
 }
 
+  /* Check for consistency with previous definition */
+  if (flag_isoc2x)
+{
+  tree vistype = previous_tag (t);
+  if (vistype
+ && TREE_CODE (vistype) == TREE_CODE (t)
+ && !C_TY

[C PATCH 2/6] c23: recursive type checking of tagged type

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




Adapt the old and unused code for type checking for C23.

gcc/c/:
* c-typeck.c (struct comptypes_data): Add anon_field flag.
(comptypes, comptypes_check_unum_int,
comptypes_check_different_types): Remove old cache.
(tagged_tu_types_compatible_p): Rewrite.
---
 gcc/c/c-typeck.cc | 261 +++---
 1 file changed, 58 insertions(+), 203 deletions(-)

diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index ed1520ed6ba..41ef05f005c 100644
--- a/gcc/c/c-typeck.cc
+++ b/gcc/c/c-typeck.cc
@@ -190,20 +190,14 @@ remove_c_maybe_const_expr (tree expr)
 return expr;
 }
 
-/* This is a cache to hold if two types are compatible or not.  */
+/* This is a cache to hold if two types are seen.  */
 
 struct tagged_tu_seen_cache {
   const struct tagged_tu_seen_cache * next;
   const_tree t1;
   const_tree t2;
-  /* The return value of tagged_types_tu_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 
*);
-
 /* Do `exp = require_complete_type (loc, exp);' to make sure exp
does not have an incomplete type.  (That includes void types.)
LOC is the location of the use.  */
@@ -1043,10 +1037,12 @@ common_type (tree t1, tree t2)
 }
 
 struct comptypes_data {
-
   bool enum_and_int_p;
   bool different_types_p;
   bool warning_needed;
+  bool anon_field;
+
+  const struct tagged_tu_seen_cache* cache;
 };
 
 /* Return 1 if TYPE1 and TYPE2 are compatible types for assignment
@@ -1056,13 +1052,9 @@ struct comptypes_data {
 int
 comptypes (tree type1, tree type2)
 {
-  const struct tagged_tu_seen_cache * tagged_tu_seen_base1 = 
tagged_tu_seen_base;
-
   struct comptypes_data data = { };
   bool ret = comptypes_internal (type1, type2, &data);
 
-  free_all_tagged_tu_seen_up_to (tagged_tu_seen_base1);
-
   return ret ? (data.warning_needed ? 2 : 1) : 0;
 }
 
@@ -1072,14 +1064,10 @@ 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;
-
   struct comptypes_data data = { };
   bool ret = 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 ret ? (data.warning_needed ? 2 : 1) : 0;
 }
 
@@ -1090,14 +1078,10 @@ 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;
-
   struct comptypes_data data = { };
   bool ret = comptypes_internal (type1, type2, &data);
   *different_types_p = data.different_types_p;
 
-  free_all_tagged_tu_seen_up_to (tagged_tu_seen_base1);
-
   return ret ? (data.warning_needed ? 2 : 1) : 0;
 }
 
@@ -1334,53 +1318,7 @@ comp_target_types (location_t location, tree ttl, tree 
ttr)
 
 /* Subroutines of `comptypes'.  */
 
-
-
-/* Allocate the seen two types, assuming that they are compatible. */
-
-static struct tagged_tu_seen_cache *
-alloc_tagged_tu_seen_cache (const_tree t1, const_tree t2)
-{
-  struct tagged_tu_seen_cache *tu = XNEW (struct tagged_tu_seen_cache);
-  tu->next = tagged_tu_seen_base;
-  tu->t1 = t1;
-  tu->t2 = t2;
-
-  tagged_tu_seen_base = tu;
-
-  /* The C standard says that two structures in different translation
- units are compatible with each other only if the types of their
- fields are compatible (among other things).  We assume that they
- are compatible until proven otherwise when building the cache.
- An example where this can occur is:
- struct a
- {
-   struct a *next;
- };
- If we are comparing this against a similar struct in another TU,
- and did not assume they were compatible, we end up with an infinite
- loop.  */
-  tu->val = 1;
-  return tu;
-}
-
-/* Free the seen types until we get to TU_TIL. */
-
-static void
-free_all_tagged_tu_seen_up_to (const struct tagged_tu_seen_cache *tu_til)
-{
-  const struct tagged_tu_seen_cache *tu = tagged_tu_seen_base;
-  while (tu != tu_til)
-{
-  const struct tagged_tu_seen_cache *const tu1
-   = (const struct tagged_tu_seen_cache *) tu;
-  tu = tu1->next;
-  XDELETE (CONST_CAST (struct tagged_tu_seen_cache *, tu1));
-}
-  tagged_tu_seen_base = tu_til;
-}
-
-/* Return 1 if two 'struct', 'union', or 'enum' types T1 and T2 are
+/* Return true if two 'struct', 'union', or 'enum' types T1 and T2 are
compatible.  If the two types are not the same (which has been
checked earlier).  */
 
@@ -1406,189 +1344,106 @@ tagged_types_tu_compatible_p (const_tree t1, 
const_tree t2,
 && DECL_ORIGINAL_TYPE (TYPE_NAME (t2)))
 t2 = DECL_ORIGINAL_TYPE (TYPE_NAME (t2));
 
-  /* C90 didn't have the requirement that the two tags be the sa

[C PATCH 1/6] c: reorganize recursive type checking

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




Reorganize recursive type checking to use a structure to
store information collected during the recursion and
returned to the caller (warning_needed, 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,
comptypes_internal): Add structure to interface, change
return type to bool, and adapt calls.
(comptarget_types): Change return type too bool.
(comptypes, comptypes_check_enum_int,
comptypes_check_different_types): Adapt calls.
---
 gcc/c/c-typeck.cc | 266 --
 1 file changed, 114 insertions(+), 152 deletions(-)

diff --git a/gcc/c/c-typeck.cc b/gcc/c/c-typeck.cc
index e6ddf37d412..ed1520ed6ba 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 *);
-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 *);
+struct comptypes_data;
+static bool tagged_types_tu_compatible_p (const_tree, const_tree,
+ struct comptypes_data *);
+static bool comp_target_types (location_t, tree, tree);
+static bool function_types_compatible_p (const_tree, const_tree,
+struct comptypes_data *);
+static bool 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 bool comptypes_internal (const_tree, const_tree,
+   struct comptypes_data *data);
 
 /* Return true if EXP is a null pointer constant, false otherwise.  */
 
@@ -1039,6 +1042,13 @@ common_type (tree t1, tree t2)
   return c_common_type (t1, t2);
 }
 
+struct comptypes_data {
+
+  bool enum_and_int_p;
+  bool different_types_p;
+  bool warning_needed;
+};
+
 /* 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.  */
@@ -1047,12 +1057,13 @@ 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);
+  struct comptypes_data data = { };
+  bool ret = comptypes_internal (type1, type2, &data);
+
   free_all_tagged_tu_seen_up_to (tagged_tu_seen_base1);
 
-  return val;
+  return ret ? (data.warning_needed ? 2 : 1) : 0;
 }
 
 /* Like comptypes, but if it returns non-zero because enum and int are
@@ -1062,12 +1073,14 @@ 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);
+  struct comptypes_data data = { };
+  bool ret = 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;
+  return ret ? (data.warning_needed ? 2 : 1) : 0;
 }
 
 /* Like comptypes, but if it returns nonzero for different types, it
@@ -1078,40 +1091,40 @@ 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;
 
-  val = comptypes_internal (type1, type2, NULL, different_types_p);
+  struct comptypes_data data = { };
+  bool ret = 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;
+  return ret ? (data.warning_needed ? 2 : 1) : 0;
 }
 
-/* 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.  If
-   ENUM_AND_INT_P is not NULL, and one type is an enum and the other a
-   compatible integer type, then this sets *ENUM_AND_INT_P to true;
-   *ENUM_AN

c23 type compatibility rules, v2

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



This is a revised series for the C23 rules for type
compatibility.

1/6 c: reorganize recursive type checking
2/6 c23: recursive type checking of tagged type
3/6 c23: tag compatibility rules for struct and unions
4/6 c23: tag compatibility rules for enums
5/6 c23: aliasing of compatible tagged types
6/6 c23: construct composite type for tagged types
x/x c: flag for tag compatibility rules


1. simplifies type checking without functionality changes
as a preparation step. (This is based on a similar preparatory
patch I posted before for checking size expressions).

2. implements the new rules in comptypes for tagged types but 
the code still remains unused. This removes a lot of old
code because we now require union members to have the same
order and merges the code for structs and unions.

3. implements the rules for structs and unions.

4. does the same for enum types and enumerators. 

5. sets TYPE_CANONICAL based on a equivalence class of types
which makes aliasing work correctly. For this there is a new
comptypes_equiv_p that does relaxed checking (ignoring size
expressions in nested types but not for fields).

6. adds support for the composite type.

There is an extra patch that adds the a flag to activate
the compatibility rules independently from language mode
and activates it by default.

1-2 should cause no change in function. 3-6 implement the
new semantics for C23.

Bootstrapped and regression tested on x86_64 (also with the
extra patch).

Martin







[committed] fix misleading identation breaking bootstrap

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


Committed as obvious.


fix misleading identation breaking bootstrap

Fix identation issue introduced by 966f3c13
"Fix format attribute for printf".

gcc/c-family/ChangeLog:

* c-format.cc: Fix identation.

diff --git a/gcc/c-family/c-format.cc b/gcc/c-family/c-format.cc
index 122ff9bd1cd..b3ef2d44ce9 100644
--- a/gcc/c-family/c-format.cc
+++ b/gcc/c-family/c-format.cc
@@ -1214,8 +1214,8 @@ check_function_format (const_tree fn, tree attrs, int 
nargs,
skipped_default_format = true;
break;
  }
-   if (skipped_default_format)
- continue;
+  if (skipped_default_format)
+continue;
}
 
  if (warn_format)




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 10:58 -0400 schrieb Siddhesh Poyarekar:
> On 2023-08-10 10:47, Martin Uecker wrote:
> > 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?
> 
> There's precedent for this through the __access__ attribute; __bos 
> trusts what the attribute says about the allocation.

The access attribute gives the size directly. The counted_by gives
a length for the array which needs to be translated into a size
via a formula. There are different formulas in use. The question 
is which formula should bdos trust?

Whatever you pick, if this is not consistent with the actual
allocation or use, then it will cause problems either by
breaking code or not detecting buffer overruns.

So it needs to be consistent with what GCC allocates for a
var with FAM and initialization and also the user needs to 
be told what the right choice is so that he can use the right
size for allocation and argument to memcpy / memset etc.

Martin








<    1   2   3   4   >