[comp.lang.c] realloc

scs@adam.pika.mit.edu (Steve Summit) (03/29/89)

Today, for the third time in half as many years, I got badly
burned, and wasted lots of time, due to a bug in a certain
vendor's implementation of realloc.  It is an apparently well-
kept secret that realloc is supposed to behave gracefully at
a slightly special-cased boundary point: when handed a NULL
pointer and a nonzero size, it acts essentially as a malloc.

If you have ever implemented a C run-time library, or if you are
implementing one now, or if you may ever implement one, or if you
know anyone who falls into any of these categories, pay attention:
begin your realloc() implementation with the equivalent of:

	char *realloc(ptr, size)
	char *ptr;
	int size;
	{
	if(ptr == NULL)
		return malloc(size);
	...

The ptr argument and realloc's return value may be void *'s, and
the size argument may be an unsigned or a size_t; the essential
point I am making is the test for NULL and the call of malloc.

This is a short message, so that people who don't read long
articles will see it.  I'll hold further explanations and
justifications for another day.

                                            Steve Summit
                                            scs@adam.pika.mit.edu

davidl@intelob.intel.com (David Levine) (03/29/89)

In article <10170@bloom-beacon.MIT.EDU> scs@adam.pika.mit.edu (Steve Summit) writes:
>                                  ... It is an apparently well-
>  kept secret that realloc is supposed to behave gracefully at
>  a slightly special-cased boundary point: when handed a NULL
>  pointer and a nonzero size, it acts essentially as a malloc.

The System V Interface Definition (which, despite its many flaws, IS
an established standard, unlike the pANS which is still only a "draft
proposed standard") doesn't require this behavior.  The documentation
for UNIX System V, BSD 4.3, and ULTRIX doesn't mention any special
behavior for reallocing a null pointer; in fact, they all say that
attempting to realloc a pointer that was not returned by malloc,
calloc, or realloc will have unexpected results.  (Yes, malloc can
return a null pointer... I think that they meant a pointer returned by
a SUCCESSFUL call to malloc, calloc, or realloc.)

This means that you are depending on an undocumented feature.  You
shouldn't be surprised when it breaks.

The behavior you describe IS required by the pANS.  You can depend on
this behavior in any ANSI-Standard implementation, but if you expect
it of any System V, BSD, or ULTRIX implementation (and quite possibly
many others), you're expecting something that isn't promised by the
manufacturer.  This, of course, is the whole point of standards.
Unfortunately, there are as yet no ANSI-Standard implementations,
since there is no approved Standard yet.

            David D. Levine                BBBBBBBBB  IIII IIII NNN  NNNN TM
        Senior Technical Writer            BBBB  BBBB iiii iiii NNNN NNNN
                                           BBBBBBBBB  IIII IIII NNNNNNNNN
UUCP: ...[!uunet]!tektronix!biin!davidl    BBBB  BBBB IIII IIII NNNN NNNN
MX-Internet: <davidl@intelob.intel.com>    BBBBBBBBB  IIII IIII NNNN  NNN
ARPA: <@iwarp.intel.com:davidl@intelob.intel.com>

gregg@ihlpb.ATT.COM (Wonderly) (03/29/89)

From article <10170@bloom-beacon.MIT.EDU>, by scs@adam.pika.mit.edu (Steve Summit):
> Today, for the third time in half as many years, I got badly
> burned, and wasted lots of time, due to a bug in a certain
> vendor's implementation of realloc.  It is an apparently well-
> kept secret that realloc is supposed to behave gracefully at
> a slightly special-cased boundary point: when handed a NULL
> pointer and a nonzero size, it acts essentially as a malloc.

I read the man page for realloc and it said nothing about this.  Is it
not possible for you to type

	if (ptr == NULL)
		ptr = malloc (nbytes);
	else
		ptr = realloc (ptr, nbytes);

or are you one of those people that assumes (*((char *)NULL) == 0) too?
This damn lazy programming and sorry excuses for not being defensive has
got to stop.  Hiding all of the magic in the inards of the implementation
does not make it any easier for people to understand the code!  I have
never assumed that realloc() would accept a NULL pointer and if I ever
saw the type of coding that you talk about I would instantly say BUG.
Its like seeing "malloc (strlen (s));".  I know it is W-R-O-N-G!

-- 
Gregg Wonderly                             DOMAIN: gregg@ihlpb.att.com
AT&T Bell Laboratories                     UUCP:   att!ihlpb!gregg

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

In article <10170@bloom-beacon.MIT.EDU> scs@adam.pika.mit.edu (Steve Summit) writes:
>Today, for the third time in half as many years, I got badly
>burned, and wasted lots of time, due to a bug in a certain
>vendor's implementation of realloc.  It is an apparently well-
>kept secret that realloc is supposed to behave gracefully at
>a slightly special-cased boundary point: when handed a NULL
>pointer and a nonzero size, it acts essentially as a malloc.

While that's required for ANSI C standard conformance, in fact
many existing C implementations do not behave that way, and it
isn't advertised behavior even in the current UNIX release (I
don't think it even works that way).  Therefore it is unwise to
rely on this behavior in an application intended for a
not-necessarily-ANSI-conforming environment.

So why standardize this uncommon behavior?  I think the intent
was to make programming easier at some future date when nearly
all C environments will be standard conforming.

consult@osiris.UUCP (Unix Consultation Mailbox ) (03/30/89)

In article <10170@bloom-beacon.MIT.EDU> scs@adam.pika.mit.edu (Steve Summit) writes:
>It is an apparently well-
>kept secret that realloc is supposed to behave gracefully at
>a slightly special-cased boundary point: when handed a NULL
>pointer and a nonzero size, it acts essentially as a malloc.

I'll say it's well-kept, neither the 4.2BSD nor SysV.2 manpages imply
that calling realloc with first argument of 0 will do anything useful,
let alone that it's *supposed* to.  The SunOS 4.0.0 manpage even says
that "[realloc will fail if] an invalid argument was specified.  The
value of ptr passed to [realloc] must be a pointer to a block previously
allocated by malloc, calloc, realloc, valloc, or memalign."  I'm afraid
0 doesn't qualify as a pointer to a legitimately-allocated block, so
realloc *should* fail in this situation with errno == EINVAL.  That's a
far cry from "is supposed to ... [act] as a malloc."

I suggest that you be more careful in the future about which effects
of library functions are required and which are arbitrary and unreliable.
(I wish all our programmers would do that too, it would keep me from
having to do stupid things with null ptrs in my case-insensitive strcmp
and other such garbage.)


Phil Kos

jym@wheaties.ai.mit.edu (Jym Dyer) (03/30/89)

In article <10032@ihlpb.ATT.COM> gregg@ihlpb.ATT.COM (Wonderly) writes:
> From article <10170@bloom-beacon.MIT.EDU>, by scs@adam.pika.mit.edu (Steve Summit):
>> It is an apparently well-kept secret that realloc is supposed to behave
>> gracefully at a slightly special-cased boundary point: when handed a NULL
>> pointer and a nonzero size, it acts essentially as a malloc.

Actually, that's a new innovation.  A good one, though.

> Is it not possible for you to type
>
>	if (ptr == NULL)
>		ptr = malloc (nbytes);
>	else
>		ptr = realloc (ptr, nbytes);

Possible, but not desirable.  If you're going to have to use this if/else
 statement every time you use realloc(), you might as well put it into
  realloc().  And that's why ANSI-conforming realloc()s do just that.

> . . . or are you one of those people that assumes (*((char *)NULL) == 0) too?
> This damn lazy programming and sorry excuses for not being defensive has
> got to stop.

I saw no such assumption, no "damn lazy programming" and no "sorry excuses
 for not being defensive."  Steve Summit's article was, in fact, quite
  helpful.
   <_Jym_>

Tim_CDC_Roberts@cup.portal.com (03/30/89)

In <10170@bloom-beacon.MIT.EDU>, scs@adam.pika.mit.edu (Steve Summit) writes:

> It is an apparently well-
> kept secret that realloc is supposed to behave gracefully at
> a slightly special-cased boundary point: when handed a NULL
> pointer and a nonzero size, it acts essentially as a malloc.

I am unable to locate any justification for this statement.  Is this
behavior actually defined anywhere, or is it just your wish that realloc
behave this way?

Tim_CDC_Roberts@cup.portal.com                | Control Data...
...!sun!portal!cup.portal.com!tim_cdc_roberts |   ...or it will control you.

ark@alice.UUCP (Andrew Koenig) (03/30/89)

In article <10032@ihlpb.ATT.COM>, gregg@ihlpb.ATT.COM (Wonderly) writes:

> I read the man page for realloc and it said nothing about this.  Is it
> not possible for you to type
> 
> 	if (ptr == NULL)
> 		ptr = malloc (nbytes);
> 	else
> 		ptr = realloc (ptr, nbytes);
> 
> or are you one of those people that assumes (*((char *)NULL) == 0) too?
> This damn lazy programming and sorry excuses for not being defensive has
> got to stop.

Hm.  Here's what my draft ANSI C spec has to say about realloc:

	void *realloc(void *ptr, size_t size);

The realloc function changes the size of the object pointed to by
`ptr' to the size specified by `size.'  The contents of the object
shall be unchanged up to the lesser of the new and old sizes.  If
the new size is larger, the value of the newly allocated portion
of the object is indeterminate.  If `ptr' is a null pointer, the
realloc function behaves like the malloc function for the
specified size...

---------

Of course, not all C implementations behave this way.  This
leaves C programmers in a bind: rely on this behavior or not?  If
not, how does one determine which behavior can be trusted?  If
so, what does one do when one's code breaks on various machines?
-- 
				--Andrew Koenig
				  ark@europa.att.com

henry@utzoo.uucp (Henry Spencer) (03/30/89)

In article <10170@bloom-beacon.MIT.EDU> scs@adam.pika.mit.edu (Steve Summit) writes:
>... It is an apparently well-
>kept secret that realloc is supposed to behave gracefully at
>a slightly special-cased boundary point: when handed a NULL
>pointer and a nonzero size, it acts essentially as a malloc.

Unfortunately, this is (at present) not a portable assumption, because
neither V6 nor V7 Unix -- the Unixes from which essentially all others
are descended, and which included the first widely-known C compilers -- 
did this.  It was invented later.  There are probably a fair number
of old systems that haven't caught up with it.  (It *is* in ANSI C as
of the Oct. draft, so it will *eventually* be a portable assumption.)
-- 
Welcome to Mars!  Your         |     Henry Spencer at U of Toronto Zoology
passport and visa, comrade?    | uunet!attcan!utzoo!henry henry@zoo.toronto.edu

scjones@sdrc.UUCP (Larry Jones) (03/30/89)

In article <10170@bloom-beacon.MIT.EDU>, scs@adam.pika.mit.edu (Steve Summit) writes:
> Today, for the third time in half as many years, I got badly
> burned, and wasted lots of time, due to a bug in a certain
> vendor's implementation of realloc.  It is an apparently well-
> kept secret that realloc is supposed to behave gracefully at
> a slightly special-cased boundary point: when handed a NULL
> pointer and a nonzero size, it acts essentially as a malloc.

And when handed a non-NULL pointer and a zero size, it acts like
free.  This behavior is required by the draft ANSI Standard.

----
Larry Jones                         UUCP: uunet!sdrc!scjones
SDRC                                      scjones@sdrc.UU.NET
2000 Eastman Dr.                    BIX:  ltl
Milford, OH  45150                  AT&T: (513) 576-2070
"When all else fails, read the directions."

johns@calvin.EE.CORNELL.EDU (John Sahr) (03/30/89)

In article <10032@ihlpb.ATT.COM> gregg@ihlpb.ATT.COM (Wonderly) writes:
>From article <10170@bloom-beacon.MIT.EDU>, by scs@adam.pika.mit.edu (Steve Summit):
[ Mr. Summit complains that ptr = realloc(ptr,nbytes) does not behave like 
ptr = malloc(nbytes) when ptr is NULL. ]

>I read the man page for realloc and it said nothing about this...

There are two different reallocs on my system, the usual realloc(3c) and
another realloc(3x).  Neither one specifies the behaviour of realloc()
when ptr is NULL.  The man for realloc(3x) says "undocumented features
of malloc(3c) have not been duplicated." Not realloc(3c), but malloc(3c).

My realloc(3c) man does say that it will handle a pointer to a block that
was previously free(3c)'d.  

I have been working on a program recently where realloc became quite 
handy.  After a while, I realized that every place I used realloc, I was
also using malloc, a la

>Is it not possible for you to type
>
>	if (ptr == NULL)
>		ptr = malloc (nbytes);
>	else
>		ptr = realloc (ptr, nbytes);
>
>or are you one of those people that assumes (*((char *)NULL) == 0) too?

So, I tried using ptr = realloc(ptr,nbytes) without the ptr == NULL check.
It worked, at least for (3c).  But Mr. Wonderly is correct to the extent
this behaviour is not documented in the man pages, and therefore _should
not be relied upon_.

>This damn lazy programming and sorry excuses for not being defensive has
>got to stop.  Hiding all of the magic in the inards of the implementation
>does not make it any easier for people to understand the code! 

True enough, in general.  In this case, however, it seems "clear" to me 
what is going on.  If you never rely on the ptr == NULL behaviour, you 
can still write if(ptr == NULL).....else....., and it will do the same 
thing, and be "clear."  Clarity, however, is in the eye of the beholder, as 
the discussion on indentation and bracket location indicated a few months
back.

As far as the magic in the innards, it strikes me that realloc(3c)'s
function of copying the old contents into the possibly moved and different
sized block is more "magical" than behaving like malloc(3c) if ptr == NULL.
One could always call memcpy() if one wanted to be more "clear" when this
behaviour is needed.

[deletions]
>Gregg Wonderly                             DOMAIN: gregg@ihlpb.att.com
>AT&T Bell Laboratories                     UUCP:   att!ihlpb!gregg



-- 
John Sahr,                          School of Elect. Eng.,  Upson Hall   
                                    Cornell University, Ithaca, NY 14853

ARPA: johns@calvin.ee.cornell.edu; UUCP: {rochester,cmcl2}!cornell!calvin!johns

gmt@arizona.edu (Gregg Townsend) (03/31/89)

realloc() is sometimes used to grow a list of objects as entries are added. 
If it's to be used with an initially empty list, realloc() must accept a null
pointer as its frist argument -- because ANSI C allows malloc() to return NULL
in response to a request of size zero!

    Gregg Townsend / Computer Science Dept / Univ of Arizona / Tucson, AZ 85721
    +1 602 621 4325      gmt@Arizona.EDU       110 57 16 W / 32 13 45 N / +758m

bader+@andrew.cmu.edu (Miles Bader) (03/31/89)

scjones@sdrc.UUCP (Larry Jones) writes:
> And when handed a non-NULL pointer and a zero size, it acts like
> free.  This behavior is required by the draft ANSI Standard.

Does it return NULL in this case (when it acts like free)?  If so, how
extra-ordinarily convenient...

-Miles

tainter@ihlpb.ATT.COM (Tainter) (03/31/89)

In article <9118@alice.UUCP> ark@alice.UUCP (Andrew Koenig) writes:
>Hm.  Here's what my draft ANSI C spec has to say about realloc:

>	void *realloc(void *ptr, size_t size);
>  If `ptr' is a null pointer, the
>realloc function behaves like the malloc function for the
>specified size...

>Of course, not all C implementations behave this way.

This just serves to remind us all that there is ONE and ONLY ONE good
use for the __ANSI define, put the following at the top of your files:

#ifndef __ANSI

This text should not compile and will produce errors.  This should show you
uou don't want to compile this anywhere but where __ANSI is defined.

#endif

--johnathan.a.tainter--

guy@auspex.UUCP (Guy Harris) (03/31/89)

>I'll say it's well-kept, neither the 4.2BSD nor SysV.2 manpages imply
>that calling realloc with first argument of 0 will do anything useful,
>let alone that it's *supposed* to.  The SunOS 4.0.0 manpage even says
>that "[realloc will fail if] an invalid argument was specified.

Yes.  However, the December 7, 1988 dpANS says:

	4.10.3.4 The "realloc" function

	Synopsis

		#include <stdlib.h>
		void *realloc(void *ptr, size_t size);

	Description

	  ... If "ptr" is a null pointer, the "realloc" function behaves
	like the "malloc" function for the specified size.

So, while the "well-kept secret" was, indeed, a secret in earlier
systems - since *no* promise about the behavior was listed in the
documentation - it's not likely to be a secret in ANSI C, unless that bit
gets deleted before the standard is issued.

So basically:

	1) if you know you'll only be running in ANSI C environments,
	   feel free to pass NULL as the first argument to "realloc"
	   (assuming that, in that case, you expect it to do a "malloc");

	2) if you *don't* know that, make sure all the assumptions you
	   made about your environment are backed up by the
	   documentation before you port to a new environment.

