https://gcc.gnu.org/g:c5c3a4a265256535a66f1656d44e143f05d77f66
commit r12-10439-gc5c3a4a265256535a66f1656d44e143f05d77f66 Author: Andrew MacLeod <amacl...@redhat.com> Date: Fri May 10 13:56:01 2024 -0400 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. Diff: --- gcc/range-op.cc | 12 +++++++++++- gcc/testsuite/gcc.dg/pr111009.c | 38 ++++++++++++++++++++++++++++++++++++++ gcc/value-range.h | 10 ++++++++++ 3 files changed, 59 insertions(+), 1 deletion(-) diff --git a/gcc/range-op.cc b/gcc/range-op.cc index bf95f5fbaa1c..2e0d67b70b65 100644 --- a/gcc/range-op.cc +++ b/gcc/range-op.cc @@ -3825,7 +3825,17 @@ operator_addr_expr::op1_range (irange &r, tree type, const irange &op2, relation_kind rel ATTRIBUTE_UNUSED) 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 000000000000..3accd9ac0630 --- /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 d4cba22d540f..22f5fc68d7cb 100644 --- a/gcc/value-range.h +++ b/gcc/value-range.h @@ -605,6 +605,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