Re: [Lit.] Buffer overruns

From: infobahn (infobahn_at_btinternet.com)
Date: 01/17/05


Date: Mon, 17 Jan 2005 00:46:26 +0000 (UTC)


[David Wagner's erroneous reply has not yet hit my server, so
I'll respond here, both to his article and to BRG's.]

BRG wrote:
>
> David Wagner wrote:
> > infobahn wrote:
> >
> >>David Wagner wrote:
> >>
> >>>Yup. Another example: the meaning of &x changes when you change x from
> >>>an array type to a pointer type.
> >>
> >>I don't see it. & is the address operator, and &x yields the address
> >>of the x object, irrespective of the type of x.
> >
> >
> > Not true.

Wrong! :-)

> > &x yields the same address as x, if x is an array -- but
> > not if x is a pointer. See below.

No, &x does not yield the same address as x when x is an array.
&x yields the address of the *array*. x, in a value context, yields
the address of the first element in that array. These two values
have different types, and are thus not comparable.

> >
> > $ cat array.c
> > #include <stdio.h>
> >
> > int main() {
> > char x[100];
> > printf("%p %p %d\n", x, &x, x == &x);

Undefined behaviour. %p expects void *. You are passing char * and
char (*)[100]. Furthermore, your comparison x == &x is illegal. The
C Standard makes this clear in 6.5.8(5):

"When two pointers are compared, the result depends on the relative
locations in the address space of the objects pointed to. If two
pointers to object or incomplete types both point to the same object,"

Nope. One points to x, and the other points to x[0]. These are not
the same object.

"or both point one past the last element of the same array object,"

Nope. One points to the array itself, and the other points to the
beginning of the array.

"they compare equal. If the objects pointed to are members of the
same aggregate object,"

Nope. x (in a value context such as this) points to x[0], which is
indeed a member of the array, but &x does not point to a member of
the aggregate object, but to the object itself.

"pointers to structure members declared later compare greater than
pointers to members declared earlier in the structure,"

Nope. No structs here.

"and pointers to array elements with larger subscript values compare
greater than pointers to elements of the same array with lower
subscript values."

Nope, because &x doesn't point to an element of the array, but to the
array itself.

"All pointers to members of the same union object compare equal."

Nope. No unions here.

"If the expression P points to an element of an array object and the
expression Q points to the last element of the same array object, the
pointer expression Q+1 compares greater than P."

Nope. Neither x nor &x points to the last element of the array.

"In all other cases, the behavior is undefined."

QED. Perhaps /you/ should use ABC-enabled implementations? :-)

> > return 0;
> > }
> > $ gcc array.c
> > $ ./a.out
> > 0xbffff970 0xbffff970 1
>
> It's even more fun to ask even experienced C users to predict the output
> of the following program before running it.

Okay, I'm game.

>
> ---------------------------------
> #include <stdio.h>
> typedef char ctype[100];
> int main()
> { char x[100], *y;
> ctype c;
> printf("\n%3d %3d", sizeof(x), sizeof(&x));

100 4 (on systems where char(*)[100] is 4).

> printf("\n%3d %3d", sizeof(y), sizeof(&y));

  4 4 (on systems where char * and char ** both have size 4!)

> printf("\n%3d %3d", sizeof(c), sizeof(&c));

100 4 (on systems where char (*)[100] is 4.

So in summary, I expect

100 4
  4 4
100 4

NOW I'll run it on my system...

First, Borland:

100 100
  4 4
100 100

This is not in line with my expectations. But all is not lost! Let's
try gcc:

gcc -W -Wall -ansi -pedantic tryit.c -o tryit
tryit.c: In function `main':
tryit.c:6: warning: int format, long int arg (arg 2)
tryit.c:6: warning: int format, long int arg (arg 3)
tryit.c:7: warning: int format, long int arg (arg 2)
tryit.c:7: warning: int format, long int arg (arg 3)
tryit.c:8: warning: int format, long int arg (arg 2)
tryit.c:8: warning: int format, long int arg (arg 3)

Tut-tut. :-)

Here's the output:

100 4
  4 4
100 4

I conclude that Borland's compiler gives incorrect results! But
gcc looks fine to me.



Relevant Pages