Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > C Programming > Arithmetic will null pointer

Reply
Thread Tools

Arithmetic will null pointer

 
 
Urs Thuermann
Guest
Posts: n/a
 
      06-16-2010
I have again a question that I don't find a definitve answer for in my
draft copy of ISO 9899-99: Is it allowed to add an integer to a null
pointer and what will be the result?

See the following short example:

char *a = 0, *b = 0, *p, *q;
void f(void)
{
p = a + 0;
q = a + 10;
}


I only could find constraints for pointers that point to an object in
section "6.5.6 Additive operators":

Constraints

[#2] For addition, either both operands shall have
arithmetic type, or one operand shall be a pointer to an
object type and the other shall have integer type.
(Incrementing is equivalent to adding 1.)

So the pointer must have object type (as opposed to void*), but does
not need to point to an object. Right? Then (char*)0 would be ok.

[#7] For the purposes of these operators, a pointer to a
nonarray object behaves the same as a pointer to the first
element of an array of length one with the type of the
object as its element type.

[#8] When an expression that has integer type is added to or
subtracted from a pointer, the result has the type of the
pointer operand. If the pointer operand points to an
element of an array object, ...

The null pointer is neither a pointer to a nonarray object nor a
pointer to an array element. So [#8] only says that (char*)0 + 1 is
of type (char*), but the rest is irrelvant.

So is that addition allowed? And is there a guarantee, that

(char*)0 + 0 == (char*)0

and

(char*)0 + 1 != (char*)0

It is clear that allmost all implementations will do so but can one
rely on this? This question turned up to me when I was writing a
short code snippet, similar to this:

char *s = 0, *old;
size_t size = 0, len = 0, n;

for (...) {
do {
n = snprintf(s + len, size - len, fmt, ...);
if (n >= size - len) {
old = s;
size += 1024;
s = realloc(s, size);
if (!s) {
goto error;
}
}
} while (s != old);
len += n;
}

The term s + len will be null pointer plus 0 in the first iteration.
(BTW, snprint(NULL, 0, ...) is allowed by ISO C, no problem here).


urs
 
Reply With Quote
 
 
 
 
Urs Thuermann
Guest
Posts: n/a
 
      06-16-2010
Richard Heathfield <> writes:

> The compiler is not required to diagnose such an addition, but the
> behaviour is undefined. See paragraph 8 of the section you quoted
> (6.5.6 Additive operators).


I don't see where this paragraph says that such an addition yields
undefined behavior. That paragraph starts as follows:

[#8] When an expression that has integer type is added to or
subtracted from a pointer, the result has the type of the
pointer operand.

This only specifies that the type of (char*)0 + 0 is (char*). As I
read it, the whole rest of the paragraph depends on the directly
following condition:

If the pointer operand points to an element of an array
object, and the array is large enough, ...

Since (char*)0 does not point to an element of an array object the
rest of the paragraph doesn't say anything about the above addition.
I assume you refer to the sentence

If both the pointer operand and the result point to elements
of the same array object, or one past the last element of the
array object, the evaluation shall not produce an overflow;
otherwise, the behavior is undefined.

Are you sure this not dependent on the first condition cited above?
This sentence refers to "the result" of which we only know how it is
derived when the pointer operand points to an element of an array
object.

Or do I misunderstand this paragraph 8 so fundamentally?


urs
 
Reply With Quote
 
 
 
 
Eric Sosman
Guest
Posts: n/a
 
      06-16-2010
On 6/16/2010 4:20 PM, Richard Heathfield wrote:
> Urs Thuermann wrote:
>> Richard Heathfield <> writes:
>>
>>> The compiler is not required to diagnose such an addition, but the
>>> behaviour is undefined. See paragraph 8 of the section you quoted
>>> (6.5.6 Additive operators).

>
> <snip>
>
>> I assume you refer to the sentence
>>
>> If both the pointer operand and the result point to elements
>> of the same array object, or one past the last element of the
>> array object, the evaluation shall not produce an overflow;
>> otherwise, the behavior is undefined.

>
> You assume correctly.
>
>> Are you sure this not dependent on the first condition cited above?

>
> Yes. Since a null pointer doesn't point to an object, neither it nor the
> result can point to "elements of the same array object, or one past the
> last element of the array object", and therefore the behaviour is
> undefined.


Further to this point: Behavior is undefined if the Standard
says so explicitly, *or* if a requirement outside a constraint
section is violated, *or* if the Standard simply doesn't describe
the behavior at all. All of these are "equally undefined" (4p1).

When attempting arithmetic on a null-valued pointer, it's the
third of these situations: The Standard describes what happens if
the pointer points at or just after an object, but a null-valued
pointer doesn't do so. Therefore, the Standard's description does
not cover the case, and the behavior is "undefined by omission."

--
Eric Sosman
lid
 
Reply With Quote
 
Seebs
Guest
Posts: n/a
 
      06-16-2010
On 2010-06-16, Richard Heathfield <> wrote:
> Yes. Since a null pointer doesn't point to an object, neither it nor the
> result can point to "elements of the same array object, or one past the
> last element of the array object", and therefore the behaviour is undefined.


Okay, I haven't had any caffeine today, but.

What tells us that a null pointer cannot point one past the last
element of an array object?

I agree that nothing tells us that it *does* point one past the last
element of an array object. But could it?

-s
--
Copyright 2010, all wrongs reversed. Peter Seebach / usenet-
http://www.seebs.net/log/ <-- lawsuits, religion, and funny pictures
http://en.wikipedia.org/wiki/Fair_Game_(Scientology) <-- get educated!
 
Reply With Quote
 
Keith Thompson
Guest
Posts: n/a
 
      06-17-2010
Eric Sosman <> writes:
> On 6/16/2010 4:20 PM, Richard Heathfield wrote:
>> Urs Thuermann wrote:
>>> Richard Heathfield <> writes:
>>>> The compiler is not required to diagnose such an addition, but the
>>>> behaviour is undefined. See paragraph 8 of the section you quoted
>>>> (6.5.6 Additive operators).

>>
>> <snip>
>>
>>> I assume you refer to the sentence
>>>
>>> If both the pointer operand and the result point to elements
>>> of the same array object, or one past the last element of the
>>> array object, the evaluation shall not produce an overflow;
>>> otherwise, the behavior is undefined.

>>
>> You assume correctly.
>>
>>> Are you sure this not dependent on the first condition cited above?

>>
>> Yes. Since a null pointer doesn't point to an object, neither it nor the
>> result can point to "elements of the same array object, or one past the
>> last element of the array object", and therefore the behaviour is
>> undefined.

>
> Further to this point: Behavior is undefined if the Standard
> says so explicitly, *or* if a requirement outside a constraint
> section is violated, *or* if the Standard simply doesn't describe
> the behavior at all. All of these are "equally undefined" (4p1).
>
> When attempting arithmetic on a null-valued pointer, it's the
> third of these situations: The Standard describes what happens if
> the pointer points at or just after an object, but a null-valued
> pointer doesn't do so. Therefore, the Standard's description does
> not cover the case, and the behavior is "undefined by omission."


Actually, as Richard pointed out, the standard says explicitly that
it's undefined:

C99 6.5.6p8 (emphasis added):

If both the pointer operand and the result point to elements of the
same array object, or one past the last element of the array object,
the evaluation shall not produce an overflow; *otherwise, the
behavior is undefined*.

(Unless a null pointer points one past the last element of the array
object, as Seebs suggests.)

--
Keith Thompson (The_Other_Keith) kst- <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
 
Reply With Quote
 
Keith Thompson
Guest
Posts: n/a
 
      06-17-2010
Seebs <usenet-> writes:
> On 2010-06-16, Richard Heathfield <> wrote:
>> Yes. Since a null pointer doesn't point to an object, neither it nor the
>> result can point to "elements of the same array object, or one past the
>> last element of the array object", and therefore the behaviour is undefined.

>
> Okay, I haven't had any caffeine today, but.
>
> What tells us that a null pointer cannot point one past the last
> element of an array object?
>
> I agree that nothing tells us that it *does* point one past the last
> element of an array object. But could it?


In theory, I think so.

C99 6.3.2.3p3:

If a null pointer constant is converted to a pointer type,
the resulting pointer, called a _null pointer_, is guaranteed
to compare unequal to a pointer to any object or function.

An implementation for which a null pointer is equal to a pointer just
past the end of some object could break some seemingly reasonable
code (but only if it happens to be operating on that one object),
but I don't see anything in the standard that forbids it.

An almost-plausible scenario: A null pointer is represented as
all-bits-zero. Automatic objects are allocated on The Stack, which
grows from high addresses to low, and starts at the top end of the
address space, address 0xffffffff. Pointer arithmetic quietly wraps
around from 0xffffffff to 0. The last byte of the first allocated
object in the program (perhaps argc, perhaps the string pointed to
by argv[0], perhaps something else) occupies byte 0xffffffff.

I doubt that any such implementations actually exist.

--
Keith Thompson (The_Other_Keith) kst- <http://www.ghoti.net/~kst>
Nokia
"We must do something. This is something. Therefore, we must do this."
-- Antony Jay and Jonathan Lynn, "Yes Minister"
 
Reply With Quote
 
Peter Nilsson
Guest
Posts: n/a
 
      06-17-2010
Keith Thompson <ks...@mib.org> wrote:
> An almost-plausible scenario: A null pointer is represented
> as all-bits-zero. *Automatic objects are allocated on The
> Stack, which grows from high addresses to low, and starts
> at the top end of the address space, address 0xffffffff.
>*Pointer arithmetic quietly wraps around from 0xffffffff to
> 0. *The last byte of the first allocated object in the
> program (perhaps argc, perhaps the string pointed to
> by argv[0], perhaps something else) occupies byte
> 0xffffffff.
>
> I doubt that any such implementations actually exist.


Particularly as 0x00000000 would have to compare greater
than 0xffffffff for an object landing on that address.

In practice, implementations already have to allow
problems with 'one past the end' pointers in memory
allocations.

--
Peter
 
Reply With Quote
 
Peter Nilsson
Guest
Posts: n/a
 
      06-17-2010
Richard Heathfield <r...@see.sig.invalid> wrote:
> Seebs wrote:
> > What tells us that a null pointer cannot point one past
> > the last element of an array object?
> >
> > I agree that nothing tells us that it *does* point one
> > past the last element of an array object. *But could it?

>
> Who cares? Even if it did, there is no strictly conforming
> way to tell /which/ object it were pointing one past the end
> of,


Well, people do use one past the end pointers as sentinels,
e.g. in for loops. People also compare against null. Whilst
I can't think of a specific circumstance where one would
compare one past the end with null (directly or indirectly,)
it's not beyond the realms of possibility that some code
somewhere might actually rely on the equality not being
equal.

--
Peter
 
Reply With Quote
 
Peter Nilsson
Guest
Posts: n/a
 
      06-17-2010
Richard Heathfield <r...@see.sig.invalid> wrote:
> Peter Nilsson wrote:
> > Well, people do use one past the end pointers as sentinels,
> > e.g. in for loops.

>
> Yes, but you wouldn't use (NULL + n) as your sentinel, would
> you?


No. That's not my point following from Seebs comment.

> > People also compare against null. Whilst
> > I can't think of a specific circumstance where one would
> > compare one past the end with null (directly or indirectly,)


Change that...

> > it's not beyond the realms of possibility that some code
> > somewhere might actually rely on the equality not being
> > equal.

>
> Either "one past the end" is guaranteed not to be a null
> pointer, or it isn't. Right now, I'm in too much of a hurry
> to look it up. If it *is* guaranteed not to be a null pointer,
> then your scenario is of no consequence and this whole
> subthread is chasing a scotch mist. If it is *not* guaranteed
> not to be a null pointer, then code that assumes it isn't a
> null pointer is relying on a broken assumption.


But it seems a reasonable assumption.

Here's a contrived example:

T *col;
T *found = NULL;

for (col = vector; col < vector + N; col++)
{
if (something(*col))
found = col;
if (something_else(*col))
break;
}

/* did we find something and break at the same spot? */
/* assumption: one past end cannot be null */
if (found == col)
do_something();

Some might call that poor coding, some might call it
efficient.

--
Peter
 
Reply With Quote
 
Stargazer
Guest
Posts: n/a
 
      06-17-2010
On Jun 17, 4:15*am, Keith Thompson <ks...@mib.org> wrote:

[...]
> An almost-plausible scenario: A null pointer is represented as
> all-bits-zero. *Automatic objects are allocated on The Stack, which
> grows from high addresses to low, and starts at the top end of the
> address space, address 0xffffffff. *Pointer arithmetic quietly wraps
> around from 0xffffffff to 0. *The last byte of the first allocated
> object in the program (perhaps argc, perhaps the string pointed to
> by argv[0], perhaps something else) occupies byte 0xffffffff.
>
> I doubt that any such implementations actually exist.


It is forbidden for an implementation to do things this way: "If both
the pointer
operand and the result point to elements of the same array object, or
one past the last
element of the array object, the evaluation shall not produce an
overflow, otherwise, the
behavior is undefined." (6.5.6[8])

In your proposal incrementing pointer to one past the last element of
an array does produce an overflow.

Daniel
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
pointer to pointer intialize to NULL but still point to NULL Christopher C++ 4 07-09-2011 12:35 AM
Null pointer (NULL array pointer is passed) aneuryzma C++ 3 06-16-2008 05:48 AM
"stringObj == null" vs "stringObj.equals(null)", for null check?? qazmlp1209@rediffmail.com Java 5 03-29-2006 10:37 PM
Usual Arithmetic Conversions-arithmetic expressions joshc C Programming 5 03-31-2005 02:23 AM
Pointer arithmetic involving NULL pointers Christopher Benson-Manica C Programming 22 09-14-2004 04:01 PM



Advertisments
 



1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57