On Wed, Nov 17, 2021 at 10:32 AM Jakub Jelinek <ja...@redhat.com> wrote: > > Hi! > > If on &base->member the offset isn't constant or isn't zero and > -fdelete-null-pointer-checks and not -fwrapv-pointer and base has a range > that doesn't include NULL, we return the range of the base. > Usually it isn't a big deal, because for most pointers we just use > varying, range_zero and range_nonzero ranges and nothing beyond that, > but if a pointer is initialized from a constant, we actually track the > exact range and in that case this causes miscompilation. > As discussed on IRC, I think doing something like: > offset_int off2; > if (off_cst && off.is_constant (&off2)) > { > tree cst = wide_int_to_tree (sizetype, off2 / > BITS_PER_UNIT); > // adjust range r with POINTER_PLUS_EXPR cst > if (!range_includes_zero_p (&r)) > return true; > } > // Fallback > r = range_nonzero (TREE_TYPE (gimple_assign_rhs1 (stmt))); > return true; > could work, given that most of the pointer ranges are just the simple ones > perhaps it is too much for little benefit. > > Bootstrapped/regtested on x86_64-linux and i686-linux, ok for trunk?
OK. Thanks for the formatting fixes btw. Unrelated, but we could remove the return value for range_of_address since it always returns true. I suppose it's consistent with range_of_*, but unlike range_of_address, the other ones can receive statements they can't process. Aldy > > 2021-11-17 Jakub Jelinek <ja...@redhat.com> > > PR tree-optimization/103255 > * gimple-range-fold.cc (fold_using_range::range_of_address): Return > range_nonzero rather than unadjusted base's range. Formatting fixes. > > * gcc.c-torture/execute/pr103255.c: New test. > > --- gcc/gimple-range-fold.cc.jj 2021-11-04 12:27:02.341298923 +0100 > +++ gcc/gimple-range-fold.cc 2021-11-16 22:10:44.453974329 +0100 > @@ -720,14 +720,20 @@ fold_using_range::range_of_address (iran > } > /* If &X->a is equal to X, the range of X is the result. */ > if (off_cst && known_eq (off, 0)) > - return true; > + return true; > else if (flag_delete_null_pointer_checks > && !TYPE_OVERFLOW_WRAPS (TREE_TYPE (expr))) > { > - /* For -fdelete-null-pointer-checks -fno-wrapv-pointer we don't > - allow going from non-NULL pointer to NULL. */ > - if(!range_includes_zero_p (&r)) > - return true; > + /* For -fdelete-null-pointer-checks -fno-wrapv-pointer we don't > + allow going from non-NULL pointer to NULL. */ > + if (!range_includes_zero_p (&r)) > + { > + /* We could here instead adjust r by off >> LOG2_BITS_PER_UNIT > + using POINTER_PLUS_EXPR if off_cst and just fall back to > + this. */ > + r = range_nonzero (TREE_TYPE (gimple_assign_rhs1 (stmt))); > + return true; > + } > } > /* If MEM_REF has a "positive" offset, consider it non-NULL > always, for -fdelete-null-pointer-checks also "negative" > --- gcc/testsuite/gcc.c-torture/execute/pr103255.c.jj 2021-11-16 > 22:14:10.660118225 +0100 > +++ gcc/testsuite/gcc.c-torture/execute/pr103255.c 2021-11-16 > 22:13:56.506314265 +0100 > @@ -0,0 +1,41 @@ > +/* PR tree-optimization/103255 */ > + > +struct H > +{ > + unsigned a; > + unsigned b; > + unsigned c; > +}; > + > +#if __SIZEOF_POINTER__ >= 4 > +#define ADDR 0x400000 > +#else > +#define ADDR 0x4000 > +#endif > +#define OFF 0x20 > + > +int > +main () > +{ > + struct H *h = 0; > + unsigned long o; > + volatile int t = 1; > + > + for (o = OFF; o <= OFF; o += 0x1000) > + { > + struct H *u; > + u = (struct H *) (ADDR + o); > + if (t) > + { > + h = u; > + break; > + } > + } > + > + if (h == 0) > + return 0; > + unsigned *tt = &h->b; > + if ((__SIZE_TYPE__) tt != (ADDR + OFF + __builtin_offsetof (struct H, b))) > + __builtin_abort (); > + return 0; > +} > > Jakub >