[comp.std.c] malloc

gwyn@smoke.BRL.MIL (Doug Gwyn ) (04/04/89)

In article <9132@alice.UUCP> andrew@alice.UUCP (Andrew Hume) writes:
>the ONLY justification put forward is some stuff about zero-sized
>objects (gwyn admits to being the point of contact). the only
>point actually mentioned is devising semantics for zero-sized objects; ...

I believe that was in fact the only technical issue involved in the
decision to permit malloc(0) to fail for reasons other than running out
of memory.  There were several X3J11 members who, rightly recognizing
that if the standard permitted portable programs to rely on malloc(0)
succeeding under normal circumstances it would also have to address the
issue of semantics for 0-sized objects, balked at having to cross that
threshold.  I'm a big fan of 0-sized objects, but I've become convinced
that formally recognizing them would have significant impact in several
places in the standard.  The amount of work to get all the technical
points right was considered more than could be justified simply to
support the style of malloc() usage you're interested in.

Incidentally, our last-minute reworking of the wording about last-plus-
one element of arrays, etc. may have provided most of the scaffolding
needed to formally support 0-sized objects as well.  However, 0-sized
objects could not be allowed without explicit full committee action,
since they had been explicitly disallowed in previous voting.

Some people might make the argument that it is more likely when malloc()
is called with a 0 size request that there is a bug in the program than
that it is a consistent and sensible thing to be attempting.  Certainly
it COULD be used for legitimate purposes as Andrew apparently does, but
most of the malloc() applications I've seen are already in trouble if
they get to the point where they would be malloc(0)ing.  Thus I don't
think the ANSI-portable malloc() behavior poses a significant problem.

#define	myalloc(n)	malloc((n)?(n):1)

bothner@sevenlayer.cs.wisc.edu (Per Bothner) (07/15/90)

I'm trying to clarify the allowed implementation of malloc(0).
I'm hoping the standard permits malloc(0) to
actually allocate memory (for each call). (In other words,
a implementation is allowed to in essence convert malloc(0)
to malloc(small_positive_integer).) This behavior is
actually *required* for C++, according to Ellis&Stroustrup:
The Annotated C++ Reference Manual, and it would be nice if
it were at least *permitted* in C.

The question hinges of the meaning of the phrase "unique pointer" below:

    4.10.3 Memory management functions

    The order and contiguity of storage allocated by successive calls to
    the calloc, malloc, and realloc functions is unspecified.  The pointer
    returned if the allocation succeeds is suitably aligned so that it may
    be assigned to a pointer to any type of object and then used to access
    such an object or an array of such objects in the space allocated (until
    the space is explicitly freed or reallocated).  Each such allocation
    shall yield a pointer to an object disjoint from any other object.  The
    pointer returned points to the start (lowest byte address) of the allocated
    space.  If the space cannot be allocated, a null pointer is returned.
    If the size of the space requested is zero, the behavior is implementation-
    defined; the value returned shall be either a null pointer or a unique
    pointer.  The value of a pointer that refers to freed space is
    indeterminate.

One suggested interpretation is that "a unique pointer" means a
globally static/fixed address. Another is a "pointer to an object
disjoint from any other object." This is seems more reasonable to
me. However, the definition of realloc() (4.10.3.4) seems
to conflict with the latter interpretation:

    If SIZE is zero and PTR is not a null pointer, the object it points
    to is freed.

	--Per Bothner
bothner@cs.wisc.edu Computer Sciences Dept, U. of Wisconsin-Madison

gwyn@smoke.BRL.MIL (Doug Gwyn) (07/24/90)

In article <10830@spool.cs.wisc.edu> bothner@sevenlayer.cs.wisc.edu (Per Bothner) writes:
>I'm trying to clarify the allowed implementation of malloc(0).
>I'm hoping the standard permits malloc(0) to
>actually allocate memory (for each call). (In other words,
>a implementation is allowed to in essence convert malloc(0)
>to malloc(small_positive_integer).)

A conforming implementation may do that, or it may always return a null
pointer.  If the pointer is non-null, it should point to a storage region
having a distinct address from all other object and 0-malloc()ed addresses.

>The question hinges of the meaning of the phrase "unique pointer" below:

