summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRichard Biener <rguenther@suse.de>2025-01-28 12:28:14 +0100
committerRichard Biener <rguenth@gcc.gnu.org>2025-06-24 13:07:50 +0200
commiteafe890ea3904c109b6bce663a81a91d61356cb4 (patch)
tree8076a4ecc0d5c4a0560faabd91bc63d61bf097f3
parentf4dbdeabb2944d014d506a537a576a6f9a1f4c1f (diff)
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. (cherry picked from commit f1e776ce58ae4a6ae67886adb4ae806598e2c7ef)
-rw-r--r--gcc/testsuite/gcc.dg/tree-ssa/ssa-lim-25.c18
-rw-r--r--gcc/tree-eh.cc9
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 00000000000..3e0f013d1e0
--- /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 85939ca0e89..e3cb99ab67d 100644
--- a/gcc/tree-eh.cc
+++ b/gcc/tree-eh.cc
@@ -2729,11 +2729,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;
}