mjschmel@phoenix.Princeton.EDU (Michael J. Schmelzer) (05/10/88)
When you free something you've malloc'ed, how does the compiler keep track of how large a block you're freeing up? Obviously, free() and malloc() are machine dependent. So specifically, I'm working in Turbo C on an AT. Is it the compiler's job to keep tabs on each block that gets allocated by malloc()? What if you just freed a random block that wasn't allocated? (Big trouble, but why?) If someone could explain what free() actually does, that would help a great deal. Thank a lot. -- "Sum Iuppiter Optimus Maximus!!"- My Latin teacher who flipped. "Worthlessness is the root of all worthlessness." -WPRB music dept. Mike Schmelzer mjschmel@phoenix!princeton.edu DISLAIMER:If you think I speak for anyone but myself, you must be a lawyer.
g-rh@cca.CCA.COM (Richard Harter) (05/10/88)
In article <2843@phoenix.Princeton.EDU> mjschmel@phoenix.Princeton.EDU (Michael J. Schmelzer) writes: >When you free something you've malloc'ed, how does the compiler >keep track of how large a block you're freeing up? Er, I hope that 'compiler' was a slip. In case it wasn't, the compiler has nothing to do with it; compilers take your source code and generate machine executable code from it. >Obviously, free() and malloc() are machine dependent. So specifically, >I'm working in Turbo C on an AT. Is it the compiler's job to keep >tabs on each block that gets allocated by malloc()? What if you just >freed a random block that wasn't allocated? (Big trouble, but why?) Free and malloc are implementation dependent -- they are independent library routines. The quality of implementations vary. There are a lot of rather cheesy implementations out there. Nice allocators keep track of every block allocated and check whether an address passed to it via free is actually an allocated block. In a lot of implementations the control information for the block is placed just before the block, and the de facto assumption is made that the address being returned is legitimate. In these implementations returning an unallocated block will point the allocator to a garbage control block. The code that links and delinks blocks will do something funny, most likely creating a spurious block and overwriting some data in an effectively random location. What happens after that depends on the details of the allocator; if the allocator places the spurious freed block in linked list a real disaster will happen when the spurious block is used. -- In the fields of Hell where the grass grows high Are the graves of dreams allowed to die. Richard Harter, SMDS Inc.
mjschmel@phoenix.Princeton.EDU (Michael J. Schmelzer) (05/11/88)
In article <27780@cca.CCA.COM> g-rh@CCA.CCA.COM.UUCP (Richard Harter) writes: > Er, I hope that 'compiler' was a slip. In case it wasn't, the It was. Forgive my lack of precision. I meant 'library' or something. > Free and malloc are implementation dependent -- they are >independent library routines. The quality of implementations vary. >There are a lot of rather cheesy implementations out there. So I shouldn't make any assumptions, in other words. That's exactly what I wanted to know. I mean, nobody actually uses K&R's source code for their implementation, do they? >allocators keep track of every block allocated and check whether an >address passed to it via free is actually an allocated block. In a >lot of implementations the control information for the block is placed >just before the block So in other words, my free() routine has a lot more info than just an address, right? Thanks again, everyone! My adviser calls me a "C wizard," let's just not tell him the truth, OK? -- "Sum Iuppiter Optimus Maximus!!"- My Latin teacher who flipped. "Worthlessness is the root of all worthlessness." -WPRB music dept. Mike Schmelzer mjschmel@phoenix!princeton.edu DISLAIMER:If you think I speak for anyone but myself, you must be a lawyer.
dsr@stl.stc.co.uk (David Riches) (02/26/90)
We're writing a tool which requires memory management. We have a routine which allocates memory in the following fashion :- #define NE_ARR_MALLOC(y,n) ((y *) malloc ((unsigned) ((n) * (sizeof(y))))) Which will allocate space for n of y. The question then arises as how best to free this space? In most cases only the pointer to the space is known but will the following free up all the space :- #define NE_ARR_FREE(x) { free((char *) sizeof(x)); x = 0; } What happens to other references which might be pointing half way down the list for instance? Does anyone have any routines for memory management within C? Dave Riches PSS: dsr@stl.stc.co.uk ARPA: dsr%stl.stc.co.uk@earn-relay.ac.uk Smail: Software Design Centre, (Dept. 103, T2 West), STC Technology Ltd., London Road, Harlow, Essex. CM17 9NA. England Phone: +44 (0)279-29531 x2496
CMH117@psuvm.psu.edu (Charles Hannum) (02/27/90)
Why don't you try: #define NE_ARR_MALLOC(n) ((y *)calloc(n, sizeof(y))) #define NE_ARR_FREE(x) (free(x), x=NULL) In your original posting, you were trying to pass the length of x (which is the size of the pointer) to free(). This won't work. You should just pass x itself. Also, your use of a block structure in NE_ARR_FREE points out a disturbing problem in C. If I have something like: if (conda) definea(junk); else defineb(junk); Will work fine if definea() and defineb() are either functions or single-line #defines. But what about multiple-line #defined macros? In this case, you can work around it with the , operator, but in many cases you cannot. For compilers that support inline function calls (read: macros that look like functions) that would be the best solution. But with those that don't ... Virtually, - Charles Martin Hannum II "Klein bottle for sale ... inquire within." (That's Charles to you!) "To life immortal!" cmh117@psuvm.{bitnet,psu.edu} "No noozzzz izzz netzzzsnoozzzzz..." c9h@psuecl.{bitnet,psu.edu} "Mem'ry, all alone in the moonlight ..."
darcy@druid.uucp (D'Arcy J.M. Cain) (02/27/90)
In article <2714@stl.stc.co.uk> dsr@stl.stc.co.uk (David Riches) writes: >We're writing a tool which requires memory management. >We have a routine which allocates memory in the following >fashion :- > #define NE_ARR_MALLOC(y,n) ((y *) malloc ((unsigned) ((n) * (sizeof(y))))) > >Which will allocate space for n of y. calloc does what you want and even initialize the space to zeroes for you. To allocate n of y use: x = (y *)calloc(n, sizeof(y); where x is a pointer to type y. If using an ANSI compiler you can even leave off the cast since calloc (and malloc) returns a pointer to void. > >The question then arises as how best to free this space? >In most cases only the pointer to the space is known but will the >following free up all the space :- > #define NE_ARR_FREE(x) { free((char *) sizeof(x)); x = 0; } > >What happens to other references which might be pointing half way >down the list for instance? > I'm afraid I can't parse the above statement. It seems to be saying that the argument to free is the size of the array casted to a pointer. In any case to free up space simply pass free the pointer to the malloc'ed space. struct y *x; unsigned nelems = NUMBER_OF ELEMENTS_REQUIRED_FOR_YOUR_APPLICATION; ... x = malloc(nelems * sizeof(y)); /***** OR *****/ x = calloc(nelems, sizeof(y)); ... free(x); -- D'Arcy J.M. Cain (darcy@druid) | Thank goodness we don't get all D'Arcy Cain Consulting | the government we pay for. West Hill, Ontario, Canada | (416) 281-6094 |
karl@haddock.ima.isc.com (Karl Heuer) (03/01/90)
In article <1990Feb27.155133.20341@druid.uucp> darcy@druid.UUCP (D'Arcy J.M. Cain) writes: >calloc does what you want and even initialize the space to zeroes for you. The calloc() function is disrecommended. Generally speaking, you should use malloc() and initialize the contents yourself. Karl W. Z. Heuer (karl@ima.ima.isc.com or harvard!ima!karl), The Walking Lint
pc@cs.keele.ac.uk (Phil Cornes) (03/01/90)
From article <2714@stl.stc.co.uk>, by dsr@stl.stc.co.uk (David Riches): > In most cases only the pointer to the space is known but will the > following free up all the space :- > #define NE_ARR_FREE(x) { free((char *) sizeof(x)); x = 0; } > No this just won't work - you can only pass a pointer returned by malloc() into a call to free().... Phil Cornes I just called to say ..... -----------* JANET: cdtpc@uk.ac.stafpol.cr83 Phone: +44 (0)785 53511 x6058 Smail: Staffordshire Polytechnic, Computing Department, Blackheath Lane, STAFFORD, ST18 0AD, ENGLAND.
darcy@druid.uucp (D'Arcy J.M. Cain) (03/01/90)
In article <16055@haddock.ima.isc.com> karl@haddock.ima.isc.com (Karl Heuer) writes: >In article <1990Feb27.155133.20341@druid.uucp> darcy@druid.UUCP (D'Arcy J.M. Cain) writes: >>calloc does what you want and even initialize the space to zeroes for you. > >The calloc() function is disrecommended. Generally speaking, you should use >malloc() and initialize the contents yourself. > I've heard that before but not the reason. So why is it disrecommended? -- D'Arcy J.M. Cain (darcy@druid) | Thank goodness we don't get all D'Arcy Cain Consulting | the government we pay for. West Hill, Ontario, Canada | (416) 281-6094 |
meissner@osf.org (Michael Meissner) (03/02/90)
In article <1990Mar1.140829.17199@druid.uucp> darcy@druid.uucp (D'Arcy J.M. Cain) writes: | In article <16055@haddock.ima.isc.com> karl@haddock.ima.isc.com (Karl Heuer) writes: | >In article <1990Feb27.155133.20341@druid.uucp> darcy@druid.UUCP (D'Arcy J.M. Cain) writes: | >>calloc does what you want and even initialize the space to zeroes for you. | > | >The calloc() function is disrecommended. Generally speaking, you should use | >malloc() and initialize the contents yourself. | > | I've heard that before but not the reason. So why is it disrecommended? Because there exist machines whose floating point 0.0 does not have all bits zeroed. There are also machines where a NULL pointer does not have all bits zeroed. Using calloc will probably work 99.99%, but do you want to have to be the 'lucky' person who has to track down why such a machine gives funny answers. -- Michael Meissner email: meissner@osf.org phone: 617-621-8861 Open Software Foundation, 11 Cambridge Center, Cambridge, MA Catproof is an oxymoron, Childproof is nearly so
morrell@hpsal2.HP.COM (Michael Morrell) (03/02/90)
/comp.lang.c/karl@haddock.ima.isc.com (Karl Heuer)/12:08 pm Feb 28, 1990/ The calloc() function is disrecommended. Generally speaking, you should use malloc() and initialize the contents yourself. ---------- Why? Michael
yahoo@unix.cis.pitt.edu (Kenneth L Moore) (03/02/90)
In article <MEISSNER.90Mar1135840@curley.osf.org> meissner@osf.org (Michael Meissner) writes: >In article <1990Mar1.140829.17199@druid.uucp> darcy@druid.uucp (D'Arcy >J.M. Cain) writes: > >| In article <16055@haddock.ima.isc.com> karl@haddock.ima.isc.com (Karl Heuer) writes: >>calloc does what you want and even initialize the space to zeroes for you. > >The calloc() function is disrecommended. Generally speaking, you should use >malloc() and initialize the contents yourself. There are instances where you want an uninitialized variable to be (nil) and not zero as a flag. This way you know you have a coding problem and can correct it. Otherwise, you may start computing with an incorrect zero resulting in an erroneous answer that might look reasonable. -- I don't yell and I don't tell and I'm grateful as hell: Benny Hill
ping@cubmol.bio.columbia.edu (Shiping Zhang) (03/02/90)
In article <MEISSNER.90Mar1135840@curley.osf.org> meissner@osf.org (Michael Meissner) writes: [In article <1990Mar1.140829.17199@druid.uucp> darcy@druid.uucp (D'Arcy [J.M. Cain) writes: [ [| In article <16055@haddock.ima.isc.com> karl@haddock.ima.isc.com (Karl Heuer) writes: [| >In article <1990Feb27.155133.20341@druid.uucp> darcy@druid.UUCP (D'Arcy J.M. Cain) writes: [| > [| >The calloc() function is disrecommended. Generally speaking, you should use [| >malloc() and initialize the contents yourself. [| > [| I've heard that before but not the reason. So why is it disrecommended? [ [Because there exist machines whose floating point 0.0 does not have [all bits zeroed. There are also machines where a NULL pointer does [not have all bits zeroed. Using calloc will probably work 99.99%, but [do you want to have to be the 'lucky' person who has to track down why [such a machine gives funny answers. My question is Why is NOT calloc() made machine independent. I also often asked (to myself) Why is NOT malloc() made to initialize the contents automatically? I simply can not think of any case where the initial contents would be useful for some purpose and should be preserved. Is the efficiency a matter here? -ping
meissner@osf.org (Michael Meissner) (03/03/90)
In article <1990Mar2.152601.8000@cubmol.bio.columbia.edu> ping@cubmol.bio.columbia.edu (Shiping Zhang) writes: | My question is | Why is NOT calloc() made machine independent. | I also often asked (to myself) | Why is NOT malloc() made to initialize the contents automatically? | I simply can not think of any case where the initial contents would | be useful for some purpose and should be preserved. Is the efficiency | a matter here? If you are allocating a very large area, and then set the area to all 0's (or whatever bit pattern you want) on a virtual memory system, it will force each of the pages to be faulted in, which can be bad. For example, if you allocate a 10 meg chunk for the worst case senario, and only use say 256K, clearing the memory would force would touch 9.75 meg of pages uselessly. A friend of mine sped up a linker on exactly this problem. -- Michael Meissner email: meissner@osf.org phone: 617-621-8861 Open Software Foundation, 11 Cambridge Center, Cambridge, MA Catproof is an oxymoron, Childproof is nearly so
bright@Data-IO.COM (Walter Bright) (03/03/90)
In article <1990Mar1.140829.17199@druid.uucp> darcy@druid.UUCP (D'Arcy J.M. Cain) writes: <In article <16055@haddock.ima.isc.com> karl@haddock.ima.isc.com (Karl Heuer) writes: <<The calloc() function is disrecommended. Generally speaking, you should use <<malloc() and initialize the contents yourself. <I've heard that before but not the reason. So why is it disrecommended? The reasons are similar to the arguments about not using goto. calloc works fine and is portable. Whether or not you use it is a religious issue. Personally, I use it a lot. I usually set up my structs so the default, benign values for members are 0. Using calloc to allocate them then gets them initialized properly and efficiently. It also avoids bugs I've had when I added a member to a struct, and forgot to initialize it in some obscure location. My code tends to use storage allocation heavilly, and the extra efficiency gained by using calloc over a sequence of assignments is significant. And no, I don't care about machines where 0.0 and NULL are not 0 bit patterns. If someday I should be unfortunate enough to run across one, I'll worry about it then!
ping@cubmol.bio.columbia.edu (Shiping Zhang) (03/03/90)
In article <MEISSNER.90Mar2124443@curley.osf.org> meissner@osf.org (Michael Meissner) writes: >In article <1990Mar2.152601.8000@cubmol.bio.columbia.edu> >ping@cubmol.bio.columbia.edu (Shiping Zhang) writes: >If you are allocating a very large area, and then set the area to all >0's (or whatever bit pattern you want) on a virtual memory system, it >will force each of the pages to be faulted in, which can be bad. For >example, if you allocate a 10 meg chunk for the worst case senario, >and only use say 256K, clearing the memory would force would touch >9.75 meg of pages uselessly. A friend of mine sped up a linker on >exactly this problem. If I'm sure the worst case will need 10 meg and NO more and I want allocate that much space all at once at the very begin, then I will simply declare an ordinary variable of that size. If that space will be used for different types of data, I can define an union to deal with the problem. Otherwise, I will only malloc() 10 kb or 1 kb first, then later realloc() more space if necessary. Working with arrays, the boundries should always be checked, so no extra boaden is given to find out when realloc() should be called. Because malloc(), calloc() and the like belong to one set of functionally related routines, the way of using them should be consistant. They should all either do initialization (with the same results machine indepently) or all do not, but not some do, some don't. If initialization can not be gaurenteed to give consistent results machine indepently, then it is much much better to just leave the programers no choice but doing initialization themselves if necessary. Don't let programers debate in their mind and take chances. -ping
msb@sq.sq.com (Mark Brader) (03/03/90)
> Why is NOT malloc() made to initialize the contents automatically? > Is the efficiency a matter here? Yes, it is. For many applications there is no point in initializing it because the next thing you're going to do is overwrite the entire space anyway. In addition, malloc() does not know what type of data you're going to put in the allocated space, and so it couldn't tell what initial value to put there anyway. (calloc() puts all zero bits, which is only useful for integer types.) -- Mark Brader, SoftQuad Inc., Toronto "Remember the Golgafrinchans" utzoo!sq!msb, msb@sq.com -- Pete Granger This article is in the public domain.
freek@fwi.uva.nl (Freek Wiedijk) (03/03/90)
In article <2353@dataio.Data-IO.COM> bright@Data-IO.COM (Walter Bright) writes: >And no, I don't care about machines where 0.0 and NULL are not 0 bit >patterns. If someday I should be unfortunate enough to run across one, >I'll worry about it then! When you read this, don't you think the C community's cavalier attitude on software reliability is horrible? :-) -- Freek "the Pistol Major" Wiedijk Path: uunet!fwi.uva.nl!freek #P:+/ = #+/P?*+/ = i<<*+/P?*+/ = +/i<<**P?*+/ = +/(i<<*P?)*+/ = +/+/(i<<*P?)**
henry@utzoo.uucp (Henry Spencer) (03/03/90)
In article <1990Mar2.152601.8000@cubmol.bio.columbia.edu> ping@cubmol.bio.columbia.edu (Shiping Zhang) writes: >[Because there exist machines whose floating point 0.0 does not have >[all bits zeroed. There are also machines where a NULL pointer does >[not have all bits zeroed... >My question is > Why is NOT calloc() made machine independent. Please re-read the ">[" part above. It *can't* be made machine-independent. It has no way to tell what type of data you're going to put into the memory, and hence it has no way to know what bit pattern it should initialize to. It is inherently, completely, unfixably machine-dependent in the general case. >I also often asked (to myself) > Why is NOT malloc() made to initialize the contents automatically? What could it usefully initialize the contents to? In most cases, the first thing the programmer does is to overwrite the contents anyway. Initializing them is mostly a waste of time. Note that C local variables are not automatically initialized either, for the same reason: it has a significant cost and is generally useless. -- MSDOS, abbrev: Maybe SomeDay | Henry Spencer at U of Toronto Zoology an Operating System. | uunet!attcan!utzoo!henry henry@zoo.toronto.edu
bengsig@oracle.nl (Bjorn Engsig) (03/05/90)
Article <1990Mar2.152601.8000@cubmol.bio.columbia.edu> by ping@cubmol.bio.columbia.edu (Shiping Zhang) says: | Why is NOT calloc() made machine independent. It's not a matter of machine dependence, but a matter of dependence of what your program puts into the malloc'ed area. And since only integers are sure to have all zero-bit zero's, only cases where you only put integers into the malloc'ed area can be cleared with all-zeros, i.e. allocated by a calloc call. | Why is NOT malloc() made to initialize the contents automatically? Why would you spend time on this, if you have to put data into the area anyway? I believe this is by far the most common use. -- Bjorn Engsig, Domain: bengsig@oracle.nl, bengsig@oracle.com Path: uunet!mcsun!orcenl!bengsig
khan@milton.acs.washington.edu (I Wish) (03/06/90)
In article <2353@dataio.Data-IO.COM> bright@Data-IO.COM (Walter Bright) writes: >The reasons are similar to the arguments about not using goto. calloc works >fine and is portable. Whether or not you use it is a religious issue. [...] >And no, I don't care about machines where 0.0 and NULL are not 0 bit >patterns. If someday I should be unfortunate enough to run across one, >I'll worry about it then! Calloc will set up a zero-bit pattern on any machine.... if you are depending on this meaning floating-point zero or the null pointer, then it won't do that some machines, so it can't be called "portable." (As an aside, does a VAX, with floating-point descriptors or whatever it uses, treat zero-bytes as float 0.0?) -- "indecipherable strangers handing out inexplicable humiliation and an unidentified army of horsemen laughing at him in his head ..." -- Douglas Adams Erik Seaberg (khan@milton.u.washington.edu)
harish@ecebucolix.ncsu.edu (Harish P. Hiriyannaiah) (03/06/90)
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX In article <2263@milton.acs.washington.edu>, khan@milton.acs.washington.edu (I Wish) writes: > > (As an aside, does a VAX, with floating-point descriptors or whatever > it uses, treat zero-bytes as float 0.0?) > -- > Erik Seaberg (khan@milton.u.washington.edu) Yes it does, both in 32-bit and 64-bit f.p. formats. The same is true (I think) for IEEE f.p. formats. (See the Intel 860 programmers handbook for the exact encoding. I have the book at home........ I will check on it and post a correction if I am wrong ). As an aside, what do netters feel about DEC's 64-bit format for floats vs the IEEE one ? I contend that the DEC format is superior, even though it lacks the extra exponent-range of the IEEE format. So whadd'yall think ? harish pu. hi. harish@ecebucolix.ncsu.edu
meissner@osf.org (Michael Meissner) (03/06/90)
In article <2263@milton.acs.washington.edu> khan@milton.acs.washington.edu (I Wish) writes: | In article <2353@dataio.Data-IO.COM> bright@Data-IO.COM (Walter Bright) writes: | | >The reasons are similar to the arguments about not using goto. calloc works | >fine and is portable. Whether or not you use it is a religious issue. | | [...] | | >And no, I don't care about machines where 0.0 and NULL are not 0 bit | >patterns. If someday I should be unfortunate enough to run across one, | >I'll worry about it then! | | Calloc will set up a zero-bit pattern on any machine.... if you are | depending on this meaning floating-point zero or the null pointer, then | it won't do that some machines, so it can't be called "portable." | | (As an aside, does a VAX, with floating-point descriptors or whatever | it uses, treat zero-bytes as float 0.0?) I believe that the only machine in the world whose floating point format for 0.0 contains 1 bits is one of the old Honeywell computers (at least that's what was mentioned in X3J11). At one point, the designers for the S1 machine (or language, it's been at least a year since I saw the newspost), toyed with making the NULL pointer contain 1 bits. When I was at Data General, I toyed with OR'ing in the current ring for the pointer at one point as well, as well, and eventually gave up on the idea. -- Michael Meissner email: meissner@osf.org phone: 617-621-8861 Open Software Foundation, 11 Cambridge Center, Cambridge, MA Catproof is an oxymoron, Childproof is nearly so
harrism@omhftre (Mark Harris) (03/08/90)
> When I was at Data General, I toyed with > OR'ing in the current ring for the pointer at one point as well, as > well, and eventually gave up on the idea. I'm sure that the folks at Data General that had to deal with customer's C compiler questions/moans are glad you dropped that idea. ;-) <Sorry Mike, couldn't resist. Hope you are doing well. I've tried sending you mail, but some machine between here and there is unresponsive. Maybe the reverse path will work.> Mark Harris
gordon@sneaky.UUCP (Gordon Burditt) (03/09/90)
>| Why is NOT malloc() made to initialize the contents automatically? >Why would you spend time on this, if you have to put data into the area anyway? >I believe this is by far the most common use. I have on occasion put my own wrapper around malloc() to initialize the allocated memory area. The data to use for initialization was chosen so that (some of these objectives are processor-dependent): - If it's used as a pointer, you get a segmentation violation. - If it's used as a function pointer, it should be odd so you trap immediately. - If it's used as a floating point number, you get a number with an obnoxiously large exponent that's likely to overflow in calculations. - If it's used as an integer, it's very large and negative. - If it's printed in hex, it's recognizable. One number I used for this was the 4-byte constant: 0xdeadbee1. On another occasion I used the negative of the time(). I would like to add one criteria I couldn't satisfy: - If it's printed as a string, it's an obscenity. Also, it's very important that no portion of the program EXCEPT the wrapper around malloc() know what the constant is or any of its attributes. Using this technique with a program that made extensive use of linked lists helped to quickly trap failure to initialize back link pointers close to the point of the problem. After the program is working (you think), you can take out the debugging initialization part to speed up the program. Gordon L. Burditt sneaky.lonestar.org!gordon
noah@wet.UUCP (Noah Spurrier) (05/07/90)
Is there anything wrong with freeing a NULL? pointer? I have a function that
uses a static pointer. Everytime the function is called it frees up the
previous pointer using free, but the first time the function is called
there is nothing to free; the static pointer is initialized to NULL. This is
a good example of one of those annoying functions that work great as long
as they don't have a first time case.
Here is what I am doing...
char *squirl()
{
static char *test = NULL;
free (test);
test = (char *) malloc (100);
return (test);
}
This function is run many times so iI do not want to protect it with an if
because the if would only be useful for the first time it is run, after that
it just eats up run time.
if (test != NULL)
free (test);
Will angry things happen if I try to free(NULL) ?
yours,
Noah Spurrier
noah@WET.UUCP
cpcahil@virtech.uucp (Conor P. Cahill) (05/08/90)
In article <1194@wet.UUCP> noah@wet.UUCP (Noah Spurrier) writes: >This function is run many times so iI do not want to protect it with an if >because the if would only be useful for the first time it is run, after that >it just eats up run time. > > if (test != NULL) > free (test); The test of a variable against zero is one of the most efficient operations performed in a computer. Even if you called the function millions of times during program execution, you probably couldn't tell whether or not the if is present because of it's small use of CPU power. >Will angry things happen if I try to free(NULL) ? Undefined. Maybe, maybe not. Why take the chance? You won't be saving any measurable CPU time. -- Conor P. Cahill (703)430-9247 Virtual Technologies, Inc., uunet!virtech!cpcahil 46030 Manekin Plaza, Suite 160 Sterling, VA 22170
whipple@sun.udel.edu (Peter Adams Whipple) (05/08/90)
In article <1194@wet.UUCP> noah@wet.UUCP (Noah Spurrier) writes: > >Will angry things happen if I try to free(NULL) ? > >yours, > >Noah Spurrier >noah@WET.UUCP According to the MSC 5.1 manual, no. Other compiler libraries may vary.
drh@romeo.cs.duke.edu (D. Richard Hipp) (05/08/90)
In article <1194@wet.UUCP> noah@wet.UUCP (Noah Spurrier) writes: > >Is there anything wrong with freeing a NULL? pointer? > >char *squirl() >{ > static char *test = NULL; > free (test); > test = (char *) malloc (100); > return (test); >} > >This function is run many times so iI do not want to protect it with an if >because the if would only be useful for the first time it is run, after that >it just eats up run time. 1. Different implementation do different things with NULL pointers passed to free(). I find it best to assume that it is illegal to not give a null pointer to free(). 2. The amount of time used by an "if" statement to protect the free(), is insignificant compared to the amount of time used by free() itself, and is REALLY insignificant compared to the amount of time used by malloc(). Use an "if". 3. If you are always freeing and mallocing a chunk of memory the same size, then why not just allocate a static array and not mess with free() and malloc() at all. Such will accomplish exactly the same thing as free() followed by malloc(), but with considerably fewer machine cycles. Example: char *squirl() { static char test[100]; return test; } 4. If you are doing something more complex than your example shows, consider using "realloc()".
henry@utzoo.uucp (Henry Spencer) (05/08/90)
In article <1194@wet.UUCP> noah@wet.UUCP (Noah Spurrier) writes: >Will angry things happen if I try to free(NULL) ? On many current systems, yes. ANSI C guarantees that you can free a null pointer, but many existing implementations will malfunction if handed one. -- If OSI is the answer, what is | Henry Spencer at U of Toronto Zoology the question?? -Rolf Nordhagen| uunet!attcan!utzoo!henry henry@zoo.toronto.edu
leo@ehviea.ine.philips.nl (Leo de Wit) (05/08/90)
In article <19461@duke.cs.duke.edu> drh@cs.duke.edu writes: |In article <1194@wet.UUCP> noah@wet.UUCP (Noah Spurrier) writes: |> |>Is there anything wrong with freeing a NULL? pointer? |> |>char *squirl() |>{ |> static char *test = NULL; |> free (test); |> test = (char *) malloc (100); |> return (test); |>} |> |>This function is run many times so iI do not want to protect it with an if |>because the if would only be useful for the first time it is run, after that |>it just eats up run time. | |1. Different implementation do different things with NULL pointers | passed to free(). I find it best to assume that it is illegal | to not give a null pointer to free(). I guess this states you cannot safely call free() ? :-) Leo.
bph@buengc.BU.EDU (Blair P. Houghton) (05/09/90)
In article <1194@wet.UUCP> noah@wet.UUCP (Noah Spurrier) writes: > >Is there anything wrong with freeing a NULL? pointer? I have a function that In ANSI C, doing `free(ptr)', "if ptr is a NULL pointer, no action occurs" (quoted from X3.159-1989). Most current free(3) manual pages seem to ignore this bit of semantics, though you might get stuck on things like "the argument to free is a pointer to a block of memory previously allocated by malloc()." ANSI instead says that if it doesn't match a *alloc'ed pointer it has undefined consequences, except of course for the explicit case where the pointer is NULL. --Blair "Let's get Mikey to program it. Yeah, he hates everything..."
bdm659@csc.anu.oz (05/09/90)
In article <1194@wet.UUCP>, noah@wet.UUCP (Noah Spurrier) writes: > > Is there anything wrong with freeing a NULL? pointer? I have a function that > uses a static pointer. Everytime the function is called it frees up the > previous pointer using free, but the first time the function is called > there is nothing to free; the static pointer is initialized to NULL. The ANSI standard says that free() is a no-op if the argument is null. Many older libraries treat it like that too, but some don't. Use something like if (p != NULL) free(p) if you want maximum portability. The extra overhead would be trivial. Incidentally, the exact form free(NULL) is dangerous is there is no visible prototype for free(). If you really want to pass a null pointer, use free((void*)NULL) or free((char*)NULL). The same holds true for procedures other than free(), of course. (In general you must cast NULL to a pointer of the type expected by the procedure, unless there is a prototype which will cause this cast to be done for you.) Failure to do this cast is a quite common programming error. Brendan McKay. bdm@anucsd.anu.oz.au or bdm@csc.anu.oz.au
henley@motcid.UUCP (Aaron Henley) (05/09/90)
noah@wet.UUCP (Noah Spurrier) writes: >char *squirl() >{ > static char *test = NULL; > free (test); > test = (char *) malloc (100); > return (test); >} >This function is run many times so iI do not want to protect it with an if >because the if would only be useful for the first time it is run, after that >it just eats up run time. > if (test != NULL) > free (test); >Will angry things happen if I try to free(NULL) ? ANSI C may specify that free(NULL) should work, but for those people currently not using an ANSI C compiler the following will also work: static char *test = (char *) malloc (100); This obviously wastes time during the first execution, but should work across all K&R C libraries and ANSI C libraries. BTW: If the ANSI C library supports this, does this mean that the "if (test != NULL)" is done by the library which now means that you'll always use up your run time with this test even if you know the test isn't needed? -- ___________________________________________________________________ / Aaron Henley, Motorola Inc. DISCLAIMER: std.disclaimer / / Cellular Infrastructure Division UUCP: ...!uunet!motcid!henley / /__________________________________________________________________/
c60c-3cf@e260-3f.berkeley.edu (Dan Kogai) (05/10/90)
In article <19461@duke.cs.duke.edu> drh@cs.duke.edu writes: >In article <1194@wet.UUCP> noah@wet.UUCP (Noah Spurrier) writes: >> >>Is there anything wrong with freeing a NULL? pointer? >>[Example code ommited] >>This function is run many times so iI do not want to protect it with an if >>because the if would only be useful for the first time it is run, after that >>it just eats up run time. >1. Different implementation do different things with NULL pointers > passed to free(). I find it best to assume that it is illegal > to not give a null pointer to free(). Yep. And it's really annoying. Sun manual said nothing about what's gonna happen--segfault? Just do nothing safely. I don't have ANSI draft handy but ANSI should've included some "specs" in case of NULL pointer if it hadn't. >2. The amount of time used by an "if" statement to protect the free(), > is insignificant compared to the amount of time used by free() itself, > and is REALLY insignificant compared to the amount of time used > by malloc(). Use an "if". Very true. Usually I write higher level function to release memory because in some cases structure contains substructure which is malloc'ed and substructure cannot be freed like the following case: typedef struct Baz{ char *foo char *bar }Baz, *baz; /* ... */ baz blech = (baz)malloc(sizeof(Baz)); blech->foo = (char *)malloc(FOOSIZE); blech->bar = (char *)malloc(BARSIZE); /* ... */ free(blech); /* foo and bar remain unfreed */ If it's simple and contains no substructure, I usually use following macro: #define trash(foo) if (foo != NULL) free(foo) >3. If you are always freeing and mallocing a chunk of memory the same > size, then why not just allocate a static array and not mess with free() > and malloc() at all. Such will accomplish exactly the same thing > as free() followed by malloc(), but with considerably fewer machine > cycles. Example: > > char *squirl() > { > static char test[100]; > return test; > } Or allocate externally. If externally allocated you don't even have to write a function for it. >4. If you are doing something more complex than your example shows, > consider using "realloc()". Plus make sure the object is already allocated by [mc]alloc(). Again I'm not sure what's gonna happen if realloc gets NULL object as an arg. Also don't forget realloc might fail--that happened to me. Happy coding! --- ################## Dan The "free" Man + ____ __ __ + (Aka Dan Kogai) + ||__||__| + E-mail: dankg@ocf.berkeley.edu + ____| ______ + Voice: 415-549-6111 + | |__|__| + USnail: 1730 Laloma Berkeley, CA 94709 + |___ |__|__| + U.S.A + |____|____ + Disclaimer: I'd rather be blackmailed for my long .sig + \_| | + than give up my cool name in Kanji. And my + <- THE MAN -> + citizenship of People's Republic o' Berkeley ################## has nothing 2 do w/ whatever I post, ThanQ.
richard@aiai.ed.ac.uk (Richard Tobin) (05/26/90)
In article <1724@necisa.ho.necisa.oz> boyd@necisa.ho.necisa.oz (Boyd Roberts) writes: >>There are plenty of cases where a careful programmer >>might do "if(p) free(p)" with complete clarity and correctness. >I hope this `careful programmer' never uses malloc(). Er, I hope they do. Otherwise they're making a mistake in using free(). >If you allocate >something, there comes a time when it should be free'd. Not because >it `might' be a good idea, but because it is correct to do so. *Sigh* Yes, *if* you allocate something, you probably want to free it later. But what if you *didn't* allocate it? Then you *don't* want to free it. It's completely reasonable, for example, to have a structure with fields that might either be filled in (with a string containing a name, perhaps) or be null (because the name isn't known, perhaps). In such a case, when you free the structure, "if(s->name) free(s->name)" is exactly what you need to do. >free(NULL) has simplicity at the cost of clarity, correctness and portability. >Successfully using an error return value is not a programming pearl. If the NULL you pass to free was handed to you by malloc() than you should almost certainly have already checked for it. Even in this case, it may simplify your error cleanup code if you just call free() anyway. But this wasn't one of the situations I had in mind. -- Richard -- Richard Tobin, JANET: R.Tobin@uk.ac.ed AI Applications Institute, ARPA: R.Tobin%uk.ac.ed@nsfnet-relay.ac.uk Edinburgh University. UUCP: ...!ukc!ed.ac.uk!R.Tobin
ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) (05/26/90)
In article <2574@skye.ed.ac.uk>, richard@aiai.ed.ac.uk (Richard Tobin) writes: > *Sigh* Yes, *if* you allocate something, you probably want to free it > later. But what if you *didn't* allocate it? Then you *don't* want > to free it. > It's completely reasonable, for example, to have a structure with fields > that might either be filled in (with a string containing a name, perhaps) > or be null (because the name isn't known, perhaps). In such a case, when > you free the structure, "if(s->name) free(s->name)" is exactly what you > need to do. Let me change the emphasis on that, from "what if you *didn't* allocate it?" to "what if *you* didn't allocate it?" The problem I've often had is that I have a data structure containing some pointers, and *I* have filled some of them in (using strdup()) and the caller preset some of them to defaults. Now I'm going to change one of them. Should I free it? If *I* allocated it, certainly, there isn't any other copy of the pointer. If the *caller* allocated it *and* the caller hasn't any other copy of the pointer *and* it was allocated using malloc() then it would be a good idea to free it, but if -- the caller wants to keep it or -- it was a string literal or -- it came from something other than malloc() then it should _not_ be given to free(), and checking for NULL isn't going to help me. I've been driven to two extremes, neither of which I am happy with: Method 1: play safe and _don't_ free things when there's any doubt. Advantage: I'm never going to free anything I shouldn't. Problem: I'm never going to free things I _should_, storage leak! Method 2: add an extra field beside each pointer saying "it is safe to free this pointer". Advantage: I get to free _precisely_ what needs freeing (and NULL is not a special case; it gets the "not safe to free" flag). Problem: the caller has to preset the fields; it is easy to forget this or to remember it and get it wrong. (Method 3, of course, would be to use a garbage collector, and I have one somewhere that came over the net. But I'd rather not make my programs any less portable than I have to. Method 4 would be to use a fast safe language like SML, except that I haven't actually got enough memory to run it and it doesn't actually work on this machine.) Note that the free(NULL) kluge doesn't help with this one tiny little bit. Can anyone suggest a better way of tackling this problem in portable C? -- "A 7th class of programs, correct in every way, is believed to exist by a few computer scientists. However, no example could be found to include here."
boyd@necisa.ho.necisa.oz (Boyd Roberts) (05/28/90)
In article <2574@skye.ed.ac.uk> richard@aiai.UUCP (Richard Tobin) writes: > >*Sigh* Yes, *if* you allocate something, you probably want to free it >later. But what if you *didn't* allocate it? Then you *don't* want >to free it. > Yeah, right... > >If the NULL you pass to free was handed to you by malloc() than you >should almost certainly have already checked for it. Even in this >case, it may simplify your error cleanup code if you just call free() >anyway. But this wasn't one of the situations I had in mind. > And now you want to free the unallocated object, courtesy of certain implementations' blessing on the construct free(NULL). The bottom line is that the library should not be mangled to cater for sloppy programming practices, which are deemed to be convenient. When I see a C library I expect it to address itself to the precise problem at hand and nothing more. I don't want code in there that checks that it's a Tuesday and that it's statistically likely that on Tuesdays a certain class of programmers will make certain wrong assumptions and the code will correct it. The onus is on the programmer to write correct programs. It should not be the library's job to act as a safety net for these `conveniences'. Boyd Roberts boyd@necisa.ho.necisa.oz.au ``When the going gets wierd, the weird turn pro...''
steve@taumet.COM (Stephen Clamage) (05/29/90)
In article <3078@goanna.cs.rmit.oz.au> ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) writes: >I have a data structure containing >some pointers, and *I* have filled some of them in >and the caller preset some of them to defaults. Now I'm going to change >one of them. Should I free it? ... >Can anyone suggest a better way of tackling this problem in portable C? This is easy to handle (safely and portably) in C++ (which is not precisely the question you asked). In the constructor for the data structure, you set a private boolean that says whether a the data pointed-to needs to be freed. The destructor, and each member function which modifies the structure, checks the boolean to see whether to free the data. These functions are written once while the design is fresh in your mind. Forever after, only the member functions are used to modify the data, and no user of the data type ever needs to think about freeing the data. -- Steve Clamage, TauMetric Corp, steve@taumet.com
boyd@necisa.ho.necisa.oz (Boyd Roberts) (05/30/90)
In article <3078@goanna.cs.rmit.oz.au> ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) writes: | |The problem I've often had is that I have a data structure containing |some pointers, and *I* have filled some of them in (using strdup()) |and the caller preset some of them to defaults. Now I'm going to change |one of them. Should I free it? If *I* allocated it, certainly, there |isn't any other copy of the pointer. If the *caller* allocated it |*and* the caller hasn't any other copy of the pointer *and* it was |allocated using malloc() then it would be a good idea to free it, but |if -- the caller wants to keep it |or -- it was a string literal |or -- it came from something other than malloc() |then it should _not_ be given to free(), and checking for NULL isn't |going to help me. I've been driven to two extremes, neither of which Well, once you've coded yourself into a corner all bets are off. Choose a better algorithm, one that has all the pointers in a free-able state. The general case of `should I free this thing returned by a library routine' is handled by RTFM. TFM should state what storage class the object returned is. If it's malloc()'d it should then also be clear whether the object is free()'d by a companion function `finished_with_this_thing(p)', or whether it is safe to just free() it. I can't see there's much of a problem with the standard libraries. Boyd Roberts boyd@necisa.ho.necisa.oz.au ``When the going gets wierd, the weird turn pro...''
brnstnd@stealth.acf.nyu.edu (05/30/90)
In article <3078@goanna.cs.rmit.oz.au> ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) writes: [ on the general problem of how to tell if an object is no longer ] [ being pointed to ] > Can anyone suggest a better way of tackling this problem in portable C? Your second solution does the job most of the time: keep a count next to each pointer. With a disciplined style such as is enforced by, say, C++ or a good macro set, you'll never forget to deal with the count. However, you do run into a problem with pointer loops: some number of structures, each containing a pointer to the next one in a circle, and none of which you actually need. There are solutions to this fundamental problem, for which I refer you to Knuth's discussion of Lists. Most of the time you don't need general List structures, and there's some way to modify your design so that it's always clear when you can free a pointer. One common technique is to do as little allocation as possible in subroutines; whenever you do allocate something, you must deallocate it in the same block. This fails only when a parent can't predict how much memory a child will need, which is rare in practice. ---Dan
ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) (05/30/90)
In article <1074:May3000:24:1990@stealth.acf.nyu.edu>, brnstnd@stealth.acf.nyu.edu writes: > In article <3078@goanna.cs.rmit.oz.au> ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) writes: > [ on the general problem of how to tell if an object is no longer ] > [ being pointed to ] > > Can anyone suggest a better way of tackling this problem in portable C? > Your second solution does the job most of the time: keep a count next to > each pointer. With a disciplined style such as is enforced by, say, C++ > or a good macro set, you'll never forget to deal with the count. This doesn't quite address my problem. Obviously, if I am in total control of a program, I can easily add and maintain counts. I am quite familiar with garbage collectors and have written several. My real problem is how can I write library packages so that it is easy for *other* people using them to follow whatever protocol is necessary. In this case, it seems to require the package users to maintain counts themselves so they can pass them on. C++ is another language. I simply do not have the option of using it, because most of the computers I have access to haven't got it installed, and I'm not in control of them. For my *own* purposes, using a garbage collector is *more* portable, because the C garbage collector that came over the net works on every kind of machine _I_ want to use. (It _does_ work on Encores after all.) -- "A 7th class of programs, correct in every way, is believed to exist by a few computer scientists. However, no example could be found to include here."
ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) (05/30/90)
In article <1739@necisa.ho.necisa.oz>, boyd@necisa.ho.necisa.oz (Boyd Roberts) writes: > In article <3078@goanna.cs.rmit.oz.au> ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) writes: [when is it safe to deallocate something] > Well, once you've coded yourself into a corner all bets are off. Choose > a better algorithm, one that has all the pointers in a free-able state. Whether something is freeable is NOT a property of the algorithm which has to make the immediate decision. It is a property of the program that USES the algorithm. If you're writing a library function, you simply haven't any control over the code that uses your function. > I can't see there's much of a problem with the standard libraries. The question had nothing to do with the standard libraries. -- "A 7th class of programs, correct in every way, is believed to exist by a few computer scientists. However, no example could be found to include here."
brnstnd@stealth.acf.nyu.edu (05/31/90)
In article <3102@goanna.cs.rmit.oz.au> ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) writes: > In article <1074:May3000:24:1990@stealth.acf.nyu.edu>, brnstnd@stealth.acf.nyu.edu writes: [ some general comments on how to deal with the multiple-pointer ] [ freeing problem ] > This doesn't quite address my problem. Well, what about my last paragraph, which says what I do in practice? Namely: Whatever you allocate inside a routine, you also deallocate inside that routine. If your memory needs are variable, provide enough information to your callers that they can allocate for you. (This is called ``passing the buck.'') If you do need to keep allocated memory around between calls, only use that space internally; don't pass it up to your parent. > My real > problem is how can I write library packages so that it is easy for > *other* people using them to follow whatever protocol is necessary. UNIX library routines generally either require the caller to provide a pointer to the result, or keep the information in a static area that's erased on each call. Both cases match the ``deallocate what you allocate'' philosophy. ---Dan
richard@aiai.ed.ac.uk (Richard Tobin) (05/31/90)
In article <1736@necisa.ho.necisa.oz> boyd@necisa.ho.necisa.oz (Boyd Roberts) writes: >When I see a C library I expect it to address itself to the precise >problem at hand and nothing more. When I see a C library I expect it to implement the functions defined in the C standard. (Well, not really of course. But maybe someday.) -- Richard -- Richard Tobin, JANET: R.Tobin@uk.ac.ed AI Applications Institute, ARPA: R.Tobin%uk.ac.ed@nsfnet-relay.ac.uk Edinburgh University. UUCP: ...!ukc!ed.ac.uk!R.Tobin
richard@aiai.ed.ac.uk (Richard Tobin) (05/31/90)
In article <3078@goanna.cs.rmit.oz.au> ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) writes:
[Description of the all-too-common problem of not knowing whether it's safe
to free something.]
One approach (which of course only solves part of the problem) is to
write your own allocator, with a free() function that ignores attempts
to free space that it didn't allocate. It can do this in various
ways, such as looking at the pointer to see whether it's in the range
of addresses it allocates (I suppose this is not strictly portable, as
it will involve comparing pointers to different objects, but maybe you
don't care about *that* sort of processor).
This of course will further enrage those people who object to free(0),
who needn't bother flaming about sloppy programming, thank you.
-- Richard
--
Richard Tobin, JANET: R.Tobin@uk.ac.ed
AI Applications Institute, ARPA: R.Tobin%uk.ac.ed@nsfnet-relay.ac.uk
Edinburgh University. UUCP: ...!ukc!ed.ac.uk!R.Tobin
peter@ficc.ferranti.com (Peter da Silva) (05/31/90)
In article <3466:May3022:56:1890@stealth.acf.nyu.edu> brnstnd@stealth.acf.nyu.edu (Dan Bernstein) writes: > Namely: Whatever you allocate inside a routine, you also deallocate > inside that routine. If your memory needs are variable, provide enough > information to your callers that they can allocate for you. (This is > called ``passing the buck.'') I disagree with this entirely. If you return a variable amount of data to your parent, there are two ways to go about it. First, you can do it like "read", where you return multiple times (saving state between calls) until all the information is returned. This is appropriate when the amount of data you have to pass up is unbounded or at least large in comparison with avaiable memory. Otherwise, returning a malloced chunk of memory is fine. Generally, you should provide a routine to dispose of that memory, so you can change the allocation strategy without letting the parent know (say, you find that a single static array is enough, or you want to cache stuff for efficiency). Fopen/fclose is an example of this type of interface. -- `-_-' Peter da Silva. +1 713 274 5180. <peter@ficc.ferranti.com> 'U` Have you hugged your wolf today? <peter@sugar.hackercorp.com> @FIN Dirty words: Zhghnyyl erphefvir vayvar shapgvbaf.
boyd@necisa.ho.necisa.oz (Boyd Roberts) (06/01/90)
In article <3103@goanna.cs.rmit.oz.au> ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) writes: > >Whether something is freeable is NOT a property of the algorithm which has >to make the immediate decision. It is a property of the program that USES >the algorithm. If you're writing a library function, you simply haven't >any control over the code that uses your function. > Exactly, you don't have control over what your caller does. That's not your problem, it's the caller's. The issue is in defining an _interface_. If it's ill or badly defined then you've got major problems. A library routine must have a well defined _interface_. The caller is bound to abide by the interface. If the caller doesn't, the routine will have its revenge (thanks Henry). The library routine should state that the objects returned are either: 1. Static and should not be free()'d. 2. malloc()'d and should be free()'d by the caller. 3. Allocated and cleaned up by a finished_with_this_object(p) call. Those are the choices. If you don't play by the rules, all bets are off. Boyd Roberts boyd@necisa.ho.necisa.oz.au ``When the going gets wierd, the weird turn pro...''
ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) (06/01/90)
In article <1743@necisa.ho.necisa.oz>, boyd@necisa.ho.necisa.oz (Boyd Roberts) writes: > The library routine should state that the objects returned are either: > 1. Static and should not be free()'d. > 2. malloc()'d and should be free()'d by the caller. > 3. Allocated and cleaned up by a finished_with_this_object(p) call. > Those are the choices. If you don't play by the rules, all bets are off. Somewhere the context seems to have been lost. I wasn't talking about library routines to create single objects, but library routines to manage a collection of objects (think of hsearch and the like) where the objects 4. Are sometimes things that the caller provided (whatever they are) and sometimes things that the package mallocked I mean, I'm talking about something that may be given hundreds of default "objects", and just change one or two. Copying _everything_ so that everything would deserve freeing is obviously not a nice thing. C++ would in effect tag each of the strings or other default objects with its own deallocation routine, but it still would not be appropriate for the collection maintenance routines to "destroy" objects that _they_ didn't "new". Basically, the problem is that a mathematically clean interface design can sometimes be made much more complicated if your language does not support automatic storage management. Oh well, if I want Scheme I know where to find it. -- "A 7th class of programs, correct in every way, is believed to exist by a few computer scientists. However, no example could be found to include here."
brnstnd@stealth.acf.nyu.edu (06/01/90)
In article <9YT3MP@xds13.ferranti.com> peter@ficc.ferranti.com (Peter da Silva) writes: > In article <3466:May3022:56:1890@stealth.acf.nyu.edu> brnstnd@stealth.acf.nyu.edu (Dan Bernstein) writes: > > Namely: Whatever you allocate inside a routine, you also deallocate > > inside that routine. If your memory needs are variable, provide enough > > information to your callers that they can allocate for you. (This is > > called ``passing the buck.'') > I disagree with this entirely. If you return a variable amount of data to > your parent, there are two ways to go about it. [ 1. like read() ] [ 2. like fopen()/fclose() ] read() falls under the ``provide enough information to your callers that they can allocate for you.'' The way fopen() and fclose() allocate FILEs falls under the sentence you left out: ``If you do need to keep allocated memory around between calls, only use that space internally; don't pass it up to your parent.'' (The pointer that fopen() passes up isn't defined as a pointer to malloc()ed space, isn't always such a pointer, and may not be dereferenced or freed portably; perhaps I should have said ``don't tell your parent how to find or use the space.'') So what are you disagreeing with? I don't think I'm totally off base, because Boyd Roberts made the same three-way classification in a simultaneous article. ---Dan
peter@ficc.ferranti.com (Peter da Silva) (06/02/90)
In article <270:Jun113:33:1590@stealth.acf.nyu.edu> brnstnd@stealth.acf.nyu.edu (Dan Bernstein) writes: > In article <9YT3MP@xds13.ferranti.com> peter@ficc.ferranti.com (Peter da Silva) writes: > > In article <3466:May3022:56:1890@stealth.acf.nyu.edu> brnstnd@stealth.acf.nyu.edu (Dan Bernstein) writes: > > > Namely: Whatever you allocate inside a routine, you also deallocate > > > inside that routine. If your memory needs are variable, provide enough > > > information to your callers that they can allocate for you. (This is > > > called ``passing the buck.'') > > I disagree with this entirely. > So what are you disagreeing with? The paragraph quoted above. Consider a routine "readline(fp)". this (hypothetical) routine reads in a line of text and allocates and returns a pointer to it. It appears that you do not believe that this is a reasonable thing to do. Please correct me if I am misinterpreting your message. Consider the commonly implemented routine "strdup" that allocates a copy of a string and returns a pointer to the copy. The model of pulling fully-formed "things" out of a pool, manipulating them, and eventually dropping them back in is perfectly valid and often useful. > I don't think I'm totally off base, > because Boyd Roberts made the same three-way classification in a > simultaneous article. He didn't make any hard-and-fast rule about never returning a malloc-ed chunk of memory to ones parent. Just make sure that the interface is properly documented and consistent. -- `-_-' Peter da Silva. +1 713 274 5180. <peter@ficc.ferranti.com> 'U` Have you hugged your wolf today? <peter@sugar.hackercorp.com> @FIN Dirty words: Zhghnyyl erphefvir vayvar shapgvbaf.
boyd@necisa.ho.necisa.oz (Boyd Roberts) (06/04/90)
In article <WUU3BX6@xds13.ferranti.com> peter@ficc.ferranti.com (Peter da Silva) writes: > >He didn't make any hard-and-fast rule about never returning a malloc-ed >chunk of memory to ones parent. Just make sure that the interface is >properly documented and consistent. >-- Correct. Return what you like and define what the caller must do with the object when the caller is finished with it. Writing code that doesn't return objects allocated on the fly can really get in the way of writing clean code. Boyd Roberts boyd@necisa.ho.necisa.oz.au ``When the going gets wierd, the weird turn pro...''
boyd@necisa.ho.necisa.oz (Boyd Roberts) (06/05/90)
In article <3124@goanna.cs.rmit.oz.au> ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) writes: >Somewhere the context seems to have been lost. I wasn't talking about >library routines to create single objects, but library routines to manage >a collection of objects (think of hsearch and the like) where the objects > 4. Are sometimes things that the caller provided (whatever they are) > and sometimes things that the package mallocked As I've said before, what you require is an interface. A clearly defined, clean interface. No more, no less. You'll just have to bite the bullet for existing routines that don't provide the interface you want. For future routines, you define the interface. Just define the interface. Boyd Roberts boyd@necisa.ho.necisa.oz.au ``When the going gets wierd, the weird turn pro...''
brnstnd@stealth.acf.nyu.edu (06/06/90)
In article <WUU3BX6@xds13.ferranti.com> peter@ficc.ferranti.com (Peter da Silva) writes: > In article <270:Jun113:33:1590@stealth.acf.nyu.edu> brnstnd@stealth.acf.nyu.edu (Dan Bernstein) writes: [ and we argue: ] > > > > Namely: Whatever you allocate inside a routine, you also deallocate > > > > inside that routine. If your memory needs are variable, provide enough > > > > information to your callers that they can allocate for you. (This is > > > > called ``passing the buck.'') > > > I disagree with this entirely. > > So what are you disagreeing with? > The paragraph quoted above. > Consider a routine "readline(fp)". this (hypothetical) routine reads in > a line of text and allocates and returns a pointer to it. It appears that > you do not believe that this is a reasonable thing to do. C'mon, Peter, this is the third time you've just left out the third part of my paragraph. It's perfectly fine to keep allocated memory around between calls, and even pass up a pointer to that memory, *provided* that the pointer isn't *defined* by your interface as a pointer to *allocated* memory. In other words, you must provide an unreadline() to free the memory. > Consider the commonly implemented routine "strdup" that allocates a copy > of a string and returns a pointer to the copy. This is a mistake, because the pointer is *defined* by the interface as a pointer to *allocated* memory. Either the parent should malloc() and strcpy(), or strdup() should also have an unstrdup() to free the memory. > > I don't think I'm totally off base, > > because Boyd Roberts made the same three-way classification in a > > simultaneous article. > He didn't make any hard-and-fast rule about never returning a malloc-ed > chunk of memory to ones parent. Just make sure that the interface is > properly documented and consistent. Again, it doesn't matter whether internally you malloced the memory or used a static area. Just never return a chunk of memory that's *defined* to be malloc()ed. (This is what he said.) To put it differently: Never, ever, ever pass internally malloc()ed memory up to your parent (this is what I said)---but, as always in C, feel free to apply the as-if rule. ---Dan
martin@mwtech.UUCP (Martin Weitzel) (06/07/90)
In article <17486:Jun611:18:1690@stealth.acf.nyu.edu> brnstnd@stealth.acf.nyu.edu (Dan Bernstein) writes: >In article <WUU3BX6@xds13.ferranti.com> peter@ficc.ferranti.com (Peter da Silva) writes: [part of discussion deleted] > >> Consider the commonly implemented routine "strdup" that allocates a copy >> of a string and returns a pointer to the copy. > >This is a mistake, because the pointer is *defined* by the interface as >a pointer to *allocated* memory. Either the parent should malloc() and >strcpy(), or strdup() should also have an unstrdup() to free the memory. Mistake of whom? The designer of the library? Though I surely appreciate information hiding and the clean constructor/destructor approach of C++, concerning some relative `low level' operations I can see a trade-off: Either you are willing to `unobscure' things a little and loose the potential to change your implementation (this is what the designer of "strdup" did) or you may get lots of "unallocating" request, most of which boil down to: #define unstrdup free #define unreadline free .... Note that I left out macro parameters here, so that even the adress of some `un'-allocating operation may be passed around without writing functions. Of course you can write `real' functions: void unstrdup(char *s) { free(s); } void unreadline(char *s) { free(s); } .... which has the disadvantage of beeing slower and the advantage that the programmer will not get confused by some source level debuggers. Note that I'll not recommend the one over the other! It's a trade-off and it's not my task to judge the designer of "strdup". One tiny little bit of criticism is that "strdup" should be included in the "malloc/ calloc/free" man page ... (if I were to write the manuals :-)), but that only emphasizes Peters point a little: Make sure that it is documented *and* try to stomp the reader of the documentation onto it. -- Martin Weitzel, email: martin@mwtech.UUCP, voice: 49-(0)6151-6 56 83
peter@ficc.ferranti.com (Peter da Silva) (06/07/90)
In article <17486:Jun611:18:1690@stealth.acf.nyu.edu> brnstnd@stealth.acf.nyu.edu (Dan Bernstein) writes: > C'mon, Peter, this is the third time you've just left out the third part > of my paragraph. Perhaps I misunderstood what you were talking about, but it didn't seem to contain any useful information. You have certainly missed *my* point... > It's perfectly fine to keep allocated memory around > between calls, and even pass up a pointer to that memory, *provided* > that the pointer isn't *defined* by your interface as a pointer to > *allocated* memory. In other words, you must provide an unreadline() to > free the memory. That's what I don't agree with. It's perfectly fine to have a routine return malloc-ed memory, so long as it's defined as returning allocated memory. You're saying that you need to have an explicit destructor matching any constructor. It may be desirable to do this for certain interfaces, but making it a hard and fast rule that you have to do this makes about as much sense as banning functions with side effects. [ in question: strdup(s) char *s; { char *t = malloc(strlen(s)+1); if(t) strcpy(t, s); return t; } ] > This is a mistake, because the pointer is *defined* by the interface as > a pointer to *allocated* memory. Either the parent should malloc() and > strcpy(), or strdup() should also have an unstrdup() to free the memory. Not at all. If you have code that's full of: if(foocopy = malloc(strlen(foo)+1)) strcpy(foocopy, foo); Why not declutter your code with: foocopy = strdup(foo); Yes, you can clutter things up again with strfree(), but now you have to treat strings allocated with strdup differently from strings explicitly malloced (say with: if(buf = malloc(strlen(path) + strlen(fname) + 2)) sprintf(buf, "%s/%s", path, fname); or the equivalent), and so on. And are you going to require that none of these new objects are ever returned from another function? > To put it differently: Never, ever, ever pass internally malloc()ed > memory up to your parent (this is what I said)---but, as always in C, > feel free to apply the as-if rule. To put it differently: it's usually a good idea to build creator/destructor functions for objects, but there is no need to make it a hard and fast rule. And I don't think Boyd said anything differently. -- `-_-' Peter da Silva. +1 713 274 5180. <peter@ficc.ferranti.com> 'U` Have you hugged your wolf today? <peter@sugar.hackercorp.com> @FIN Dirty words: Zhghnyyl erphefvir vayvar shapgvbaf.
boyd@necisa.ho.necisa.oz (Boyd Roberts) (06/08/90)
In article <17486:Jun611:18:1690@stealth.acf.nyu.edu> brnstnd@stealth.acf.nyu.edu (Dan Bernstein) writes: > >Again, it doesn't matter whether internally you malloced the memory or >used a static area. Just never return a chunk of memory that's *defined* >to be malloc()ed. (This is what he said.) > No, that's not what I said. I said you could return what you liked as long as you defined what to do with the object when you'd finished with it. >To put it differently: Never, ever, ever pass internally malloc()ed >memory up to your parent (this is what I said)---but, as always in C, >feel free to apply the as-if rule. > Totally, incorrect. I'll return whatever I like. There is no problem. When I return a simple malloc()'d object my interface definition will say `call free() to free it'. By simple, I mean an object that will be completely free()'d by the one malloc call. If the object is complex, then I'll use a finished_with_this_thing(p) function. But only for complex objects, such as: struct tricky { int flags; char *name; }; Because, just calling malloc() will do the wrong thing. It won't free what `name' points to. So free_tricky() goes: free_tricky(p) struct tricky *p; { free(p->name); free((char *)p); } It is overengineering to have a free function for every type of object. It the object is derived from a simple malloc, the free function is free(). Sure, you may like the style of it, but who needs code full of redundancies? free_special_thing(p) char *p; { free(p); } No, use free() in line. Define the interface and stick by it. Boyd Roberts boyd@necisa.ho.necisa.oz.au ``When the going gets wierd, the weird turn pro...''