djones@megatest.UUCP (Dave Jones) (03/31/89)

I guess this is all figured out now.

My $.02:

1. The first posting may have had just a hint of flame to it, but
   there was no call to heap such a raft of shit on the guy.
   I've been reading the net for over four years, and I am still sometimes
   amazed by the vitriol that purely technical discussions can elicit.
   (Grumble, mumble, snort.)

2. Just because the ANSII draft says that realloc((char*)0, size) is supposed
   to be cool does not mean it ever will be universally portable.  (I
   wonder why they did it.  Looks like asking for trouble.)   ANSII can
   only legislate what ANSII-conforming compilers do.  I expect variants
   of the old runtime libraries to be around as long as I live, (and I'm 
   trying to eat more vegetables and get some walking in, so that could
   be *years*!).

djones@megatest.UUCP (Dave Jones) (03/31/89)

From article <681@sdrc.UUCP>, by scjones@sdrc.UUCP (Larry Jones):
> 
> And when handed a non-NULL pointer and a zero size, it acts like
> free.  This behavior is required by the draft ANSI Standard.
> 


Gack.

The realloc((char*)0, size) thing was bad enough. What's this all
about?

Stuff like this just makes it hard to port ANSII programs to
old systems. Also makes it harder to convert an old system to ANSII.
I can't think of any good reason to add such a silly spec. What am I
missing?

Can anyone suggest a legitimate reason why they would want to do such
a thing?

daveb@geaclib.UUCP (David Collier-Brown) (03/31/89)

 In article <10032@ihlpb.ATT.COM>, gregg@ihlpb.ATT.COM (Wonderly) writes:
| I read the man page for realloc and it said nothing about this.  Is it
| not possible for you to type ...

