ranger: Fix up fold_using_range::range_of_address [PR103255]
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. 2021-11-17 Jakub Jelinek <jakub@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.
This commit is contained in:
parent
7061300025
commit
c39cb6bf83
|
@ -720,14 +720,20 @@ fold_using_range::range_of_address (irange &r, gimple *stmt, fur_source &src)
|
|||
}
|
||||
/* 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"
|
||||
|
|
|
@ -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;
|
||||
}
|
Loading…
Reference in New Issue