commom malloc/free practice breaks standard - author strikes back

Brendan McKay bdm at anucsd.oz
Mon Oct 16 21:10:59 AEST 1989


Here are my responses to the first four "rebuttals" of my posting.
 
(A) Mike Haertel <mike at stolaf.edu>
 
> >* assigning a void* to an OBJ* involves rounding up to an even address
> The standard doesn't say anything about "rounding" pointers.
 
Nor should it---that's an implementation issue.  I'm allowed to implement
pointers and pointer casting in any way I please so long as the behaviour of
my implementation satisfies the requirements of the standard.
 
> Assigning a misaligned void* to an OBJ* might well cause a trap when
> the OBJ* is dereferenced.  Or even when the void* is just assigned to it!
 
What's a "misaligned void*"?  If you mean "a value of void* which cannot be
safely cast to OBJ* and dereferenced", then my implementation of malloc()
does not return any such values.   If you mean "a value of void* corresponding
to an odd underlying address", then no such traps will occur in my
implementation.  Are they compulsory?
 
> >* malloc allocates sufficient space so that it will cover an object of
> >  type OBJ even when the void* value returned is rounded up to even.
> >  (Thus, sometimes it actually allocates one more cell than it is asked for.)
 
> No!  The pointer returned by malloc() always has the most pessimistic
> necessary alignment.
 
I'm not sure what it means for a value of type A* to have alignment suitable
for type B*, unless it means that I can cast that A* to a B* and use it
to access a B. By that criterion, my malloc() returns values suitable for OBJ*.
The standard does have a concept of "type A has more strict
alignment requirement than type B", though.  It means I can confidentally
cast a A* to an B* and use the result, but may have trouble the other way
around.  Note that it refers to the result of casts, not to some arithmetic
property of underlying machine addresses or whatever.
 
=======
(B) Conor P. Cahill   <uunet!virtech!cpcahil>
 
> > "The pointer returned if the allocation succeeds is such that, if it is cast
> > to a pointer to any type of object and then that pointer is cast to type
> > void*, the original value is recovered."
 
> That is the meaning of the "suitably aligned so that it may be
> assigned to a pointer to any type of object and then used to access such an
> object..." (Section 4.10.3).
 
That was probably the intention, but it certainly isn't what it says.
My hypothetical implementation returns a value which can always be assigned
to an OBJ* and used to access an OBJ.  Doesn't it?
 
> An assignment of a void* pointer that is an invalid address for an OBJ*
> will usually cause a core drop at the point of dereference and may cause
> a core drop at the assignment.
 
The standard permits implementations where some pointer casting causes
exceptions or results in values which cannot be deferenced.  It doesn't
make such implementations compulsory.
 
> It *should* not modify the value of the pointer.
 
You have to be careful when you talk about "the value of the pointer"
across different pointer types.  If you mean "underlying bit pattern"
you are wrong: many existing implementations change bit patterns for
some pointer casts (consider char* on a word-addressed machine).
If you mean that the value before the cast must test as equal to that
after the cast, then my implementation *does* have that property.
Check the section on comparisons between pointers of different types---
it requires *casting*.
 
=====
(C) Scott A. Rotondo  <scott at Altos.COM>
 
> > Consider the following hypothetical implementation:
> > * pointers are implemented as memory addresses in the common way
> > * objects of type OBJ require even addresses.
> > * assigning a void* to an OBJ* involves rounding up to an even address
> > * malloc allocates sufficient space so that it will cover an object of
> >   type OBJ even when the void* value returned is rounded up to even.
> >   (Thus, sometimes it actually allocates one more cell than it is asked for.)
> > * assigning an OBJ* to a void* involves no change of address
 
> Your hypothetical implementation is not Standard-conforming because of
> the fourth point above.  Your quote from section 4.10.3 requires that
> the pointer returned from malloc() be aligned according to the most
> restrictive alignment requirements for this implementation.  That means
> that the cast from void * to OBJ * must leave the address unchanged
 
I have trouble with both "most restrictive alignment" (only used by the
standard as a property of types, not of pointer values) and "address
unchanged" (see part (B) above).
 
> (the internal pointer representation may change, but that is
> invisible).  Similarly, the cast from OBJ * to void * will not change
> the address.
 
That much is (sort of) implied by the rule that the pair of casts
OBJ* -> void* -> OBJ* gets you back where you started.  It's the other
cast which causes the trouble.
 
> > This implementation is unusual, but seems to obey the rules.  There was no
> > requirement that malloc() return an even address, only that the value
> > returned could be used after casting to OBJ*.  However, when objptr is cast
> > back to void* for passing to free(), the value obtained is possibly different
> > from the one returned by malloc(), thus breaking the rules for free().
>
> As indicated above, malloc() must return an even address in this
> implementation.  Since neither cast will change the address, free()
> will work as expected.
 
Already answered, I think.
 
> > No doubt this problem was unintentional.  It could easily be fixed by a
> > sentence reading something like "The pointer returned if the allocation
> > succeeds is such that, if it is cast to a pointer to any type of object
> > and then that pointer is cast to type void*, the original value is
> > recovered."
 
> This is precisely the meaning of the section 4.10.3 alignment rule.
 
The intention, I'm sure.  The meaning is another matter.
 
=====
(D) Doug Gwyn  <gwyn at smoke.brl.mil>
> >Note that I'm not claiming the Standard is broken, only that the writers of
> >the standard have accidentally ruled out a common coding practice.
 
> No, we didn't -- any valid pointer can be converted to a pointer that
> has less strict alignment and back, so that the result compares equal
> to the original pointer,
 
I can only find this rule for OBJ* -> void* -> OBJ* and OBJ* -> char* -> OBJ*.
Am I missing a section?
 
> void* has the same alignment requirement as
> char*, and converting a coarsely-aligned malloc() void* to OBJ* does
> NOT result in adjustment of the alignment.
 
Hang on.  OBJ* has a MORE strict alignment requirement than void*, not less,
so the general rule you mention doesn't apply.  Moreover, I can't find any
support in the standard for your concept "coarsely-aligned malloc()" except
as it applies to the validity and result of a pointer cast.  By that
criterion, my hypothetical implementation is fine (until proven otherwise).
 
> Apply ALL the relevant constraints and you'll find that there is no problem
> with typical malloc()/free() usage.
 
Maybe, but I need more convincing yet.
 
===========================================================================
 
Oh, I'm only a poor theoretician having a bit of fun.  Keep it coming.
Is anyone out there brave enough to AGREE with me?
 
Brendan McKay.   bdm at anucsd.oz  or  bdm at anucsd.oz.au
 



More information about the Comp.lang.c mailing list