From article <9118@alice.UUCP>, by ark@alice.UUCP (Andrew Koenig):
| Hm.  Here's what my draft ANSI C spec has to say about realloc:
| ...  the object is indeterminate.  If `ptr' is a null pointer, the
| realloc function behaves like the malloc function for the
| specified size...
| 

Ok, its a verbal dispute (ie, one which can  be resolved by looking
something up).  now, on to the C question:
 
| Of course, not all C implementations behave this way.  This
| leaves C programmers in a bind: rely on this behavior or not?  If
| not, how does one determine which behavior can be trusted?  If
| so, what does one do when one's code breaks on various machines?

  Firstly, one provides a compile-time test for the behavior of
realloc, and then one compiles a wrapper if necessary.    To do this,
write a function that tries to break realloc, compile it and run it
to produce a value testable by a makefile.  If the makefile finds a
"core" file, an error status or an "i failed, but survived" status,
add the following:
void *	theNameOfMyRealloc(void *ptr, size_t size) {
	return (ptr == NULL || *ptr == NULL)? malloc(size):
		realloc(ptr,size);
}
otherwise add
#define theNameOfMyRealloc(ptr,size) realloc(ptr,size)
to the compilation of the libraries.

Morven's Metatheorum:
	Any problem in computer science can be solved by using
exactly the right number of levels of indirection.  Usually adding
one more does the job.

--dave (the Morven in question is Dr. Morven Gentleman, formerly
	of the University, Waterloo) c-b
-- 
 David Collier-Brown.  | yunexus!lethe!dave
 Interleaf Canada Inc. |
 1550 Enterprise Rd.   | He's so smart he's dumb.
 Mississauga, Ontario  |       --Joyce C-B

mark@jhereg.Jhereg.MN.ORG (Mark H. Colburn) (03/31/89)

In article <DAVIDL.89Mar29091834@intelob.intel.com> davidl@intelob.intel.com (David Levine) writes:
>The System V Interface Definition (which, despite its many flaws, IS
>an established standard, unlike the pANS which is still only a "draft
>proposed standard") doesn't require this behavior. 

One of the SVID's biggest flaws is that it is NOT a standard: it was never 
balloted and approved by anyone.  It is an interface specification for a 
particular implementation of Unix.  It should be noted that there few 
companies, if any, which have SVID conforming interfaces; even AT&T doen't 
conform to their own interface specification.

The SVID is one of the base documents for some of the P1003 working groups 
because it represents one of the most comprehensive descriptions of Unix 
currently available.  The SVID along with work done by /usr/group provided 
a lot of groundwork for p1003, which IS a standard, and provided some 
impetus for X3J11 which is currently jumping through the final hoops to 
become a standard.

If the SVID were a standard, there would have been no need for P1003.
Unfortunately, there were a couple of hole in the SVID which you could
drive trucks through, hence P1003.


-- 
Mark H. Colburn                  "Look into a child's eye;
Minnetech Consulting, Inc.        there's no hate and there's no lie;
mark@jhereg.mn.org                there's no black and there's no white."

andrew@alice.UUCP (Andrew Hume) (03/31/89)

gregg townsend reminds us of the pANS ``feature'' that malloc(0) returns NULL.
can anyone provide the (or any) justification of this pointless stupid
definition? i just love the idea that an initialised pointer is SOMETIMES
indistinguishable from an uninitialised pointer.

ka@june.cs.washington.edu (Kenneth Almquist) (03/31/89)

ark@alice.UUCP (Andrew Koenig) writes (r. e. the ANSI realloc function):
> Of course, not all C implementations behave this way.  This
> leaves C programmers in a bind: rely on this behavior or not?  If
> not, how does one determine which behavior can be trusted?  If
> so, what does one do when one's code breaks on various machines?

Given that the ANSI standard hasn't even been officially released,
C programmers shouldn't rely on this behavior now.  Maybe five years
from now we will find that virtually everyone has ANSI conformant C
libraries and we can start taking advantage of the ANSI realloc routine.
Until then, it's less of a hassle to type in a few extra lines of code
rather than having your code break in mysterious ways when it is ported
to a non-ANSI system.  The ANSI realloc is different from the majority
of ANSI features, which will cause your program to fail to compile on a
non-ANSI system and can therefore be adopted more aggressively.

As for Andrew's question about what programmer's *can* rely on, the
answer is the current de facto standard, which consists of the
language as defined in the first edition of K&R plus some later
enhancements to the language.  Exactly what is included in this
de facto standard is a matter of opinion, which is one reason for
the ANSI standard.
				Kenneth Almquist

scs@adam.pika.mit.edu (Steve Summit) (03/31/89)

Several recent articles have made just about all the points
there are to make.  I will apologize for having been imperfectly
informed of realloc's history; I had not realized that so many
de-facto "standard" implementations did not provide the
additional functionality I described.

I need to respond to Gregg Wonderly, who wonders if I am

	one of those people that assumes (*((char *)NULL) == 0) too?
	This damn lazy programming and sorry excuses for not being
	defensive has got to stop.

and Phil Kos, who suggests that I

	be more careful in the future about which effects of
	library functions are required and which are arbitrary and unreliable.

and David Levine, who chastises me for

	depending on an undocumented feature.  You
	shouldn't be surprised when it breaks.

Rest assured that I am not "one of those people."

It happens that I learned about this odd behavior of realloc in
the first place when I was implementing a C run-time library, and
one of my users complained that my realloc didn't handle NULL.  A
similar exchange occurred, with the roles reversed.  (I hadn't
known about "extended" realloc at the time.)  I felt exactly the
same way -- that a programmer who needed this behavior was being
lazy -- and only changed my mind when I discovered that it was
both documented and very useful.

Unfortunately I can no longer discover which system's
documentation I actually read about it in.  It was probably 4.1x
or 4.2bsd (for x in [abc]).  I **never** depend on undocumented
behavior -- the fact that I once implemented a realloc that
handled NULL, and have since been relying on it in my code,
proves to me that I once saw it in documentation which I assumed
was definitive.  Apparently the secret was even better-kept than
I realized, since so many examples have been listed of systems
which neither provide nor document the extended behavior.

(Before you point out the folly of trusting bsd documentation,
let me point out that Berkeley used to add more features than it
documented, and that a Berkeley man page on a standard function
like realloc was likely to be copied directly from v7-based
antecedents with little change.  In fact, I thought I had
convinced myself that realloc(NULL, ...) dated back to v7, and
was therefore likely to be present in any v7-derived system, by
discovering that my pdp11 at home, which is v7-based without any
direct bsd influence, has a realloc that handles NULL.  I'll
defer to Henry Spencer's wider experience with v7, and now assume
that my machine in fact had its realloc "fixed" since v7.)

My reason for wanting a realloc that handles NULL is precisely
because of the clean, self-starting, idempotent algorithms it
permits.  Two good examples are a string function which handles
arbitrary-length arguments:

	char *strupper(str)		/* returns ptr to static data */
	char *str;			/* overwritten with each call */
	{
	static char *retbuf = NULL;
	static int retsize = 0;
	int len = strlen(str) + 1;

	if(len > retsize)
		{
		char *new = realloc(retbuf, len);
		if(new == NULL)
			return NULL;	/* error handling problematical */
		retbuf = new;
		retsize = len;
		}

	...now copy str to retbuf, uppercasifying...

	return retbuf;
	}

or a function which stashes its argument in a data structure for
later use:

	graph_title(gd, title)
	struct graph *gd;		/* graph descriptor */
	char *title;
	{
	char *new = realloc(gd->g_title, strlen(title) + 1);
	if(new == NULL)
		return NULL;
	(void)strcpy(new, title);
	gd->g_title = new;
	}

Assuming realloc handles a NULL pointer argument, neither of
these subroutines requires any special-casing for the first call.
graph_title is nicely idempotent; it can be called multiple times
without ill effect.  (It assumes that the routine that allocated
graph descriptors initialized g_title to NULL.)

Certainly, if realloc were not guaranteed to handle NULL
pointers, I would provide a "wrapper" function around it which
did.  (Most of the time, I use a wrapper function anyway, to
centralize the error check.)  I'd rather not duplicate standard
functionality, though.  However, as has now been amply pointed
out, a realloc that handles NULL is anything but standard in the
pre-ANSI C world, and I am already adjusting my coding practices
to reflect this.  (I do like portable code; I'd rather not depend
on ANSI yet.)

Finally, to assuage a few people's doubts that "well, I can see
how realloc(NULL, ...) might be useful, but having realloc(..., 0)
return NULL is GROSS," I'll point out that, for full
consistency and generality, both cases are equally necessary.
Suppose you have a pair of variables

	char *p = NULL;
	int size = 0;

defining a buffer which grows as necessary (using realloc, of
course, as in the first example above).  If the buffer can also
grow smaller, it seems sensible to make it return to its starting
condition if the size ever reaches 0, to free all memory and
reset p to NULL.  If the size grows again, p will be correctly
reallocated to a "real" pointer again, anyway.  (Although hardly
an overriding concern, note that if malloc(0) or realloc(..., 0)
returns a non-NULL pointer, it will typically have some malloc
arena overhead behind it, consuming space, even though zero bytes
are available to the caller.)

                                            Steve Summit
                                            scs@adam.pika.mit.edu

guy@auspex.auspex.com (Guy Harris) (03/31/89)

 >Unfortunately, this is (at present) not a portable assumption, because
 >neither V6 nor V7 Unix -- the Unixes from which essentially all others
 >are descended, and which included the first widely-known C compilers -- 
 >did this.  It was invented later.  There are probably a fair number
 >of old systems that haven't caught up with it.

In fact, I checked the S5R3 "malloc"s - both the one in "libc", which
is, as I remember, little changed from the V7 one, and the one in
"-lmalloc" - and they most definitely do not make the check for NULL, so
there are probably a fair number of *new* systems that haven't caught up
with it.

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

In article <3229@goofy.megatest.UUCP> djones@megatest.UUCP (Dave Jones) writes:
>Can anyone suggest a legitimate reason why they would want to do such
>a thing?

I already did that.

bright@Data-IO.COM (Walter Bright) (04/01/89)

In article <9118@alice.UUCP< ark@alice.UUCP (Andrew Koenig) writes:
<In article <10032@ihlpb.ATT.COM<, gregg@ihlpb.ATT.COM (Wonderly) writes:
<< I read the man page for realloc and it said nothing about this.  Is it
<< not possible for you to type
<< 	if (ptr == NULL)
<< 		ptr = malloc (nbytes);
<< 	else
<< 		ptr = realloc (ptr, nbytes);
<Hm.  Here's what my draft ANSI C spec has to say about realloc:
<	[stuff deleted]
<Of course, not all C implementations behave this way.  This
<leaves C programmers in a bind: rely on this behavior or not?  If
<not, how does one determine which behavior can be trusted?  If
<so, what does one do when one's code breaks on various machines?

I am involved daily with porting code between PCs, Suns, Apples, Vaxes,
etc. The quality of C compilers varies widely, as does the conformance
to ANSI C. What I have done is create a file called 'missing.c' in
which I write functional equivalents of ANSI C library functions. They
are #ifdef'd in for those primitive compilers that don't have them.
For instance, BSD Unix doesn't have memcpy, so I have:

#if BSDUNIX || VAX11C
char *memcpy(t,f,n)
#if BSDUNIX
char *t,*f;
int n;
{
	bcopy(f,t,n);
	return t;
}
#else
register char *t,*f;
register int n;
{
	char *retval = t;

	while (n--) *t++ = *f++;
	return retval;
}
#endif
#endif

(VAX11C is my euphamism for DEC's C compiler.)

I have dealt with the primitive realloc's by always using a function
mem_realloc, and defining it as:

#if __STDC__
#define mem_realloc realloc
#else
void *mem_realloc(oldmem_ptr,newnumbytes)
void *oldmem_ptr;
unsigned newnumbytes;
{   extern void *realloc(),*malloc();
    void *p;

    if (oldptr == NULL)
	p = newnumbytes ? malloc(newnumbytes) : NULL;
    else if (newnumbytes == 0)
    {	free(oldptr);
	p = NULL;
    }
    else
	p = realloc(oldptr,newnumbytes);
    /*printf("realloc(x%lx,%d) = x%lx\n",oldptr,newnumbytes,p);*/
    return p;
}
#endif

If I'm using a compiler which has a broken realloc(), (which is common!)
I can reimplement my mem_realloc as using a malloc/memcpy/free combination.

Using this approach I can use ANSI library function semantics and still
work with archaic compilers. The application code doesn't have to be
littered with crutches for this stuff, it's isolated away.

hascall@atanasoff.cs.iastate.edu (John Hascall) (04/01/89)

In article <9122@alice.UUCP> andrew@alice.UUCP (Andrew Hume) writes:


>gregg townsend reminds us of the pANS ``feature'' that malloc(0) returns NULL.
>can anyone provide the (or any) justification of this pointless stupid
>definition? i just love the idea that an initialised pointer is SOMETIMES
>indistinguishable from an uninitialised pointer.

     And what would you have it return?   An Address?  ...which points to
     zero bytes of allocated storage?  And would successive malloc(0)
     calls return the same pointer? (you're not using any heap with each
     call)  And then consider doing a "free" on such a pointer.

     Just think of malloc(NULL) as not initialising the pointer,
     just as malloc(MORE_BYTES_THAN_WE_GOT) doesn't.

John Hascall

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

In article <9122@alice.UUCP> andrew@alice.UUCP (Andrew Hume) writes:
>gregg townsend reminds us of the pANS ``feature'' that malloc(0) returns NULL.
>can anyone provide the (or any) justification of this pointless stupid
>definition?

Sure.  malloc() either fails or it succeeds.  If it were required to
succeed for a 0-sized allocation attempt, then additional semantics
would have had to have been devised to deal with the 0-sized object
pointed to by the returned non-null pointer.  For example, should
a series of malloc(0) calls return distinct pointers?  Anyway, for
the limited additional functionality this was considered too big a
can of worms to open.

Happens I'm the POC for 0-sized object extensions to C.  There has
so far been a distinct lack of interest in this area..

scjones@sdrc.UUCP (Larry Jones) (04/01/89)

In article <cYAd3My00UkaI1vvZr@andrew.cmu.edu>, bader+@andrew.cmu.edu (Miles Bader) writes:
> scjones@sdrc.UUCP (Larry Jones) writes:
> > And when handed a non-NULL pointer and a zero size, it acts like
> > free.  This behavior is required by the draft ANSI Standard.
> 
> Does it return NULL in this case (when it acts like free)?  If so, how
> extra-ordinarily convenient...

It's implementation defined -- the implementation is allowed to
return either a NULL pointer or a pointer to a zero-sized object
(although many people find that concept quite repugnant, that's
the way many existing implementations behave).

----
Larry Jones                         UUCP: uunet!sdrc!scjones
SDRC                                      scjones@sdrc.UU.NET
2000 Eastman Dr.                    BIX:  ltl
Milford, OH  45150                  AT&T: (513) 576-2070
"When all else fails, read the directions."

scjones@sdrc.UUCP (Larry Jones) (04/01/89)

In article <3229@goofy.megatest.UUCP>, djones@megatest.UUCP (Dave Jones) writes:
> Gack.
> 
> The realloc((char*)0, size) thing was bad enough. What's this all
> about? [realloc(ptr, (size_t)0) === free(ptr)]
> 
> Stuff like this just makes it hard to port ANSII programs to
> old systems. Also makes it harder to convert an old system to ANSII.
> I can't think of any good reason to add such a silly spec. What am I
> missing?
> 
> Can anyone suggest a legitimate reason why they would want to do such
> a thing?

The idea is to avoid applications having to special case zero.
Thus, it should be possible to malloc for a size of zero, realloc
to or from a size of zero, and free something with a size of
zero.  Since C does not allow one to declare zero-size objects,
there was some objection to requiring implementations to allow
for dynamically created zero-size objects -- thus the compromise
of allowing pointers to zero-size objects to either be unique
pointers like all other object pointers, or all NULL at the
implementation's discretion.

Ease of porting to non-complying systems is NOT one of the goals
of the standard; ease of porting to COMPLYING systems IS.  Most
existing implementations I know of already meet this spec -- they
either return unique pointers for zero-size objects or consider
it an error and return NULL.  Since existing systems work both
ways, portable programs can't depend on a specific behavior and
so will work just fine with an ANSI implementation.

----
Larry Jones                         UUCP: uunet!sdrc!scjones
SDRC                                      scjones@sdrc.UU.NET
2000 Eastman Dr.                    BIX:  ltl
Milford, OH  45150                  AT&T: (513) 576-2070
"When all else fails, read the directions."

antoine@alberta.UUCP (Antoine Verheijen) (04/01/89)

In article <9122@alice.UUCP> andrew@alice.UUCP (Andrew Hume) writes:
>
>
>gregg townsend reminds us of the pANS ``feature'' that malloc(0) returns NULL.
>can anyone provide the (or any) justification of this pointless stupid
>definition? i just love the idea that an initialised pointer is SOMETIMES
>indistinguishable from an uninitialised pointer.


Please note that a NULL pointer is not (necessarily) the same thing as an
uninitialized pointer. NULL is a very specific and legitimate value for
a pointer whereas an uninitialized pointer is, by definition, unpredictable,
its value usually being dependent on the system you're running under (unless
I've missed something new in the standard).

djones@megatest.UUCP (Dave Jones) (04/01/89)

From article <9962@smoke.BRL.MIL>, by gwyn@smoke.BRL.MIL (Doug Gwyn ):
> In article <3229@goofy.megatest.UUCP> djones@megatest.UUCP (Dave Jones) writes:
>>Can anyone suggest a legitimate reason why they would want to do such
>>a thing?
> 
> I already did that.


Well excuuuusee ME!

The posting which I assume you refer to arived days after I posted
the above question.  In fact, somehow it got here *after* the 
"I already did that" posting (but in the same batch).

Might I suggest to everyone:

  1) if you are quoting are article, please include enough context 
  so that the reader can figure out what the quote
  is about -- (btw, I quoted the *entire* response above!) -- and

  2) if you refer to another article, or to a manual, or
  to a book or whatever, please identify it as best you can.

Thenkyewverymuch.

Now then.

This discussion is about the proposed ANSI behavior of malloc(0): namely
returning (char*)0.

I just now read the article alluded to above.

No sale.

Unless there are existing systems that behave in the proposed way -- 
(are there?) -- the new spec just breaks programs for no reason,
and perhaps too quietly.

I mean, if you really want a standard procedure that returns
(char*)0 when told to return a pointer to zero bytes, just define a
new one for Pete's sake!  Call it zzalloc, or something.

Looks to me like the only reasonable choices are

	1. Document the behavior as unpredictable; and
  
	2. Have malloc(0) return a pointer distinct from 0 and from all
	   other mallocked pointers, or else return 0 and set errno
	   if there is not enough memory available for the heap-overhead
	   of an empty packet. ("The set containing only the empty set 
	   is not empty," a famous Math professor used to be fond
           of reminding people.)


Given an xor, I prefer number 1, but I really would like to have
both!  That way, old programs will probably work, but I'll be warned
to check them over, and that they may not be portable.

Why is 1 better than the proposal?  Because otherwise somebody reading
the standard might be lulled into thinking that he is writing a portable
program when he's not. It is the ANSI-STANDARD, after all (ta-ta!).

Sidebar:

  I recall once, many many moons ago, writing a LISP-system in C.
  I was "young and easy, about the lilting house and happy as the grass
  was green", one might say, and I thought it was cool to allocate
  pointers to no bytes to represent t and nil. Made checking an S-
  expression for t-ness and nil-ness real quick...  and why allocate
  bytes when you're not going to use them, eh?  Okay, now maybe I know
  better,  but so what?

guy@auspex.auspex.com (Guy Harris) (04/01/89)

>Unfortunately I can no longer discover which system's
>documentation I actually read about it in.  It was probably 4.1x
>or 4.2bsd (for x in [abc]).

It sure ain't 4.3-tahoe, so I tend to doubt it was 4.1x or 4.2, either.
Maybe some local person had discovered the behavior by e.g. scanning the
source, and updated your documentation?

>Apparently the secret was even better-kept than I realized, since so
>many examples have been listed of systems which neither provide nor
>document the extended behavior.

If, say, the folks at AT&T had never even *seen* the BSD code, it's not
hard to imagine why this was a secret to them, since the BSD
documentation probably didn't mention it.  Even if some implementer
*had* seen it, given that it's an undocumented feature I don't have any
particular problem with them saying "so what" and not implementing it in
their systems - especially since people writing programs would be
ill-advised to depend on a feature not generally documented. 

Now that it's in the dpANS, and will probably be in the ANS, it's
effectively a documented feature, at least to the extent that
implementers should start thinking of providing it.  That's one
advantage of standards: they make it clearer what you can depend on and
can't depend on in a particular environment (or, at least, what things
vendors have no reason not to provide, and what things there's no *de
jure* reason for them to provide - there are, of course, few ironclad
guarantees that some C implementation actually meets the spec, short of
a report saying it passes some test suite, and even then the test suite
could miss something).

ka@june.cs.washington.edu (Kenneth Almquist) (04/01/89)

hascall@atanasoff.cs.iastate.edu (John Hascall) writes:
>     And what would you have malloc(0) return?   An Address?
What else?

>    ...which points to zero bytes of allocated storage?
At least zero bytes.

>    And would successive malloc(0) calls return the same pointer?
No.

>    (you're not using any heap with each call)
Yes you are, because malloc has to record the size of the allocated
block somewhere.

>    And then consider doing a "free" on such a pointer.
Makes as much sense as freeing any other pointer.

That's what existing UNIX malloc implementations do, and as I understand
it there is nothing in the ANSI C standard that prohibits this behavior.


In article <3810@geaclib.UUCP>, David suggests writing a program that
tests whether the realloc implementation is ANSI compliant, and using
it to conditionally compile a wrapper routine around realloc.  There is
no guarantee that the test program will work ("Testing can never show
the absense of bugs, only their presense."), although it should be
possible to write a wrapper routine that will work well enough in
practice.  Personally, I wouldn't bother; it seems simpler to just use
the wrapper routine all the time.
				Kenneth Almquist

andrew@alice.UUCP (Andrew Hume) (04/02/89)

	my request for an explanation of why anyone (especially pANS)
would give as silly an answer as 0 for malloc(0) generated a few useful
replies (thanks guy, brad, gwyn and kenneth) but a lot of
people were confused by my misstatement at the end. so let me rephrase:

	malloc(n) returning 0 is, to me, an error condition. that is,
i should pack up and go home. (of course i check malloc's return value).
But now, thanks to pANS, i first have to check if n==0. this is a pain
in the butt.

	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;
hascall derisively says ``And what would you have malloc(0) return?
An Address?''. paraphrasing kenneth's reply, ``gosh, yes, i would return an
address!''.
	lets get this straight; malloc has never said (at least until VERY recently)
that it returns a pointer to n bytes of storage. it has always said at least
n bytes of storage and the reason is clear if you look how most malloc's
are implemented; they almost always allocate an integral number of
machine words, rounding the actual request up. given that, what is
all the whining about? can't malloc(0) return a pointer to 1 (or 2 or 4)
bytes? of course, everyone would be happy now, wouldn't they?
and, innovative as it may be, 0 could revert to meaning 'I ran out of storage'
and we could even get rid of the peculiar special cases of giving
zero pointers to realloc. call me old-fashioned but 0 means
no pointer, end of list, you can stop here. don't let it become a
legitimate return value; just say no.

(and if anyone accuses me of flaming, let me say i didn't
actually say the decision was batshit).

bill@twwells.uucp (T. William Wells) (04/03/89)

In article <9964@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn (VLD/VMB) <gwyn>) writes:
: Happens I'm the POC for 0-sized object extensions to C.  There has
: so far been a distinct lack of interest in this area..

Somehow I missed that. How would one have discovered it?  When I
submitted my comments on the standard, I did ask that there be zero
sized arrays at the end of structures; I got a NAK.

Could you clue me in on what existing proposals there are on zero
sized objects? Few may be interested, but I am.

---
Bill                            { uunet | novavax } !twwells!bill
(BTW, I'm may be looking for a new job sometime in the next few
months.  If you know of a good one where I can be based in South
Florida do send me e-mail.)

gregg@ihlpb.ATT.COM (Wonderly) (04/03/89)

From article <9964@smoke.BRL.MIL>, by gwyn@smoke.BRL.MIL (Doug Gwyn ):
> In article <9122@alice.UUCP> andrew@alice.UUCP (Andrew Hume) writes:
>>gregg townsend reminds us of the pANS ``feature'' that malloc(0) returns NULL.
>>can anyone provide the (or any) justification of this pointless stupid
>>definition?
> 
> Sure.  malloc() either fails or it succeeds.  If it were required to
> succeed for a 0-sized allocation attempt, then additional semantics
> would have had to have been devised to deal with the 0-sized object
> pointed to by the returned non-null pointer.  For example, should
> a series of malloc(0) calls return distinct pointers?  Anyway, for
> the limited additional functionality this was considered too big a
> can of worms to open.

The use of malloc (0) may exist.  But I have always, and will always continue
to use

	if (nbytes == 0)
		nbytes = 1;

	if (ptr == NULL)
		ptr = (some cast) malloc (nbytes);
	else
		ptr = (some cast) realloc (ptr, nbytes);

When the sequence occurs a lot, I put it into a function.  For crissake,
this is not a "gee look at the benefits this feature provides" issue!  It
is a "gee look at how so many more portability issues are going to pop up"
issue!  And a stupid one at that!

Allocating a small amount of data to point a pointer into so that it is
non-null is going to save a large amount of code space and special case
code all through programs that deal with dynamic objects.

Changing one of the basic library routine interfaces is always a bad
idea, and it always will be!

-- 
Gregg Wonderly                             DOMAIN: gregg@ihlpb.att.com
AT&T Bell Laboratories                     UUCP:   att!ihlpb!gregg

oisin@cmtl01.UUCP (Oisin) (04/03/89)

in Article 131 of comp.std.c: gregg@ihlpb.ATT.COM (Wonderly)  says:
>From article <10170@bloom-beacon.MIT.EDU>, by scs@adam.pika.mit.edu (Steve Summit):
[ anecdote deleted ]
>> kept secret that realloc is supposed to behave gracefully at
>> a slightly special-cased boundary point: when handed a NULL
>> pointer and a nonzero size, it acts essentially as a malloc.
>
>I read the man page for realloc and it said nothing about this.  Is it
>not possible for you to type
>
>	if (ptr == NULL)
>		ptr = malloc (nbytes);
>	else
>		ptr = realloc (ptr, nbytes);
>
>or are you one of those people that assumes (*((char *)NULL) == 0) too?
[ more flame deleted ]

Pardon my ignorance, but if I'm wrong you can flame me too...
Does the draft not specify that whatever implementation of NULL is used, 
the compiler must guarantee that a ptr containing that implementation's
version of NULL must test as false?  (Notice I did not say it had to
BE false, just that the compiler must evaluate a logical test on it
as being false).  I'm don't write compilers or anything like that..
I'm just a "dumb end user" of C, but if my understanding is wrong, then
I and a lot of other programmers will have to "mend our ways".  I
stopped wasting my employers time with the redundant "== NULL" when
I read about that guarantee being in the standard.  Please correct
me if I am "bugging" my programs.

........................................................................
Oisin "Curly" Curtin -- uucp:uunet!attcan!cmtl01!oisin
Disclaimer- Opinions are my own.  CNR, AT&T and my wife don't want them.
........................................................................
Money is the root of all evil, and man needs roots

chris@mimsy.UUCP (Chris Torek) (04/03/89)

[flaming about realloc((char *)NULL) deleted]

In article <1196@cmtl01.UUCP> oisin@cmtl01.UUCP (Oisin) writes:
>Pardon my ignorance, but if I'm wrong you can flame me too...
>Does the draft not specify that whatever implementation of NULL is used, 
>the compiler must guarantee that a ptr containing that implementation's
>version of NULL must test as false?

Yes.  In standard-ese, a null pointer of any type must compare equal
to the integer constant zero and to the nil-pointer-to-void ((void *)0).
This has nothing to do with the flaming about

	realloc((char *)NULL, sz),  where sz > 0

nor that about

	malloc((size_t)0)
and	realloc(ptr, (size_t)0)

(The `correct' set of definitions---which is not the same as the pANS
set, but is fairly close; I can deal with the pANS version---appears
to me to be:

	malloc(sz) should return a unique pointer to at least sz bytes,
	or the value (void *)NULL if space is not available

	free((char *)NULL) should be a no-op, not an error

	realloc(ptr, sz) should `act like' free(ptr)+malloc(sz)+copy(old
	data, new location).  In particular, realloc(NULL) should act
	like malloc, and realloc(?, 0) should return a unique pointer to
	at least zero bytes.

This could be done in an ANSI-conformant environment with a small set
of wrapper functions.  Note that, with these definitions, malloc()
becomes unnecessary; it need not appear as a wrapper function.)
-- 
In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
Domain:	chris@mimsy.umd.edu	Path:	uunet!mimsy!chris

crossgl@ingr.com (Gordon Cross) (04/03/89)

In article <3229@goofy.megatest.UUCP> djones@megatest.UUCP (Dave Jones) writes:
>
>The realloc((char*)0, size) thing was bad enough. What's this all
>about?
>Can anyone suggest a legitimate reason why they would want to do such
>a thing?

Yes!!  Imagine a situation wherein you are dynamically adjusting your memory
requirements (both up and down) to hold data which may grow and shrink in
its storage requirements.  This behavior eliminates special handling of the
boundary case when the size periodically goes to zero!!  I've desired this
behavior many times and I solved it with:

char *myrealloc (ptr, size)

char     *ptr;
unsigned  size;
{
  if (!ptr)
    return malloc (size);
  if (!size) {
    free (ptr);
    return 0;
  }
  return realloc (ptr, size);
}

I am VERY pleased that ANSI choose to require this behavior...
-- 

Gordon Cross             UUCP:      uunet!ingr!crossgl     "all opinions are
111 Westminister Way     INTERNET:  crossgl@ingr.com        mine and not those
Madison, AL 35758        MA BELL:   (205) 772-7842          of my employer."

crossgl@ingr.com (Gordon Cross) (04/03/89)

In article <9122@alice.UUCP> andrew@alice.UUCP (Andrew Hume) writes:
}
}gregg townsend reminds us of the pANS ``feature'' that malloc(0) returns NULL.
}can anyone provide the (or any) justification of this pointless stupid
}definition?

Yes, a pointer to something of zero size takes up NO space!!!  You would be
able to increase this size later with the (ANSI) realloc...  (ain't life great)

-- 

Gordon Cross             UUCP:      uunet!ingr!crossgl     "all opinions are
111 Westminister Way     INTERNET:  crossgl@ingr.com        mine and not those
Madison, AL 35758        MA BELL:   (205) 772-7842          of my employer."

crossgl@ingr.com (Gordon Cross) (04/03/89)

In article <9132@alice.UUCP> andrew@alice.UUCP (Andrew Hume) writes:
>
>	malloc(n) returning 0 is, to me, an error condition. that is,
>i should pack up and go home. (of course i check malloc's return value).
>But now, thanks to pANS, i first have to check if n==0. this is a pain
>in the butt.

Yes, it is.  I've always wanted behavior similiar to an "out-of-memory"
signal that I could trap to let me know when there is no more memory.  So
much so in fact, I wrote my own malloc that lets me set things up to have
a function called whenever an out-of-memory condition occurs.  Regrettably
to the best of my knowlegde, the pANS does not address this issue...
-- 

Gordon Cross             UUCP:      uunet!ingr!crossgl     "all opinions are
111 Westminister Way     INTERNET:  crossgl@ingr.com        mine and not those
Madison, AL 35758        MA BELL:   (205) 772-7842          of my employer."

peter@ficc.uu.net (Peter da Silva) (04/03/89)

  [ malloc(0) -> NULL is a bug]
In article <934@atanasoff.cs.iastate.edu>, hascall@atanasoff.cs.iastate.edu (John Hascall) writes:
> And what would you have it return?   An Address?

Yes.

> ...which points to zero bytes of allocated storage?

Yes.

> And would successive malloc(0) calls return the same pointer?

No.

> (you're not using any heap with each call)

Yes you are. 4-8 bytes depending on memory model.

> And then consider doing a "free" on such a pointer.

Sure.

malloc(NULL) -> NULL is an optimisation better performed by the programmer.
-- 
Peter da Silva, Xenix Support, Ferranti International Controls Corporation.

Business: uunet.uu.net!ficc!peter, peter@ficc.uu.net, +1 713 274 5180.
Personal: ...!texbell!sugar!peter, peter@sugar.hackercorp.com.

guy@auspex.auspex.com (Guy Harris) (04/04/89)

>>I read the man page for realloc and it said nothing about this.  Is it
>>not possible for you to type
>>
>>	if (ptr == NULL)
>>		ptr = malloc (nbytes);
>>	else
>>		ptr = realloc (ptr, nbytes);
>>
>>or are you one of those people that assumes (*((char *)NULL) == 0) too?
>[ more flame deleted ]
>
>Pardon my ignorance, but if I'm wrong you can flame me too...
>Does the draft not specify that whatever implementation of NULL is used, 
>the compiler must guarantee that a ptr containing that implementation's
>version of NULL must test as false?

Huh?  What does that have to do with any of this?  The draft does
specify that

	if (x)

is equivalent to

	if (x != 0)

and that, at least for "x" of pointer type, that is in turn equivalent
to

	if (x != NULL)

but in no way does the draft require that

	*((char *)NULL) == 0

and a damn good thing that is - some implementations cause programs that
illegally attempt to dereference the null pointer to blow up, so that
bugs of that sort are caught....

If *you* want to write

	if (p)

rather than

	if (p != NULL)

go ahead; both are equally legal C, and while the "!= NULL" may be
redundant in some sense, at least some of us find that

	if (p != NULL)

easier to read than

	if (p)

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

In article <3240@goofy.megatest.UUCP> djones@megatest.UUCP (Dave Jones) writes:
>Why is 1 better than the proposal?  Because otherwise somebody reading
>the standard might be lulled into thinking that he is writing a portable
>program when he's not. It is the ANSI-STANDARD, after all (ta-ta!).

I think that would indicate confusion about the use of the C standard
that needs to be straightened out anyway.  The (p)ANS is not intended
to document a "lowest common denominator" of existing C implementations.
It IS intended to document an interface that can be relied on for any
implementation that is advertised as ANSI C standard conforming.  How
to cope with non-standard implementations is a proper topic for courses
in C programming, but it's not directly the business of the standard.

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

In article <812@twwells.uucp> bill@twwells.UUCP (T. William Wells) writes:
>Could you clue me in on what existing proposals there are on zero
>sized objects? Few may be interested, but I am.

There aren't any at this point.  It was agreed to keep them out of the
pANS.  Also I think there was agreement that any such proposal would
have to include as thorough a review of the standard for potential
impact as I did when I proposed "short char".  The 0-sized object SIG,
if it's going to do anything at all, will have to determine how such a
proposal would fit into a future revised standard and come up with
some experimental implementations and applications that use the feature
in order to be able to justify adding it at some future date.  I haven't
seen enough genuine interest to justify all that work.

djones@megatest.UUCP (Dave Jones) (04/04/89)

From article <9132@alice.UUCP>, by andrew@alice.UUCP (Andrew Hume):
> what is
> all the whining about? can't malloc(0) return a pointer to 1 (or 2 or 4)
> bytes? of course, everyone would be happy now, wouldn't they?

Hear! Hear!

Indeed, most implementations could actually return a valid pointer to
ZERO bytes, if they wanted to!

Yep.  Typically a pointer to a heap-packet is the machine-address of the
memory just after a heap-packet HEADER, which the heap routines use
to keep books.  Since no two heap-packets have the same headers, no
two heap-packets have the same heap-packet pointer.  This remains
true even if no memory beyond the header is actually reserved.

In practice, a heap-packet-pointer-to-nothing would typically
be the machine address of another heap-packet-header.  We dare not 
dereference it, but so what?  It is always an error to use a
heap-packet-pointer to index as much as heap-packet-size bytes into the 
heap-packet. (Doing so usually gets you into another heap-packet-header,
or another heap-packet, and can keep you awake debugging all night
and most of the next day, so don't DO that!)

Ego, with a pointer to zero bytes, it is an error to index even zero-bytes
beyond it.  That is to say, the pointer-to-nothing is good only for
comparing for equality with similarly typed pointers.

No problem.

Maybe on a Prevert-2000, that keeps different kinds of pointers in
different shapes of mayonaise jars, you would have to allocate a byte
or four of memory.  Okay. Fine.

Ain' no deal, Home!

frank@zen.co.uk (Frank Wales) (04/04/89)

In article <1196@cmtl01.UUCP> oisin@cmtl01.UUCP (Oisin) writes:
>in Article 131 of comp.std.c: gregg@ihlpb.ATT.COM (Wonderly)  says:
>>or are you one of those people that assumes (*((char *)NULL) == 0) too?
>
>Pardon my ignorance, but if I'm wrong you can flame me too...
>Does the draft not specify that whatever implementation of NULL is used, 
>the compiler must guarantee that a ptr containing that implementation's
>version of NULL must test as false?

[just a singe] Gregg was actually bemoaning the extremely fragile assumption
that dereferencing a NULL pointer yields 0, probably the commonest single
pain in the arse to those who would port other people's programs.
--
Frank Wales, Systems Manager,        [frank@zen.co.uk<->mcvax!zen.co.uk!frank]
Zengrange Ltd., Greenfield Rd., Leeds, ENGLAND, LS9 8DB. (+44) 532 489048 x217 

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

In article <3255@goofy.megatest.UUCP> djones@megatest.UUCP (Dave Jones) writes:
>... with a pointer to zero bytes, ...
>No problem.

You haven't thought out all the ramifications of officially permitting
0-sized objects in C.  That's not to say that the problems are insoluble,
but they are there and must be dealt with if you're going that direction.

daw@cbnewsh.att.com (David Wolverton) (01/26/91)

In article <22311:Jan2502:34:1191@kramden.acf.nyu.edu>, brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes:
> [ lots deleted ]
> Now you can talk all you want about reallocating memory (btw, there's no
                                                                ^^^^^^^^^^
> safe way to use realloc(), but you knew that) ...
  ^^^^^^^^^^^^^^^^^^^^^^^^^

OK, I'll bite.  I didn't know that.  So, what is the problem
with realloc()?

Dave Wolverton
daw@attunix.att.com

kaleb@thyme.jpl.nasa.gov (Kaleb Keithley) (01/26/91)

In article <22311:Jan2502:34:1191@kramden.acf.nyu.edu>, brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes:
> [ lots deleted ]
> Now you can talk all you want about reallocating memory (btw, there's no
                                                                ^^^^^^^^^^
> safe way to use realloc(), but you knew that) ...
  ^^^^^^^^^^^^^^^^^^^^^^^^^

You better tell OSF, MIT, and hundreds, if not thousands, of software
developers, because I know for a fact that products like X Window and
Motif make frequent use of realloc().

-- 
Kaleb Keithley                        kaleb@thyme.jpl.nasa.gov

As of right now, I'm in charge here now...                  Alexander Haig.
Voodoo Economics, that's what it is, voodoo economics.      George Bush

pas@unhd.unh.edu (Paul A. Sand) (01/30/91)

In article <23975:Jan2516:36:5891@kramden.acf.nyu.edu> brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes:
>Some versions of realloc() return the original pointer rather than 0 if
>they run out of memory. So you have to code the malloc()/bcopy()/free()
>sequence yourself if you want error checking.

Other posters have pointed out that such realloc()'s are seriously
broken, but I wonder how many versions "some versions" actually are.  A
brief check of my portability references (Jaeschke's _Portability and
the C Language_, Rabinowitz's and Schaap's _Portable C_, 1st and 3rd
editions of Harbison & Steele) doesn't turn up any warnings about such
behavior. (And these folks seem to warn about *very* unlikely things.)

But as long as I'm reading, I did notice a howler in Jaeschke's text,
on page 320:

	You should ALWAYS use realloc as follows:

	ptr = realloc(ptr, new_size);

Emphasis is Jaeschke's. Even a tyro like me can recognize that you
are in big trouble if (a) the realloc() fails, (b) ptr is your only
access to the block, and (c) you had something important there.
-- 
-- Paul A. Sand                |
-- University of New Hampshire | I ain't here on business, baby.
-- uunet!unhd!pas              | I'm only here for fun.
-- pas@unhd.unh.edu            |

jik@athena.mit.edu (Jonathan I. Kamens) (01/31/91)

In article <1991Jan30.121425.16882@unhd.unh.edu>, pas@unhd.unh.edu (Paul A. Sand) writes:
|> Emphasis is Jaeschke's. Even a tyro like me can recognize that you
|> are in big trouble if (a) the realloc() fails, (b) ptr is your only
|> access to the block, and (c) you had something important there.

  I believe that if the realloc() fails, the memory block pointed to by the
pointer passed into realloc() is no longer guaranteed to be valid.  Therefore,
Jaeschke is right -- after realloc() returns NULL, you should not try to use
the block whose address you passed into realloc().


-- 
Jonathan Kamens			              USnail:
MIT Project Athena				11 Ashford Terrace
jik@Athena.MIT.EDU				Allston, MA  02134
Office: 617-253-8085			      Home: 617-782-0710

mcdonald@aries.scs.uiuc.edu (Doug McDonald) (01/31/91)

In article <1991Jan30.193308.3897@athena.mit.edu> jik@athena.mit.edu (Jonathan I. Kamens) writes:
>
>  I believe that if the realloc() fails, the memory block pointed to by the
>pointer passed into realloc() is no longer guaranteed to be valid.  Therefore,
>Jaeschke is right -- after realloc() returns NULL, you should not try to use
>the block whose address you passed into realloc().
>

"
void *realloc(void *p, size_t size);

realloc changes the size of the object pointed to by p to size. The
contents will be unchanged up to the minimum of the old and new sizes.
If the new size is larger the new space is uninitialized. Realloc returns
a pointer to the new space, or NULL if the request cannot be satisfied,
in which case *p is unchanged."

The "" indicate a quote from K&R II. Note the last sentence: it says that
*p is unchanged. *p is the CONTENTS of what p originally (and presumably still 
must) point to.


So the quote preceeded by > signs is not true for a correct realloc.
You CAN reuse p and *p after a failed realloc.


Doug McDonald

jik@athena.mit.edu (Jonathan I. Kamens) (01/31/91)

In article <1991Jan30.201955.21797@ux1.cso.uiuc.edu>, mcdonald@aries.scs.uiuc.edu (Doug McDonald) writes:
|> So the quote preceeded by > signs is not true for a correct realloc.
|> You CAN reuse p and *p after a failed realloc.

  We're not talking about "a correct realloc."  Remember that the book in
question is //Portability and the C Language//.  If you want to assume that
because ANSI C specifies realloc() as you quoted, all implementation of
realloc() you come across specify it in that way, that's your right, but I
doubt such an assumption is portable, which is why Jaeschke gave the
restriction he did.

-- 
Jonathan Kamens			              USnail:
MIT Project Athena				11 Ashford Terrace
jik@Athena.MIT.EDU				Allston, MA  02134
Office: 617-253-8085			      Home: 617-782-0710

kaleb@thyme.jpl.nasa.gov (Kaleb Keithley) (01/31/91)

In article <1991Jan30.193308.3897@athena.mit.edu> jik@athena.mit.edu (Jonathan I. Kamens) writes:
>In article <1991Jan30.121425.16882@unhd.unh.edu>, pas@unhd.unh.edu (Paul A. Sand) writes:
>|> Emphasis is Jaeschke's. Even a tyro like me can recognize that you
>|> are in big trouble if (a) the realloc() fails, (b) ptr is your only
>|> access to the block, and (c) you had something important there.
>
>  I believe that if the realloc() fails, the memory block pointed to by the
>pointer passed into realloc() is no longer guaranteed to be valid.  Therefore,
>Jaeschke is right -- after realloc() returns NULL, you should not try to use
>the block whose address you passed into realloc().

the man page (on Sun) states the following:     
     ... If unable to honor a reallocation request, realloc() leaves 
     its first argument unaltered....

K&RII states the following:
    ... realloc returns [...] NULL if the request cannot be satisfied, in which
    case [the first argument] is unchanged.

-- 
Kaleb Keithley                        kaleb@thyme.jpl.nasa.gov

As of right now, I'm in charge here now...                  Alexander Haig.
Voodoo Economics, that's what it is, voodoo economics.      George Bush

3003jalp@ucsbuxa.ucsb.edu (Applied Magnetics) (01/31/91)

In article <1991Jan30.201955.21797@ux1.cso.uiuc.edu> mcdonald@aries.scs.uiuc.edu (Doug McDonald) writes:

> [...]  . Realloc returns a pointer to the new space, or NULL if the
> request cannot be satisfied, in which case *p is unchanged."

> The "" indicate a quote from K&R II. Note the last sentence: it says
> that *p is unchanged. *p is the CONTENTS of what p originally (and
> presumably still must) point to.

At last sanity prevails in principle.  It may not prevail in practice:
  The malloc subroutine, realloc subroutine, and calloc subroutine
  return a NULL pointer if there is no available memory or if the memory
  arena has been corrupted by storing outside the bounds of a block.
  When this happens, the block pointed to by the Pointer parameter may
  be destroyed.
This slightly ambiguous quote is from the aix3.1 manual.  To be fair
to IBM, many vendors do that.

  --Pierre Asselin, R&D, Applied Magnetics Corp.  I speak for me.

browns@iccgcc.decnet.ab.com (Stan Brown) (02/02/91)

In article <1991Jan30.193308.3897@athena.mit.edu>, 
jik@athena.mit.edu (Jonathan I. Kamens) writes:
>   I believe that if the realloc() fails, the memory block pointed to by the
> pointer passed into realloc() is no longer guaranteed to be valid.  Therefore,
> Jaeschke is right -- after realloc() returns NULL, you should not try to use
> the block whose address you passed into realloc().

ANSI X3.159-1989, pg 156, lines 23-24 (sec 4.10.3.4, The realloc
Function): "If the space cannot be allocated, the object pointed to by
ptr is unchanged."  'ptr' is the first argument to the function.

So in case of failure of new allocation, the old block _is_ guaranteed
to be untouched--unless the library is broken.

Hey--this is all my opinion, nobody else's. Rely on it at your peril.
                email: browns@ab.com -or- browns@iccgcc.decnet.ab.com
Stan Brown, Oak Road Systems, Cleveland, Ohio, USA    +1 216 371 0043

moraes@cs.toronto.edu (Mark Moraes) (02/03/91)

From the Seventh Edition manual page for malloc(3):
> BUGS
>      When realloc returns 0, the block pointed to by ptr  may  be
>      destroyed.

[This exists in the Eighth and Tenth Edition manuals as well, also
 the 4.3Reno manuals]

So one can't portably rely on the contents of the block being
realloced if the realloc failed.  On the other hand, this behaviour is
clearly marked a bug as far back as V7.

	Mark.

rob@jimi.UUCP (Rob Carlson) (02/06/91)

>
>But as long as I'm reading, I did notice a howler in Jaeschke's text,
>on page 320:
>
>	You should ALWAYS use realloc as follows:
>
>	ptr = realloc(ptr, new_size);
>
>Emphasis is Jaeschke's. Even a tyro like me can recognize that you
>are in big trouble if (a) the realloc() fails, (b) ptr is your only



  My understanding has always been that if realloc() fails (returns NULL),
ALL access to the previously allocated block is gone. It makes no difference
whether you keep the original ptr or not.

  This has stuck in my head because of a particularly nasty bug due to
assuming that the original ptr was still valid after the failure. But I can't
seem to find an adequate reference to back up my 'understanding'.

  Can anyone cite ANSI or any other reference to clear this up?
  
	Rob Carlson  

gwyn@smoke.brl.mil (Doug Gwyn) (02/09/91)

In article <00066@jimi.UUCP> rob@jimi.UUCP writes:
>  Can anyone cite ANSI or any other reference to clear this up?

They've already done so.  realloc() is obliged, in a conforming
implementation, to preserve the old data (and validity of the
old pointer value) when it returns null.

pas@unhd.unh.edu (Paul A. Sand) (02/09/91)

In article <00066@jimi.UUCP> rob@jimi.UUCP writes:
[me:]
>>But as long as I'm reading, I did notice a howler in Jaeschke's text,
>>on page 320:
>>
>>	You should ALWAYS use realloc as follows:
>>
>>	ptr = realloc(ptr, new_size);
>>

>  My understanding has always been that if realloc() fails (returns NULL),
>ALL access to the previously allocated block is gone. It makes no difference
>whether you keep the original ptr or not.

An ANSI-compatible realloc() must keep the original block unchanged on
failure. (See K&R, 2nd ed., p. 252.) Jaeschke's code is OK if you
assume that the block is trashed, but less than ideal if you're using a
standard realloc(). For that reason, I don't think he should have
said "ALWAYS".

>  This has stuck in my head because of a particularly nasty bug due to
>assuming that the original ptr was still valid after the failure. But I can't
>seem to find an adequate reference to back up my 'understanding'.

Since my original posting, a number of folks have pointed out that some
older realloc()'s indeed do trash the original block on failure.  My
own research (read: "a few minutes browsing at the bookstores") bears
this out. One text claims that the UNIX System V Release 4 realloc()
acts like that. (Can that be true?)

Interestingly enough, none of the three books I use as portability
references bothers to point this out, which is regrettable. Grr.
(Jaeschke's _Portability and the C Language_; Rabinowitz & Schaap's
_Portable C_, and Harbison & Steele, 3rd ed.)
-- 
-- Paul A. Sand                |
-- University of New Hampshire | I ain't here on business, baby.
-- uunet!unhd!pas              | I'm only here for fun.
-- pas@unhd.unh.edu            |

kpv@ulysses.att.com (Phong Vo[drew]) (02/10/91)

In article <1991Feb9.032853.25461@unhd.unh.edu>, pas@unhd.unh.edu (Paul A. Sand) writes:
: 
: Since my original posting, a number of folks have pointed out that some
: older realloc()'s indeed do trash the original block on failure.  My
: own research (read: "a few minutes browsing at the bookstores") bears
: this out. One text claims that the UNIX System V Release 4 realloc()
: acts like that. (Can that be true?)
: 
SysVr4 realloc is not old (at least in terms of publically available software)
and as far as I know it does not trash space after failure. The available version
may not be completely ansi-conformant with respect to realloc(NULL,size)
and free(NULL) but it should otherwise work as expected. My own version
is conformant and has few more bells and whistles but its public availability
will take time.

scott@bbxsda.UUCP (Scott Amspoker) (02/11/91)

In article <00066@jimi.UUCP> rob@jimi.UUCP writes:
>  My understanding has always been that if realloc() fails (returns NULL),
>ALL access to the previously allocated block is gone. It makes no difference
>whether you keep the original ptr or not.
>
>  This has stuck in my head because of a particularly nasty bug due to
>assuming that the original ptr was still valid after the failure. But I can't
>seem to find an adequate reference to back up my 'understanding'.

You're not imagining things.  There was a time when that was true.  We've
also had to deal with that "feature".  As for the present, someone has 
already posted a reference stating that realloc() must preserve the 
original data if it fails.

-- 
Scott Amspoker                       | 
Basis International, Albuquerque, NM |     This space available
(505) 345-5232                       | 
unmvax.cs.unm.edu!bbx!bbxsda!scott   |

bright@nazgul.UUCP (Walter Bright) (02/11/91)

In article <1991Jan30.204159.5726@athena.mit.edu> jik@athena.mit.edu (Jonathan I. Kamens) writes:
/If you want to assume that
/because ANSI C specifies realloc() as you quoted, all implementation of
/realloc() you come across specify it in that way, that's your right, but I
/doubt such an assumption is portable

What I do is assume realloc works in an ANSI way across all platforms. If
I discover one in which realloc is broken, the workaround consists of
writing my own replacement in terms of malloc, memcpy, free.
You don't have to suffer the lowest common denominator in library functions.
I also have a set of str... and mem... functions which are written portably,
and are used when I'm stuck on a system that doesn't support them.

Some functions can't be fixed simply, like fork, but a lot can be done if
you are willing to do a minor amount of work.

P.S. I'm not talking about patching the system's libraries or headers, I
insert the replacements in a separate module and link them in, thus overriding
the system libraries.

kean@pscnet.UUCP (Kean Johnston) (02/16/91)

The other day I had occasion to write a little C program which was repeatedly
increasing an array. Of course, realloc() is perfect for this. However, in
Harbison and Steele, they state that if you pass as the first parameter to
realloc a NULL pointer, then realloc() will allocate a block of size bytes
for you. No need to malloc the very first block.

Well, under Xenix 2.3.3 with 2.3.0 DevSys, this isn't so. If you don't do
the initial alloc() of the block, then realloc fails. Is using a NULL pointer
as the first parameter to realloc() a "standard" feature of the function, and
if so, which of the plethora of standards?

Thanks in advance,
Kean

-- 
+----------------------------------------------------------------------------+
| Kean Johnston: ..!ddsw1!proxima!olsa99!tabbs!pscnet!kean  kean@pscnet.UUCP |
|                "I think, therefore I AM" - Rene Descartes                  |
+----------------------------------------------------------------------------+

gwyn@smoke.brl.mil (Doug Gwyn) (02/24/91)

In article <6461@stpstn.UUCP> lerman@stpstn.UUCP (Ken Lerman) writes:
>So the solution is to "#define realloc Realloc" in my code so I can link
>my Realloc with my program.

You should not in general attempt to replace functions normally provided
by the standard C library with your own implementations, because it is
unlikely that you will know precisely what non-obvious constraints the C
library implementation has adopted.  (Often there are subtle things that
need to be taken care of within the C library of which most programmers
are unaware.)  This is especially problematic for memory allocation.  If
you feel the need to provide your own spiffy memory allocation interface,
use your OWN NAMES for those functions and have them call upon the
standard C memory allocation functions as required.  (This could take the
form of one huge allocation at the beginning of an application, which is
subsequently doled out in pieces by your own functions.  Other approaches
are also feasible.)

scs@adam.mit.edu (Steve Summit) (02/24/91)

In article <1991Feb16.010828.2152@pscnet.UUCP> kean@pscnet.UUCP (Kean Johnston) writes:
>The other day I had occasion to write a little C program which was repeatedly
>increasing an array. Of course, realloc() is perfect for this.
>...Harbison and Steele... state that if you pass as the first parameter to
>realloc a NULL pointer, then realloc() will allocate a block of size bytes
>for you. No need to malloc the very first block.
>Well, under Xenix 2.3.3 with 2.3.0 DevSys, this isn't so. If you don't do
>the initial [m]alloc of the block, then realloc fails. Is using a NULL pointer
>as the first parameter to realloc() a "standard" feature of the function, and
>if so, which of the plethora of standards?

The Teeming Millions (if I may borrow Cecil Adams' term) are
certainly prescient this month!  This is an excellent question,
and calls for another sneak preview of the upcoming, updated
comp.lang.c frequently-asked questions list:

56.  Is it legal to pass a null pointer as the first argument to
     realloc()?  Why would you want to?

A:   Doing so is legal and portable, at least as of ANSI X3.159's
     ratification.  (Not all pre-ANSI libraries accept it, however.)
     Passing an initially-null pointer to realloc can make it very easy
     to write a self-starting incremental allocation algorithm.

To elaborate, BSD (and perhaps V7) have already had the newly-
standardized behavior, but many other historical systems
(including, I am told, pre-ANSI System V) did not.

                                            Steve Summit
                                            scs@adam.mit.edu

P.S. I'm surprised that Harbison & Steele (2nd Ed.) sanction the
usage, since it was not universal in 1987 when the book was
published.  (I have been burned by the historical inconsistency,
as well.)

brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (02/25/91)

In article <1991Feb24.071716.409@athena.mit.edu> scs@adam.mit.edu writes:
>      Passing an initially-null pointer to realloc can make it very easy
>      to write a self-starting incremental allocation algorithm.

I find this advice counterproductive. Much better would be

	Passing an initially null pointer to realloc may seem a tempting
	way to write a self-starting incremental allocation algorithm,
	but it is simply not portable. It's just as easy---and much more
	portable---to start by allocating one element.

---Dan

dave@cs.arizona.edu (Dave P. Schaumann) (02/25/91)

In article <15112:Feb2419:11:4391@kramden.acf.nyu.edu> brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes:
>In article <1991Feb24.071716.409@athena.mit.edu> scs@adam.mit.edu writes:
>>      Passing an initially-null pointer to realloc can make it very easy
>>      to write a self-starting incremental allocation algorithm.
>
>I find this advice counterproductive. [...]
>it is simply not portable. It's just as easy---and much more
>portable---to start by allocating one element.

Actually, if you want to port code that passes NULL to realloc to a machine
that doesn't like that, all you have to do is this:

void *Realloc( void *ptr, size_t size ) {

  if( ptr == NULL ) return malloc ( size ) ;
  else		    return realloc( ptr, size ) ;

} /* Realloc */

Then, just #define realloc Realloc anywhere you need to.  I was going to post
this when this question first came up, but I thought it was so obvious, it
would be a waste of bandwidth...

-- 
Dave Schaumann      | Is this question undecidable?
dave@cs.arizona.edu |

markh@csd4.csd.uwm.edu (Mark William Hopkins) (03/05/91)

dave@cs.arizona.edu (Dave P. Schaumann) writes:
> Actually, if you want to port code that passes NULL to realloc to a machine
> that doesn't like that, all you have to do is this:
> [write correct routine called Realloc]
> Then, just #define realloc Realloc anywhere you need to.

In article <1991Feb25.053353.12842@athena.mit.edu> scs@adam.mit.edu writes:
>This is the right approach, but it's much better (if you care
>about widespread portability) to use a name like xrealloc instead
>of Realloc.  "Realloc" is not a good name for a wrapper function
>around realloc, because it is not distinct under a monocase
>linker.

The realloc problem is a red-herring.  All you have to do hide this away
somewhere in an include file:

#define xalloc(Loc, Bytes) \
   ((Loc) == NULL? malloc(Bytes): realloc((Loc), (Bytes)))

and don't use anything but xalloc...

You could even add in an #if section to define xalloc as realloc for standard
C.  And while you're at it, you might as well put in a couple more definitions
like:

#define make(Loc, Type) ((Type *)xalloc(Loc, sizeof(Type)))
#define break(Loc) (free((char *)Loc))

just to fatten up the include file...