No, the important issue is that there are no 0-sized objects in C, so
the program making a malloc(0) call is not strictly conforming, and thus
a conforming implementation is free to interpret the malloc(0) request
as it sees fit; however, other constraints should be obeyed.  The clear
intent of the pointer uniqueness requirement is to ensure that equality
of valid pointers implies that the same object is pointed to by both
pointers.  If it were not for this requirement, all malloc(0) requests
could be satisfied by returning a constant pointer to some valid library
object.  As it is, however, a distinct pointer should be handed out for
each active malloc(0).  Since each allocated block normally has an
associated bookkeeping header in front of it, this is easy to accomplish
with linked-list allocation schemes.  With a "buddy system" allocator
special care must be taken to change the size from 0 to some positive
value.  (I don't recommend "buddy system" allocators anyway.)

>However, the definition of realloc() (4.10.3.4) seems
>to conflict with the latter interpretation:
>    If SIZE is zero and PTR is not a null pointer, the object it points
>    to is freed.

It's not a conflict, just a reason to be careful if you want to exploit
an implementation's extended malloc(0) support.

dan@oresoft.com (Daniel Elbaum) (07/27/90)

In <13384@smoke.BRL.MIL> gwyn@smoke.BRL.MIL (Doug Gwyn) writes:

>In article <10830@spool.cs.wisc.edu> bothner@sevenlayer.cs.wisc.edu (Per Bothner) writes:
>>I'm trying to clarify the allowed implementation of malloc(0).

>A conforming implementation may ... always return a null
>pointer.  If the pointer is non-null, it should point to a storage region
>having a distinct address from all other object and 0-malloc()ed addresses.

>>The question hinges of the meaning of the phrase "unique pointer" below:

>No, the important issue is that there are no 0-sized objects in C, so
>the program making a malloc(0) call is not strictly conforming, and thus
>a conforming implementation is free to interpret the malloc(0) request
>as it sees fit; however, other constraints should be obeyed.  The clear
>intent of the pointer uniqueness requirement is to ensure that equality
>of valid pointers implies that the same object is pointed to by both
>pointers.  If it were not for this requirement, all malloc(0) requests
>could be satisfied by returning a constant pointer to some valid library
>object.

How can one zero-sized object be the "same" as another?   Since C
does not have zero-sized objects, a program must not do anything
with that which is pointed to by the return value of malloc(0).  If
an implementation chooses to return a valid pointer to an object of
no particular size, it's still illegal to use that object.  The
pointer is "unique" insofar as it can only be obtained by a call
to malloc or calloc with a zero argument.  Is this meaning of
"unique" consistent with the wording and intent of 4.10.3?

>>However, the definition of realloc() (4.10.3.4) seems
>>to conflict with the latter interpretation:
>>    If SIZE is zero and PTR is not a null pointer, the object it points
>>    to is freed.

>It's not a conflict, just a reason to be careful if you want to exploit
>an implementation's extended malloc(0) support.

"Freeing" an object appears to mean, according to 4.10.3.2, making
that object available to future calls to malloc() and calloc().  If
the object is already available in a way that does not conflict with
4.10.3, then the call to free() is permitted to have nil effect.
-- 
Being conservative in most respects and reluctant to transform country and
constitution, the coup d'etat typically neither attracts nor needs the fanatic.

({uunet,tektronix,reed,sun!nosun,m2xenix}!oresoft!(dan)@oresoft.com)

gwyn@smoke.BRL.MIL (Doug Gwyn) (07/29/90)

In article <1990Jul26.232216.15093@oresoft.com> dan@oresoft.com (Daniel Elbaum) writes:
>Is this meaning of "unique" consistent with the wording and intent of 4.10.3?

Unique pointers mean just what I said in my previous message.
I don't know why you're concentrating on the (empty) content of the objects;
I was discussing pointers to the objects, which is what matters here.
I could repeat what I said before, or you could retrieve it and study
it until you understand my point.

dan@oresoft.com (Daniel Elbaum) (08/01/90)

In <13441@smoke.BRL.MIL> gwyn@smoke.BRL.MIL (Doug Gwyn) writes:
:In article <1990Jul26.232216.15093@oresoft.com> dan@oresoft.com (Daniel Elbaum) writes:
:>Is this meaning of "unique" consistent with the wording and intent of 4.10.3?

:Unique pointers mean just what I said in my previous message.
:I don't know why you're concentrating on the (empty) content of the objects;
:I was discussing pointers to the objects, which is what matters here.
:I could repeat what I said before, or you could retrieve it and study
:it until you understand my point.

Your point isn't difficult to understand.  But it was stated as an
assertion rather than a conclusion.  You said

	The clear intent of the pointer uniqueness requirement is to
	ensure that equality of valid pointers implies that the same
	object is pointed to by both pointers.  If it were not for this
	requirement, all malloc(0) requests could be satisfied by
	returning a constant pointer to some valid library object.

I meant to ask what you mean by "the same object."  Suppose we have
two library routines, malloc1() and malloc2().  Malloc1 conforms to
the requirements you mentioned in your previous posting.  Malloc2
behaves like the hypothetical routine suggested in Bothner's
original article--it always returns the same valid pointer when
called with a zero argument, and never returns that pointer when
called with a nonzero argument.  Now if two valid pointers are
obtained from malloc1(0) (with no intervening call to free()),
the pointers are known to be distinct.  If, on the other hand,
two pointers are obtained from malloc2(0), their values are known
to be identical.  They compare equal, but it's impossible to say
that they point to the same object, because what they point to isn't,
formally speaking, an object.

Leaving aside the issue of ease of implementation, each approach has
one major advantage.  Malloc1 provides a safe means of obtaining a
unique, valid pointer.  Malloc2 provides a single value for the
pointer-to-zero-sized-object.  Either may be useful according to
the application.  For example, one approach to error handling might
take advantage of malloc2's behavior by checking pointers against
the "known-zero" pointer at critical spots in a program.

In short, the second approach has some merit.  How (and why) is it
forbidden by the Standard?
-- 
Being conservative in most respects and reluctant to transform country and
constitution, the coup d'etat typically neither attracts nor needs the fanatic.

({uunet,tektronix,reed,sun!nosun,m2xenix}!oresoft!(dan)@oresoft.com)
-- 
Being conservative in most respects and reluctant to transform country and
constitution, the coup d'etat typically neither attracts nor needs the fanatic.

({uunet,tektronix,reed,sun!nosun,m2xenix}!oresoft!(dan)@oresoft.com)

gwyn@smoke.BRL.MIL (Doug Gwyn) (08/03/90)

In article <1990Jul31.222850.1873@oresoft.com> dan@oresoft.com (Daniel Elbaum) writes:
>If, on the other hand, two pointers are obtained from malloc2(0), their
>values are known to be identical.  They compare equal, but it's impossible
>to say that they point to the same object, because what they point to isn't,
>formally speaking, an object.

It is, if the implementation provides this 0-sized object extension.

>In short, the second approach has some merit.  How (and why) is it
>forbidden by the Standard?

A strictly conforming program may not rely on malloc() supporting
0-sized objects at all.  If some implementation provides such
support as an extension, it should do so in a way that is consistent
with the principles used in the standard.  In this context, the most
important principles are that pointers to distinct objects must not
compare equal, and that each invocation of malloc() must allocate an
object distinct from all other currently valid objects.

I provide this just as guidance for implementors.  Technically, such
extensions are constrained by the standard only to the extent that
they can be interpreted in terms of the basic standard.  Since there
are no explicit guidelines for 0-sized objects in the standard, some
attributes of such objects in an extended implementation are subject
to "judgement calls".  As Point Of Contact for 0-sized objects, I've
heard essentially all of the arguments pro and con each choice, and
what I recommend is simply my best judgement concerning the matter.
In particular, if programs are to make real use of 0-sized objects,
they will benefit greatly if separately-malloc()ed ones do not seem
to have equal pointers.  Try writing some heavy-duty applications
involving this stuff and see what I mean.

bobj@gli.com (Robert Jacobs) (08/06/90)

About using malloc(0) to point to a unique place. What's wrong with using
malloc(1) ??
That way malloc(0) would do what is expected. Return a NULL pointer.

This just seems too easy, doesn't it?

gwyn@smoke.BRL.MIL (Doug Gwyn) (08/07/90)

In article <1990Aug6.142050.18629@gli.com> bobj@gli.com (Robert Jacobs) writes:
>About using malloc(0) to point to a unique place. What's wrong with using
>malloc(1) ??
>That way malloc(0) would do what is expected. Return a NULL pointer.
>This just seems too easy, doesn't it?

Yes, it seems too easy because it is too easy.

The issue was that it is not clear what to "expect" malloc(0) to return.
The standard was deliberately vague on this point, because X3J11 was
fairly evenly divided on the issue, but in much better agreement that it
wasn't such an important point that it had to be nailed down in the spec.