From: kanze@us-es.sel.de (James Kanze)
Subject: Re: struct hack
Organization: SEL
	<1992Sep19.225457.13353@jarvis.csri.toronto.edu>
	<KANZE.92Oct2210740@slsvdnt.us-es.sel.de> <1992Oct7.001450.16021@sq.sq.com>
Date: 7 Oct 92 21:22:15

In article <1992Oct7.001450.16021@sq.sq.com> msb@sq.sq.com (Mark
Brader) writes:

> > I have been following this thread for a while, and since nobody else
> > seems to have said it, I will.
> > 
> > >     struct fred { int i; char s [1]; } *f;
> > >     char *s;
> > > 
> > >     /* ... */
> > >     f = malloc (sizeof f + strlen (ss));
> > >     f->s[1 /* or 2, or anything other than 0 */] ;
> > 
> > ... As is pointed out in previous posts, the pointer returned by malloc
> > points to an area big enough for the job.  In fact, the following
> > should be legal:
> > 
> >     char *p = malloc( sizeof( struct fred ) + strlen( ss ) ) ;
> >     p += offsetof( struct fred , s ) ;
> >     p[ 1 /* Or anything up to the end of the malloced memory */ ]
> > 
> > The problem with the example is that the pointer under consideration
> > is *not* the pointer returned from malloc, but rather the results of
> > the pointer expression f->s (which has a type of char*).

> Correct, but this does not affect the relative legality of the two
> expressions.  The standard says in 3.1.2.5 (ANSI, 6.1.2.5 in ISO) that
> a value of pointer type "provides a reference to an entity of the
> referenced type".  That is, a char * points to ONE char.  Whether that
> char happens to be part of a larger object is irrelevant; this fact
> cannot be represented in the type.  Suppose the above examples to be
> modified so that f and p are initially copies of the same value returned
> by a single call to malloc(), with the subsequent operations the same.
> The expressions p and f->s point to the same char; therefore they are
> wholly identical; assuming that strlen didn't return 0, p[1] is legal;
> therefore, under the same assumption, f->s[1] is legal.

> The restrictions in 3.3.6 (6.3.6) that allow bounds checking are on
> the additive operators (and therefore implicitly on subscripting, of
> course).  They are expressed in terms of whether the operand pointer
> value and the resulting value point to elements of the same array or
> not; there is nothing about HOW the operand value pointing into that
> array was obtained in the first place.  In this case the values do
> point to elements of the same array, namely the malloc()ed one.  QED.

As has also been pointed out to me in email, I made a mistake at the
end of my previous posting, which in fact negated most of my argument.

The expression f->s does not have type char*, it has type char[1].  It
does not refer to the array returned by malloc, but simply to a small
part of it, the part defined in the structure.  This part has a length
of one.  (Try sizeof(f->s).)  This array then converts to an address
in any expression (except sizeof).  The restrictions in the ANSI
standard thus explicitly allow bounds checking on it, since the
operand pointer points the the array of one character within the
structure.  (Whether the structure itself is on the heap, the stack or
in static memory is irrelevent to the question.)

On the other hand, the playing around with p at the end of my posting
*is* legal for exactly the reasons you say.  The only "array" which
contains p is the one returned by malloc.
--
James Kanze                     GABI Software, Sarl.
email: kanze@us-es.sel.de       8 rue du Faisan
                                67000 Strasbourg
                                France
Newsgroups: comp.std.c