Patchwork [PR45098] Disallow NULL pointer in pointer arithmetic

login
register
mail settings
Submitter Tom de Vries
Date June 17, 2011, 10:40 a.m.
Message ID <4DFB2F3A.3040706@codesourcery.com>
Download mbox | patch
Permalink /patch/100792/
State New
Headers show

Comments

Tom de Vries - June 17, 2011, 10:40 a.m.
On 06/17/2011 12:01 AM, Jeff Law wrote:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
> 
> On 06/16/11 00:39, Tom de Vries wrote:
>> Hi,
>>
>> Consider the following example.
>>
>> extern unsigned int foo (int*) __attribute__((pure));
>> unsigned int
>> tr (int array[], int n)
>> {
>>   unsigned int i;
>>   unsigned int sum = 0;
>>   for (i = 0; i < n; i++)
>>     sum += foo (&array[i]);
>>   return sum;
>> }
>>
>> For 32-bit pointers, the analysis in infer_loop_bounds_from_pointer_arith
>> currently concludes that the range of valid &array[i] is &array[0x0] to
>> &array[0x3fffffff], meaning 0x40000000 distinct values.
>> This implies that i < n is executed at most 0x40000001 times, and i < n
>> cannot be eliminated by an 32-bit iterator with step 4, since that one has
>> only 0x40000000 distinct values.
>>
>> The patch reasons that NULL cannot be used or produced by pointer
>> arithmetic, and that we can exclude the possibility of the NULL pointer in the
>> range. So the range of valid &array[i] is &array[0] to &array[0x3ffffffe],
>> meaning 0x3fffffff distinct values.
>> This implies that i < n is executed at most 0x40000000 times and i < n can be
>> eliminated.
>>
>> The patch implements this new limitation by changing the (low, high, step)
>> triplet in infer_loop_bounds_from_pointer_arith from (0x0, 0xffffffff, 0x4)
>> to (0x4, 0xffffffff, 0x4).
>>
>> I'm not too happy about the test for C-like language: ptrdiff_type_node !=
>> NULL_TREE, but I'm not sure how else to test for this.
>>
>> Bootstrapped and reg-tested on x86_64.
>>
>> I will sent the adapted test cases in a separate email.

> Interesting.  I'd never thought about the generation/use angle to prove
> a pointer was non-null.  ISTM we could use that same logic to infer that
> more pointers are non-null in extract_range_from_binary_expr.
> 
> Interested in tackling that improvement, obviously as an independent patch?
> 

I'm not familiar with vrp code, but.. something like this?


