]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
[ifcombine] out-of-bounds bitfield refs can trap [PR118514]
authorAlexandre Oliva <oliva@adacore.com>
Fri, 24 Jan 2025 02:23:10 +0000 (23:23 -0300)
committerAlexandre Oliva <oliva@gnu.org>
Fri, 24 Jan 2025 02:23:10 +0000 (23:23 -0300)
Check that BIT_FIELD_REFs of DECLs are in range before deciding they
don't trap.

Check that a replacement bitfield load is as trapping as the replaced
load.

for  gcc/ChangeLog

PR tree-optimization/118514
* tree-eh.cc (bit_field_ref_in_bounds_p): New.
(tree_could_trap_p) <BIT_FIELD_REF>: Call it.
* gimple-fold.cc (make_bit_field_load): Check trapping status
of replacement load against original load.

for  gcc/testsuite/ChangeLog

PR tree-optimization/118514
* gcc.dg/field-merge-23.c: New.

gcc/gimple-fold.cc
gcc/testsuite/gcc.dg/field-merge-23.c [new file with mode: 0644]
gcc/tree-eh.cc

index 3c971a29ef045f37eb3a14e5605ab1378fc454bb..01c4d076af26c16adbf928d15c7c624471dd855a 100644 (file)
@@ -7859,6 +7859,11 @@ make_bit_field_load (location_t loc, tree inner, tree orig_inner, tree type,
       gimple *new_stmt = gsi_stmt (i);
       if (gimple_has_mem_ops (new_stmt))
        gimple_set_vuse (new_stmt, reaching_vuse);
+      gcc_checking_assert (! (gimple_assign_load_p (point)
+                             && gimple_assign_load_p (new_stmt))
+                          || (tree_could_trap_p (gimple_assign_rhs1 (point))
+                              == tree_could_trap_p (gimple_assign_rhs1
+                                                    (new_stmt))));
     }
 
   gimple_stmt_iterator gsi = gsi_for_stmt (point);
diff --git a/gcc/testsuite/gcc.dg/field-merge-23.c b/gcc/testsuite/gcc.dg/field-merge-23.c
new file mode 100644 (file)
index 0000000..d60f762
--- /dev/null
@@ -0,0 +1,19 @@
+/* { dg-do run } */
+/* { dg-options "-O" } */
+
+/* PR tree-optimization/118514 */
+
+/* Check that we don't pull optimized references that could trap out of
+   loops.  */
+
+int a, c = 1;
+unsigned char b[1], d;
+int main() {
+  while (a || !c) {
+    signed char e = b[1000000000];
+    d = e < 0 || b[1000000000] > 1;
+    if (d)
+      __builtin_abort ();
+  }
+  return 0;
+}
index 1033b124e4df369843f135d478ad42d7f4363821..27a4b2b5b1665bc93ce2ae9365f3c20b451c5c89 100644 (file)
@@ -2646,6 +2646,29 @@ range_in_array_bounds_p (tree ref)
   return true;
 }
 
+/* Return true iff EXPR, a BIT_FIELD_REF, accesses a bit range that is known to
+   be in bounds for the referred operand type.  */
+
+static bool
+bit_field_ref_in_bounds_p (tree expr)
+{
+  tree size_tree;
+  poly_uint64 size_max, min, wid, max;
+
+  size_tree = TYPE_SIZE (TREE_TYPE (TREE_OPERAND (expr, 0)));
+  if (!size_tree || !poly_int_tree_p (size_tree, &size_max))
+    return false;
+
+  min = bit_field_offset (expr);
+  wid = bit_field_size (expr);
+  max = min + wid;
+  if (maybe_lt (max, min)
+      || maybe_lt (size_max, max))
+    return false;
+
+  return true;
+}
+
 /* Return true if EXPR can trap, as in dereferencing an invalid pointer
    location or floating point arithmetic.  C.f. the rtl version, may_trap_p.
    This routine expects only GIMPLE lhs or rhs input.  */
@@ -2688,10 +2711,14 @@ tree_could_trap_p (tree expr)
  restart:
   switch (code)
     {
+    case BIT_FIELD_REF:
+      if (DECL_P (TREE_OPERAND (expr, 0)) && !bit_field_ref_in_bounds_p (expr))
+       return true;
+      /* Fall through.  */
+
     case COMPONENT_REF:
     case REALPART_EXPR:
     case IMAGPART_EXPR:
-    case BIT_FIELD_REF:
     case VIEW_CONVERT_EXPR:
     case WITH_SIZE_EXPR:
       expr = TREE_OPERAND (expr, 0);