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 {