Thanks,
- Tom
Richard Guenther - June 17, 2011, 10:44 a.m.
On Fri, Jun 17, 2011 at 12:40 PM, Tom de Vries <vries@codesourcery.com> wrote:
> On 06/17/2011 12:01 AM, Jeff Law wrote:
>> -----BEGIN PGP SIGNED MESSAGE-----
>> Hash: SHA1
>>
>> On 06/16/11 00:39, Tom de Vries wrote:
>>> Hi,
>>>
>>> Consider the following example.
>>>
>>> extern unsigned int foo (int*) __attribute__((pure));
>>> unsigned int
>>> tr (int array[], int n)
>>> {
>>>   unsigned int i;
>>>   unsigned int sum = 0;
>>>   for (i = 0; i < n; i++)
>>>     sum += foo (&array[i]);
>>>   return sum;
>>> }
>>>
>>> For 32-bit pointers, the analysis in infer_loop_bounds_from_pointer_arith
>>> currently concludes that the range of valid &array[i] is &array[0x0] to
>>> &array[0x3fffffff], meaning 0x40000000 distinct values.
>>> This implies that i < n is executed at most 0x40000001 times, and i < n
>>> cannot be eliminated by an 32-bit iterator with step 4, since that one has
>>> only 0x40000000 distinct values.
>>>
>>> The patch reasons that NULL cannot be used or produced by pointer
>>> arithmetic, and that we can exclude the possibility of the NULL pointer in the
>>> range. So the range of valid &array[i] is &array[0] to &array[0x3ffffffe],
>>> meaning 0x3fffffff distinct values.
>>> This implies that i < n is executed at most 0x40000000 times and i < n can be
>>> eliminated.
>>>
>>> The patch implements this new limitation by changing the (low, high, step)
>>> triplet in infer_loop_bounds_from_pointer_arith from (0x0, 0xffffffff, 0x4)
>>> to (0x4, 0xffffffff, 0x4).
>>>
>>> I'm not too happy about the test for C-like language: ptrdiff_type_node !=
>>> NULL_TREE, but I'm not sure how else to test for this.
>>>
>>> Bootstrapped and reg-tested on x86_64.
>>>
>>> I will sent the adapted test cases in a separate email.
>
>> Interesting.  I'd never thought about the generation/use angle to prove
>> a pointer was non-null.  ISTM we could use that same logic to infer that
>> more pointers are non-null in extract_range_from_binary_expr.
>>
>> Interested in tackling that improvement, obviously as an independent patch?
>>
>
> I'm not familiar with vrp code, but.. something like this?
>
> Index: tree-vrp.c
> ===================================================================
> --- tree-vrp.c  (revision 173703)
> +++ tree-vrp.c  (working copy)
> @@ -2273,7 +2273,12 @@ extract_range_from_binary_expr (value_ra
>        {
>          /* For pointer types, we are really only interested in asserting
>             whether the expression evaluates to non-NULL.  */
> -         if (range_is_nonnull (&vr0) || range_is_nonnull (&vr1))
> +         if (flag_delete_null_pointer_checks && nowrap_type_p (expr_type))

the latter would always return true

Btw, I guess you'll "miscompile" a load of code that is strictly
undefined.  So I'm not sure we want to do this against our users ...

Oh, and of course it's even wrong.  I thing it needs &&
!range_includes_zero (&vr1) (which we probably don't have).  The
offset may be 0 and NULL + 0
is still NULL.

Richard.

> +           {
> +             set_value_range_to_nonnull (vr, expr_type);
> +             set_value_range_to_nonnull (&vr0, expr_type);
> +           }
> +         else if (range_is_nonnull (&vr0) || range_is_nonnull (&vr1))
>            set_value_range_to_nonnull (vr, expr_type);
>          else if (range_is_null (&vr0) && range_is_null (&vr1))
>            set_value_range_to_null (vr, expr_type);
>
> Thanks,
> - Tom
>
Zdenek Dvorak - June 17, 2011, 10:55 a.m.
> >> Interesting.  I'd never thought about the generation/use angle to prove
> >> a pointer was non-null.  ISTM we could use that same logic to infer that
> >> more pointers are non-null in extract_range_from_binary_expr.
> >>
> >> Interested in tackling that improvement, obviously as an independent patch?
> >>
> >
> > I'm not familiar with vrp code, but.. something like this?
> >
> > Index: tree-vrp.c
> > ===================================================================
> > --- tree-vrp.c  (revision 173703)
> > +++ tree-vrp.c  (working copy)
> > @@ -2273,7 +2273,12 @@ extract_range_from_binary_expr (value_ra
> >        {
> >          /* For pointer types, we are really only interested in asserting
> >             whether the expression evaluates to non-NULL.  */
> > -         if (range_is_nonnull (&vr0) || range_is_nonnull (&vr1))
> > +         if (flag_delete_null_pointer_checks && nowrap_type_p (expr_type))
> 
> the latter would always return true
> 
> Btw, I guess you'll "miscompile" a load of code that is strictly
> undefined.  So I'm not sure we want to do this against our users ...

Probably not, at least unless the user explicitly asks for it -- for example,
we could have -fdelete-null-pointer-checks=2.  In fact, it might be a good idea
to implement this flag anyway, since some current uses of flag_delete_null_pointer_checks
can lead to "miscompilations" when user makes an error in their code and would
probably appreciate more having their program crash.

> Oh, and of course it's even wrong.  I thing it needs &&
> !range_includes_zero (&vr1) (which we probably don't have).  The
> offset may be 0 and NULL + 0
> is still NULL.

actually, the result of NULL + 0 is undefined (pointer arithmetics is only defined
for pointers to actual objects, and NULL cannot point to one).

Zdenek
Richard Guenther - June 17, 2011, 10:57 a.m.
2011/6/17 Zdenek Dvorak <rakdver@kam.mff.cuni.cz>:
>> >> Interesting.  I'd never thought about the generation/use angle to prove
>> >> a pointer was non-null.  ISTM we could use that same logic to infer that
>> >> more pointers are non-null in extract_range_from_binary_expr.
>> >>
>> >> Interested in tackling that improvement, obviously as an independent patch?
>> >>
>> >
>> > I'm not familiar with vrp code, but.. something like this?
>> >
>> > Index: tree-vrp.c
>> > ===================================================================
>> > --- tree-vrp.c  (revision 173703)
>> > +++ tree-vrp.c  (working copy)
>> > @@ -2273,7 +2273,12 @@ extract_range_from_binary_expr (value_ra
>> >        {
>> >          /* For pointer types, we are really only interested in asserting
>> >             whether the expression evaluates to non-NULL.  */
>> > -         if (range_is_nonnull (&vr0) || range_is_nonnull (&vr1))
>> > +         if (flag_delete_null_pointer_checks && nowrap_type_p (expr_type))
>>
>> the latter would always return true
>>
>> Btw, I guess you'll "miscompile" a load of code that is strictly
>> undefined.  So I'm not sure we want to do this against our users ...
>
> Probably not, at least unless the user explicitly asks for it -- for example,
> we could have -fdelete-null-pointer-checks=2.  In fact, it might be a good idea
> to implement this flag anyway, since some current uses of flag_delete_null_pointer_checks
> can lead to "miscompilations" when user makes an error in their code and would
> probably appreciate more having their program crash.
>
>> Oh, and of course it's even wrong.  I thing it needs &&
>> !range_includes_zero (&vr1) (which we probably don't have).  The
>> offset may be 0 and NULL + 0
>> is still NULL.
>
> actually, the result of NULL + 0 is undefined (pointer arithmetics is only defined
> for pointers to actual objects, and NULL cannot point to one).

It's maybe undefined in C, but is it undefined in the middle-end?  Thus,
are you sure we never generate it from (void *)((uintptr_t)p + obfuscated_0)?
I'm sure we simply fold that to p + obfuscated_0.

Richard.

> Zdenek
>
Zdenek Dvorak - June 17, 2011, 11:13 a.m.
Hi,

> >> > Index: tree-vrp.c
> >> > ===================================================================
> >> > --- tree-vrp.c  (revision 173703)
> >> > +++ tree-vrp.c  (working copy)
> >> > @@ -2273,7 +2273,12 @@ extract_range_from_binary_expr (value_ra
> >> >        {
> >> >          /* For pointer types, we are really only interested in asserting
> >> >             whether the expression evaluates to non-NULL.  */
> >> > -         if (range_is_nonnull (&vr0) || range_is_nonnull (&vr1))
> >> > +         if (flag_delete_null_pointer_checks && nowrap_type_p (expr_type))
> >>
> >> the latter would always return true
> >>
> >> Btw, I guess you'll "miscompile" a load of code that is strictly
> >> undefined.  So I'm not sure we want to do this against our users ...
> >
> > Probably not, at least unless the user explicitly asks for it -- for example,
> > we could have -fdelete-null-pointer-checks=2.  In fact, it might be a good idea
> > to implement this flag anyway, since some current uses of flag_delete_null_pointer_checks
> > can lead to "miscompilations" when user makes an error in their code and would
> > probably appreciate more having their program crash.
> >
> >> Oh, and of course it's even wrong.  I thing it needs &&
> >> !range_includes_zero (&vr1) (which we probably don't have).  The
> >> offset may be 0 and NULL + 0
> >> is still NULL.
> >
> > actually, the result of NULL + 0 is undefined (pointer arithmetics is only defined
> > for pointers to actual objects, and NULL cannot point to one).
> 
> It's maybe undefined in C, but is it undefined in the middle-end?  Thus,
> are you sure we never generate it from (void *)((uintptr_t)p + obfuscated_0)?
> I'm sure we simply fold that to p + obfuscated_0.

if we do, we definitely should not -- the only point of such a construction is
to bypass the pointer arithmetics restrictions,

Zdenek
Richard Guenther - June 17, 2011, 11:22 a.m.
2011/6/17 Zdenek Dvorak <rakdver@kam.mff.cuni.cz>:
> Hi,
>
>> >> > Index: tree-vrp.c
>> >> > ===================================================================
>> >> > --- tree-vrp.c  (revision 173703)
>> >> > +++ tree-vrp.c  (working copy)
>> >> > @@ -2273,7 +2273,12 @@ extract_range_from_binary_expr (value_ra
>> >> >        {
>> >> >          /* For pointer types, we are really only interested in asserting
>> >> >             whether the expression evaluates to non-NULL.  */
>> >> > -         if (range_is_nonnull (&vr0) || range_is_nonnull (&vr1))
>> >> > +         if (flag_delete_null_pointer_checks && nowrap_type_p (expr_type))
>> >>
>> >> the latter would always return true
>> >>
>> >> Btw, I guess you'll "miscompile" a load of code that is strictly
>> >> undefined.  So I'm not sure we want to do this against our users ...
>> >
>> > Probably not, at least unless the user explicitly asks for it -- for example,
>> > we could have -fdelete-null-pointer-checks=2.  In fact, it might be a good idea
>> > to implement this flag anyway, since some current uses of flag_delete_null_pointer_checks
>> > can lead to "miscompilations" when user makes an error in their code and would
>> > probably appreciate more having their program crash.
>> >
>> >> Oh, and of course it's even wrong.  I thing it needs &&
>> >> !range_includes_zero (&vr1) (which we probably don't have).  The
>> >> offset may be 0 and NULL + 0
>> >> is still NULL.
>> >
>> > actually, the result of NULL + 0 is undefined (pointer arithmetics is only defined
>> > for pointers to actual objects, and NULL cannot point to one).
>>
>> It's maybe undefined in C, but is it undefined in the middle-end?  Thus,
>> are you sure we never generate it from (void *)((uintptr_t)p + obfuscated_0)?
>> I'm sure we simply fold that to p + obfuscated_0.
>
> if we do, we definitely should not -- the only point of such a construction is
> to bypass the pointer arithmetics restrictions,

Ok, we don't.  Where does the C standard say that NULL + 0 is undefined?

Richard.

> Zdenek
>
Zdenek Dvorak - June 17, 2011, 2:12 p.m.
Hi,

> >> >> > Index: tree-vrp.c
> >> >> > ===================================================================
> >> >> > --- tree-vrp.c  (revision 173703)
> >> >> > +++ tree-vrp.c  (working copy)
> >> >> > @@ -2273,7 +2273,12 @@ extract_range_from_binary_expr (value_ra
> >> >> >        {
> >> >> >          /* For pointer types, we are really only interested in asserting
> >> >> >             whether the expression evaluates to non-NULL.  */
> >> >> > -         if (range_is_nonnull (&vr0) || range_is_nonnull (&vr1))
> >> >> > +         if (flag_delete_null_pointer_checks && nowrap_type_p (expr_type))
> >> >>
> >> >> the latter would always return true
> >> >>
> >> >> Btw, I guess you'll "miscompile" a load of code that is strictly
> >> >> undefined.  So I'm not sure we want to do this against our users ...
> >> >
> >> > Probably not, at least unless the user explicitly asks for it -- for example,
> >> > we could have -fdelete-null-pointer-checks=2.  In fact, it might be a good idea
> >> > to implement this flag anyway, since some current uses of flag_delete_null_pointer_checks
> >> > can lead to "miscompilations" when user makes an error in their code and would
> >> > probably appreciate more having their program crash.
> >> >
> >> >> Oh, and of course it's even wrong.  I thing it needs &&
> >> >> !range_includes_zero (&vr1) (which we probably don't have).  The
> >> >> offset may be 0 and NULL + 0
> >> >> is still NULL.
> >> >
> >> > actually, the result of NULL + 0 is undefined (pointer arithmetics is only defined
> >> > for pointers to actual objects, and NULL cannot point to one).
> >>
> >> It's maybe undefined in C, but is it undefined in the middle-end?  Thus,
> >> are you sure we never generate it from (void *)((uintptr_t)p + obfuscated_0)?
> >> I'm sure we simply fold that to p + obfuscated_0.
> >
> > if we do, we definitely should not -- the only point of such a construction is
> > to bypass the pointer arithmetics restrictions,
> 
> Ok, we don't.  Where does the C standard say that NULL + 0 is undefined?

I don't think it explicitly states that it is undefined.  But 6.5.6 #7 and #8 only
give semantics for pointers to objects,

Zdenek
Jeff Law - June 17, 2011, 6 p.m.
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

On 06/17/11 08:12, Zdenek Dvorak wrote:

>>> if we do, we definitely should not -- the only point of such a construction is
>>> to bypass the pointer arithmetics restrictions,
>>
>> Ok, we don't.  Where does the C standard say that NULL + 0 is undefined?
> 
> I don't think it explicitly states that it is undefined.  But 6.5.6 #7 and #8 only
> give semantics for pointers to objects,
Right.  I think we need to review the standard closely, but IIRC
pointers are allowed to be NULL, point into an object or point to one
element beyond an object.

If that's correct P+C could only result in a NULL value if P was one
element beyond the end of an object and C happened to be the exact magic
value to wrap P to zero.  I have a hard time seeing how code could which
did that (and relied upon it) could ever be standard conforming.

Closely related, given P+C where the result is a pointer ought to tells
us that P is non-null since the only way it could be null would be if C
was the exact magic constant to make the result point to a valid object.

Jeff
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v1.4.11 (GNU/Linux)
Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/

iQEcBAEBAgAGBQJN+5ZSAAoJEBRtltQi2kC7H34H/RG+9VrV6RqeolgSIqjyLsUf
WbJwl2AWo3xIMt/8OKpWG5zzhgJk67tW+PpSHhzs615kjRPryOiiNq+GBIelteKT
ho3mgbBeU5qJsPLU6j2feBR4+OEdo/oJZxHm/m8zUwWcGuZtazNGtoiuq7rlNr52
PDl7DM7ZWK731nFZfKYPq/fYMgNxWhxTBo9ucH3s9yXKJ6LYbUGHpKNyP14nB3n3
bJhdPF8A365uLYz5xCmP0QOKInbzNclN+gbTVZXc+NxtOYNUM16NalsxWhHSALCB
U0S9hpDMDznWWEwPDNdNN2oRphSGmIB0oYxeuaga5RgviNiPNVgEzANkGIv7OEo=
=z8kH
-----END PGP SIGNATURE-----
Richard Guenther - June 20, 2011, 10:52 a.m.
2011/6/17 Jeff Law <law@redhat.com>:
> -----BEGIN PGP SIGNED MESSAGE-----
> Hash: SHA1
>
> On 06/17/11 08:12, Zdenek Dvorak wrote:
>
>>>> if we do, we definitely should not -- the only point of such a construction is
>>>> to bypass the pointer arithmetics restrictions,
>>>
>>> Ok, we don't.  Where does the C standard say that NULL + 0 is undefined?
>>
>> I don't think it explicitly states that it is undefined.  But 6.5.6 #7 and #8 only
>> give semantics for pointers to objects,
> Right.  I think we need to review the standard closely, but IIRC
> pointers are allowed to be NULL, point into an object or point to one
> element beyond an object.
>
> If that's correct P+C could only result in a NULL value if P was one
> element beyond the end of an object and C happened to be the exact magic
> value to wrap P to zero.  I have a hard time seeing how code could which
> did that (and relied upon it) could ever be standard conforming.
>
> Closely related, given P+C where the result is a pointer ought to tells
> us that P is non-null since the only way it could be null would be if C
> was the exact magic constant to make the result point to a valid object.

So you propose we compile the following to an abort()?

int __attribute__((noinline)) foo (void *p, int i)
{
  return p + i != NULL;
}
int main()
{
  if (foo(NULL, 0))
    abort ();
  return 0;
}

?  Thus, would it be ok to fold ptr + offset ==/!= NULL to false/true?

I don't think we should move this kind of undefinedness from C to
the GIMPLE semantics.  What do other languages allow that
we have to support (what did K&R C specify?).

Richard.

> Jeff
> -----BEGIN PGP SIGNATURE-----
> Version: GnuPG v1.4.11 (GNU/Linux)
> Comment: Using GnuPG with Fedora - http://enigmail.mozdev.org/
>
> iQEcBAEBAgAGBQJN+5ZSAAoJEBRtltQi2kC7H34H/RG+9VrV6RqeolgSIqjyLsUf
> WbJwl2AWo3xIMt/8OKpWG5zzhgJk67tW+PpSHhzs615kjRPryOiiNq+GBIelteKT
> ho3mgbBeU5qJsPLU6j2feBR4+OEdo/oJZxHm/m8zUwWcGuZtazNGtoiuq7rlNr52
> PDl7DM7ZWK731nFZfKYPq/fYMgNxWhxTBo9ucH3s9yXKJ6LYbUGHpKNyP14nB3n3
> bJhdPF8A365uLYz5xCmP0QOKInbzNclN+gbTVZXc+NxtOYNUM16NalsxWhHSALCB
> U0S9hpDMDznWWEwPDNdNN2oRphSGmIB0oYxeuaga5RgviNiPNVgEzANkGIv7OEo=
> =z8kH
> -----END PGP SIGNATURE-----
>
Zdenek Dvorak - June 20, 2011, 12:20 p.m.
> I don't think we should move this kind of undefinedness from C to
> the GIMPLE semantics.  What do other languages allow that
> we have to support (what did K&R C specify?).

I don't think there is a formal specification of K&R C, just the (somewhat
informal) book.  On topic of pointer arithmetics, the case of addition
is not completely clear.  It does say that you can only subtract pointers
to members of the same array, though.

On topic of addition of integer to a pointer, it says that "The construction
p + n means the address of the n-th object beyond the one p currently points to. This is true
regardless of the kind of object p points to; n is scaled according to the size of the objects p
points to, which is determined by the declaration of p."

Zdenek
Zdenek Dvorak - June 20, 2011, 12:25 p.m.
> > I don't think we should move this kind of undefinedness from C to
> > the GIMPLE semantics.  What do other languages allow that
> > we have to support (what did K&R C specify?).
> 
> I don't think there is a formal specification of K&R C, just the (somewhat
> informal) book.  On topic of pointer arithmetics, the case of addition
> is not completely clear.  It does say that you can only subtract pointers
> to members of the same array, though.
> 
> On topic of addition of integer to a pointer, it says that "The construction
> p + n means the address of the n-th object beyond the one p currently points to. This is true
> regardless of the kind of object p points to; n is scaled according to the size of the objects p
> points to, which is determined by the declaration of p."

Anyway, I don't think that this should be a matter of lawyer scrutiny of the specifications;
rather, we should consider whether there is a situation where a user could reasonably expect
NULL + 0 to be valid.  In the example by Richard,

int __attribute__((noinline)) foo (void *p, int i)
{
  return p + i != NULL;
}

I think it would be hard to argue that this construction is natural.

Zdenek
Richard Guenther - June 20, 2011, 12:41 p.m.
On Mon, Jun 20, 2011 at 2:25 PM, Zdenek Dvorak <rakdver@kam.mff.cuni.cz> wrote:
>> > I don't think we should move this kind of undefinedness from C to
>> > the GIMPLE semantics.  What do other languages allow that
>> > we have to support (what did K&R C specify?).
>>
>> I don't think there is a formal specification of K&R C, just the (somewhat
>> informal) book.  On topic of pointer arithmetics, the case of addition
>> is not completely clear.  It does say that you can only subtract pointers
>> to members of the same array, though.
>>
>> On topic of addition of integer to a pointer, it says that "The construction
>> p + n means the address of the n-th object beyond the one p currently points to. This is true
>> regardless of the kind of object p points to; n is scaled according to the size of the objects p
>> points to, which is determined by the declaration of p."
>
> Anyway, I don't think that this should be a matter of lawyer scrutiny of the specifications;
> rather, we should consider whether there is a situation where a user could reasonably expect
> NULL + 0 to be valid.  In the example by Richard,
>
> int __attribute__((noinline)) foo (void *p, int i)
> {
>  return p + i != NULL;
> }
>
> I think it would be hard to argue that this construction is natural.

Nor does it feel natural that 'p' is different from 'p + 0'.

Richard.

> Zdenek
>
Michael Matz - June 20, 2011, 1:29 p.m.
Hi,

On Mon, 20 Jun 2011, Richard Guenther wrote:

> > of the specifications; rather, we should consider whether there is a 
> > situation where a user could reasonably expect NULL + 0 to be valid. 
> >  In the example by Richard,
> >
> > int __attribute__((noinline)) foo (void *p, int i)
> > {
> >  return p + i != NULL;
> > }
> >
> > I think it would be hard to argue that this construction is natural.
> 
> Nor does it feel natural that 'p' is different from 'p + 0'.

Right.  If we would include such reasoning in GIMPLE, we already could 
infer simply from the presence of any POINTER_PLUS_EXPR that the pointer 
operand is != NULL (which means != zero-bit-pattern in our case) in the 
control region containing it.

This might be tempting, but it would be quite confusing, and I'm not sure 
at all that we should include such reasoning for an IR that is supposed to 
be able to implement all languages, which in my book would include 
languages that simply define pointers as addresses in a wrapping space.

Hence, if the language in question does guarantee certain specifics (here 
non-null of p in 'p + i'), it should explicitely say so via assert_expr.  
Possibly this doesn't work currently that well, because we recompute and 
throw away assert_exprs sometimes, but I argue that we should work towards 
making this possible.


Ciao,
Michael.

Patch

Index: tree-vrp.c
===================================================================
--- tree-vrp.c	(revision 173703)
+++ tree-vrp.c	(working copy)
@@ -2273,7 +2273,12 @@  extract_range_from_binary_expr (value_ra
 	{
 	  /* For pointer types, we are really only interested in asserting
 	     whether the expression evaluates to non-NULL.  */
-	  if (range_is_nonnull (&vr0) || range_is_nonnull (&vr1))
+	  if (flag_delete_null_pointer_checks && nowrap_type_p (expr_type))
+	    {
+	      set_value_range_to_nonnull (vr, expr_type);
+	      set_value_range_to_nonnull (&vr0, expr_type);
+	    }
+	  else if (range_is_nonnull (&vr0) || range_is_nonnull (&vr1))
 	    set_value_range_to_nonnull (vr, expr_type);
 	  else if (range_is_null (&vr0) && range_is_null (&vr1))
 	    set_value_range_to_null (vr, expr_type);