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...