https://gcc.gnu.org/g:893e2613ddb928aacfdbae35d96c105ecf18bf82

commit r17-5336-g893e2613ddb928aacfdbae35d96c105ecf18bf82
Author: Siddhesh Poyarekar <[email protected]>
Date:   Thu Oct 15 20:04:43 2026 -0400

    tree-object-size: Fix reexamine propagation [PR 127899]
    
    For OST_DYNAMIC, the reexamine flag is set to mark sites using temporary
    SSA names so that they can be freed up during unknown propagation.  For
    this to work correctly, unknown values should not
    be marked for reexamination.  Fix this in plus_stmt_object_size.
    
    Further, add reexamine propagation in cond_expr too since otherwise one
    could have stale references to temporary SSA names that could
    potentially get freed during unknown propagation.
    
    gcc/ChangeLog:
    
            PR tree-optimization/127899
            * tree-object-size.cc (plus_stmt_object_size): Reset WHOLESIZE
            if BYTES is unknown.
            (dynamic_object_size): Return bool.
            (cond_expr_object_size): Adjust calls and return REEXAMINE.
            (collect_object_sizes_for): Add assert that size is unknown for
            reexamined objects.
    
    gcc/testsuite/ChangeLog:
    
            PR tree-optimization/127899
            * gcc.dg/builtin-dynamic-object-size-pr127899-1.c: New test.
            * gcc.dg/builtin-dynamic-object-size-pr127899-2.c: Likewise.
            * gcc.dg/builtin-dynamic-object-size-pr127899-3.c: Likewise.
    
    Signed-off-by: Siddhesh Poyarekar <[email protected]>

Diff:
---
 .../builtin-dynamic-object-size-pr127899-1.c       | 36 ++++++++++++++++++++++
 .../builtin-dynamic-object-size-pr127899-2.c       | 30 ++++++++++++++++++
 .../builtin-dynamic-object-size-pr127899-3.c       | 15 +++++++++
 gcc/tree-object-size.cc                            | 32 ++++++++++++++++---
 4 files changed, 108 insertions(+), 5 deletions(-)

diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-pr127899-1.c 
b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-pr127899-1.c
new file mode 100644
index 000000000000..4d809542a5e1
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-pr127899-1.c
@@ -0,0 +1,36 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+typedef __SIZE_TYPE__ size_t;
+
+#define container_of(ptr, type, member) \
+  ((type *) ((char *) (ptr) - __builtin_offsetof (type, member)))
+
+struct S
+{
+  int count;
+  char data[] __attribute__ ((counted_by (count)));
+};
+
+__attribute__ ((noinline)) size_t
+min_size (struct S *s)
+{
+  /* Back from the flexible array member to the structure holding it.  */
+  void *data = s->data;
+  struct S *again = container_of (data, struct S, data);
+
+  return __builtin_dynamic_object_size (again, 2);
+}
+
+int
+main (void)
+{
+  struct S *s = __builtin_malloc (sizeof (*s) + 10);
+
+  if (!s)
+    return 1;
+  s->count = 10;
+  __builtin_printf ("%zu\n", min_size (s));
+  __builtin_free (s);
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-pr127899-2.c 
b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-pr127899-2.c
new file mode 100644
index 000000000000..7f05e1ee826c
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-pr127899-2.c
@@ -0,0 +1,30 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+typedef __SIZE_TYPE__ size_t;
+static char pool[64];
+static size_t used;
+
+/* Hand out consecutive pieces of POOL.  */
+__attribute__ ((alloc_size (1), noinline)) char *
+pool_alloc (size_t n)
+{
+  char *p = pool + used;
+
+  used += n;
+  return p;
+}
+
+int
+main (int argc, char **argv)
+{
+  (void) argv;
+  size_t n = argc + 7;
+  char *a = pool_alloc (8);
+  char *b = pool_alloc (n);
+  /* A again: B - 8 is &pool[0].  */
+  char *before = b - 8;
+
+  __builtin_printf ("%d %zu\n", before == a, __builtin_dynamic_object_size 
(before, 2));
+  return 0;
+}
diff --git a/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-pr127899-3.c 
b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-pr127899-3.c
new file mode 100644
index 000000000000..397b3df3f8db
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/builtin-dynamic-object-size-pr127899-3.c
@@ -0,0 +1,15 @@
+/* { dg-do compile } */
+/* { dg-options "-O2" } */
+
+__SIZE_TYPE__ h (int n)
+{
+  char *q = __builtin_malloc (n);
+  return __builtin_dynamic_object_size (q - 8, 2);
+}
+
+extern char a[10], b[20];
+__SIZE_TYPE__ k (int c)
+{
+  char *q = c ? a : b;
+  return __builtin_dynamic_object_size (q - 8, 2);
+}
diff --git a/gcc/tree-object-size.cc b/gcc/tree-object-size.cc
index 488ecfcccb0b..196aa93d44fc 100644
--- a/gcc/tree-object-size.cc
+++ b/gcc/tree-object-size.cc
@@ -1635,6 +1635,15 @@ plus_stmt_object_size (struct object_size_info *osi, 
tree var, gimple *stmt)
        bytes = size_unknown (object_size_type);
       else
        bytes = wholesize;
+
+      /* If the size ends up being unknown (either intentionally or because
+        SIZE_FOR_OFFSET returned a zero size, which happens to be the unknown
+        value for OST_MINIMUM), reset wholesize too.  */
+      if (size_unknown_p (bytes, object_size_type))
+       {
+         wholesize = size_unknown (object_size_type);
+         reexamine = false;
+       }
     }
   else
     bytes = wholesize = size_unknown (object_size_type);
