diff options
| author | Richard Biener <rguenther@suse.de> | 2025-01-28 12:28:14 +0100 |
|---|---|---|
| committer | Richard Biener <rguenth@gcc.gnu.org> | 2025-06-24 13:07:50 +0200 |
| commit | eafe890ea3904c109b6bce663a81a91d61356cb4 (patch) | |
| tree | 8076a4ecc0d5c4a0560faabd91bc63d61bf097f3 | |
| parent | f4dbdeabb2944d014d506a537a576a6f9a1f4c1f (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.c | 18 | ||||
| -rw-r--r-- | 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 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; } |
