aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew MacLeod <amacleod@redhat.com>2024-05-08 10:22:23 -0400
committerAndrew MacLeod <amacleod@redhat.com>2024-05-09 10:28:23 -0400
commit421311a31a12b96143eb901fde0e020771fe71d4 (patch)
treee706ee50e2e5dd851f5ab42dd6ef8b1edcffd6e8
parentfefdb9f6b4784fa71bd14ae579fc52b2107f8495 (diff)
downloadgcc-421311a31a12b96143eb901fde0e020771fe71d4.zip
gcc-421311a31a12b96143eb901fde0e020771fe71d4.tar.gz
gcc-421311a31a12b96143eb901fde0e020771fe71d4.tar.bz2
Fix range-ops operator_addr.
Lack of symbolic information prevents op1_range from being able to draw the same conclusions as fold_range can. PR tree-optimization/111009 gcc/ * range-op.cc (operator_addr_expr::op1_range): Be more restrictive. * value-range.h (contains_zero_p): New. gcc/testsuite/ * gcc.dg/pr111009.c: New.
-rw-r--r--gcc/range-op.cc12
-rw-r--r--gcc/testsuite/gcc.dg/pr111009.c38
-rw-r--r--gcc/value-range.h10
3 files changed, 59 insertions, 1 deletions
diff --git a/gcc/range-op.cc b/gcc/range-op.cc
index f90e78d..97a88dc 100644
--- a/gcc/range-op.cc
+++ b/gcc/range-op.cc
@@ -4357,7 +4357,17 @@ operator_addr_expr::op1_range (irange &r, tree type,
const irange &op2,
relation_trio) const
{
- return operator_addr_expr::fold_range (r, type, lhs, op2);
+ if (empty_range_varying (r, type, lhs, op2))
+ return true;
+
+ // Return a non-null pointer of the LHS type (passed in op2), but only
+ // if we cant overflow, eitherwise a no-zero offset could wrap to zero.
+ // See PR 111009.
+ if (!contains_zero_p (lhs) && TYPE_OVERFLOW_UNDEFINED (type))
+ r = range_nonzero (type);
+ else
+ r.set_varying (type);
+ return true;
}
diff --git a/gcc/testsuite/gcc.dg/pr111009.c b/gcc/testsuite/gcc.dg/pr111009.c
new file mode 100644
index 0000000..3accd9a
--- /dev/null
+++ b/gcc/testsuite/gcc.dg/pr111009.c
@@ -0,0 +1,38 @@
+/* PR tree-optimization/111009 */
+/* { dg-do run } */
+/* { dg-options "-O3 -fno-strict-overflow" } */
+
+struct dso {
+ struct dso * next;
+ int maj;
+};
+
+__attribute__((noipa)) static void __dso_id__cmp_(void) {}
+
+__attribute__((noipa))
+static int bug(struct dso * d, struct dso *dso)
+{
+ struct dso **p = &d;
+ struct dso *curr = 0;
+
+ while (*p) {
+ curr = *p;
+ // prevent null deref below
+ if (!dso) return 1;
+ if (dso == curr) return 1;
+
+ int *a = &dso->maj;
+ // null deref
+ if (!(a && *a)) __dso_id__cmp_();
+
+ p = &curr->next;
+ }
+ return 0;
+}
+
+__attribute__((noipa))
+int main(void) {
+ struct dso d = { 0, 0, };
+ bug(&d, 0);
+}
+
diff --git a/gcc/value-range.h b/gcc/value-range.h
index 96e59ec..0284d6c 100644
--- a/gcc/value-range.h
+++ b/gcc/value-range.h
@@ -1111,6 +1111,16 @@ irange::normalize_kind ()
}
}
+inline bool
+contains_zero_p (const irange &r)
+{
+ if (r.undefined_p ())
+ return false;
+
+ tree zero = build_zero_cst (r.type ());
+ return r.contains_p (zero);
+}
+
// Return the maximum value for TYPE.
inline tree