@@ -1651,11 +1660,12 @@ plus_stmt_object_size (struct object_size_info *osi, 
tree var, gimple *stmt)
 /* Compute the dynamic object size for VAR.  Return the result in SIZE and
    WHOLESIZE.  */
 
-static void
+static bool
 dynamic_object_size (struct object_size_info *osi, tree var,
                     tree *size, tree *wholesize)
 {
   int object_size_type = osi->object_size_type;
+  bool reexamine = false;
 
   if (TREE_CODE (var) == SSA_NAME)
     {
@@ -1664,11 +1674,14 @@ dynamic_object_size (struct object_size_info *osi, tree 
var,
       collect_object_sizes_for (osi, var);
       *size = object_sizes_get (osi, varno);
       *wholesize = object_sizes_get (osi, varno, true);
+      reexamine = bitmap_bit_p (osi->reexamine, varno);
     }
   else if (TREE_CODE (var) == ADDR_EXPR)
     addr_object_size (osi, var, object_size_type, size, wholesize);
   else
     *size = *wholesize = size_unknown (object_size_type);
+
+  return reexamine;
 }
 
 /* Compute object_sizes for VAR, defined at STMT, which is
@@ -1695,9 +1708,11 @@ cond_expr_object_size (struct object_size_info *osi, 
tree var, gimple *stmt)
     {
       tree then_size, then_wholesize, else_size, else_wholesize;
 
-      dynamic_object_size (osi, then_, &then_size, &then_wholesize);
+      reexamine |= dynamic_object_size (osi, then_, &then_size,
+                                       &then_wholesize);
       if (!size_unknown_p (then_size, object_size_type))
-       dynamic_object_size (osi, else_, &else_size, &else_wholesize);
+       reexamine |= dynamic_object_size (osi, else_, &else_size,
+                                         &else_wholesize);
 
       tree cond_size, cond_wholesize;
       if (size_unknown_p (then_size, object_size_type)
@@ -1715,7 +1730,7 @@ cond_expr_object_size (struct object_size_info *osi, tree 
var, gimple *stmt)
 
       object_sizes_set (osi, varno, cond_size, cond_wholesize);
 
-      return false;
+      return reexamine;
     }
 
   if (TREE_CODE (then_) == SSA_NAME)
@@ -2012,8 +2027,15 @@ collect_object_sizes_for (struct object_size_info *osi, 
tree var)
       bitmap_set_bit (computed[object_size_type], varno);
       if (!(object_size_type & OST_DYNAMIC))
        bitmap_clear_bit (osi->reexamine, varno);
+      /* The REEXAMINE flag for dynamic size expressions needs to propagate so
+        that there are no stale references to SSA names released during
+        unknown size propagation in gimplify_size_expressions.  */
       else if (reexamine)
-       bitmap_set_bit (osi->reexamine, varno);
+       {
+         gcc_checking_assert (!object_sizes_unknown_p (object_size_type,
+                                                       varno));
+         bitmap_set_bit (osi->reexamine, varno);
+       }
     }
   else
     {

Reply via email to