https://gcc.gnu.org/g:f1e776ce58ae4a6ae67886adb4ae806598e2c7ef

commit r15-7249-gf1e776ce58ae4a6ae67886adb4ae806598e2c7ef
Author: Richard Biener <rguent...@suse.de>
Date:   Tue Jan 28 12:28:14 2025 +0100

    tree-optimization/117424 - invalid LIM of trapping ref
    
    The following addresses a bug in tree_could_trap_p leading to
    hoisting of a possibly trapping, because of out-of-bound, access.
    We only ensured the first accessed byte is within a decl there,
    the patch makes sure the whole base of the reference is within it.
    This is pessimistic if a handled component would then subset to
    a sub-object within the decl but upcasting of a decl to larger
    types should be uncommon, questionable, and wrong without
    -fno-strict-aliasing.
    
    The testcase is a bit fragile, but I could not devise a (portable)
    way to ensure an out-of-bound access to a decl would fault.
    
            PR tree-optimization/117424
            * tree-eh.cc (tree_could_trap_p): Verify the base is
            fully contained within a decl.
    
            * gcc.dg/tree-ssa/ssa-lim-25.c: New testcase.

Diff:
---
 gcc/testsuite/gcc.dg/tree-ssa/ssa-lim-25.c | 18 ++++++++++++++++++
 gcc/tree-eh.cc                             |  9 +++++++--
 2 files changed, 25 insertions(+), 2 deletions(-)

diff --git a/gcc/testsuite/gcc.dg/tree-ssa/ssa-lim-25.c 
b/gcc/testsuite/gcc.dg/tree-ssa/ssa-lim-25.c
new file mode 100644
index 000000000000..3e0f013d1e0d
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/tree-ssa/ssa-lim-25.c
@@ -0,0 +1,18 @@
+/* { dg-do compile } */
+/* { dg-options "-O2 -fdump-tree-lim2-details" } */
+
+char x;
+
+long foo (int n)
+{
+  long y = 0;
+  for (int j = 0; j < 1024; ++j)
+    for (int i = 0; i < n; ++i)
+      y += *(long *)&x;
+  return y;
+}
+
+/* Because *(long *)&x may trap we have to preserve execution and
+   only hoist it from the innermost loop (after the header check).  */
+/* { dg-final { scan-tree-dump-not "out of loop 1" "lim2" } } */
+/* { dg-final { scan-tree-dump "out of loop 2" "lim2" } } */
diff --git a/gcc/tree-eh.cc b/gcc/tree-eh.cc
index 27a4b2b5b166..7015189a2de8 100644
--- a/gcc/tree-eh.cc
+++ b/gcc/tree-eh.cc
@@ -2762,11 +2762,16 @@ tree_could_trap_p (tree expr)
          if (TREE_CODE (base) == STRING_CST)
            return maybe_le (TREE_STRING_LENGTH (base), off);
          tree size = DECL_SIZE_UNIT (base);
+         tree refsz = TYPE_SIZE_UNIT (TREE_TYPE (expr));
          if (size == NULL_TREE
+             || refsz == NULL_TREE
              || !poly_int_tree_p (size)
-             || maybe_le (wi::to_poly_offset (size), off))
+             || !poly_int_tree_p (refsz)
+             || maybe_le (wi::to_poly_offset (size), off)
+             || maybe_gt (off + wi::to_poly_offset (refsz),
+                          wi::to_poly_offset (size)))
            return true;
-         /* Now we are sure the first byte of the access is inside
+         /* Now we are sure the whole base of the access is inside
             the object.  */
          return false;
        }

Reply via email to