funkstr@ucscb.ucsc.edu (Larry Hastings) (10/01/90)
Seeing as how people are just now discussing using heap memory after it's been free()d, I thought I'd suggest this. It's something that either I or my boss came up with (I forget who). And, yes, the whole purpose of its existence is to have a "side-effect", but this one is IMHO worth it: #define smart_free(x) { if (x != NULL) { free(x); x = NULL; } } This takes care of two problems: 1) If you access a pointer after smart_free()ing it, you are dereferencing a null pointer, which gives you a lovely error message (except on DOS, where I am doomed to stay). 2) If you smart_free() something twice, nothing bad happens. (The pointer gets set to NULL the first time, and gets blocked by the "if" the second time.) Just remember that this is a macro when you call it, and don't do anything funny like smart_free(*x++), and those heap manager problems will go away. This joins an entire brace of "smart_" functions (smart_calloc(), smart_open(), smart_close() and so on) which act "intelligently". This mainly means they call the function they replace (smart_write() calls write()) and check the return value -- if there's anything wrong, they abort. -- larry hastings, the galactic funkster, funkstr@ucscb.ucsc.edu I don't speak for Knowledge Dynamics or UC Santa Cruz, nor do they speak for me The 4th law of Robotics (courtesy of Lore Shoberg): "A robot must encourage proper dental hygiene, except where such encouragement would interfere with the 0th, 1st, 2nd, and 3rd laws."
cpcahil@virtech.uucp (Conor P. Cahill) (10/01/90)
In article <7365@darkstar.ucsc.edu> funkstr@ucscb.ucsc.edu (Larry Hastings) writes: > >#define smart_free(x) { if (x != NULL) { free(x); x = NULL; } } > >This takes care of two problems: > 1) If you access a pointer after smart_free()ing it, you are > dereferencing a null pointer, which gives you a lovely error message > (except on DOS, where I am doomed to stay). Only if you use the same pointer. If the pointer had been copied somewhere else (or a pointer within that area had been used) it still would point to the area that had been freed. > 2) If you smart_free() something twice, nothing bad happens. (The > pointer gets set to NULL the first time, and gets blocked by the > "if" the second time.) I don't think you should do this. If you are calling free twice with the same pointer, something is wrong. I would prefer an abort, so people could track down the problem, not hide it. A while back I put together a debugging library for malloc and it's associated functions which was posted to comp.sources.unix back in may/june. This library purposely trashes data pointed to by the free'd pointer to ensure that you aren't using a freed pointer (in addition to lots of other checks, like overrunning the amount of malloc data that you asked for). If you are working with malloc'd data, you might want to get a copy of the library. It makes solving most malloc problem easy. -- Conor P. Cahill (703)430-9247 Virtual Technologies, Inc., uunet!virtech!cpcahil 46030 Manekin Plaza, Suite 160 Sterling, VA 22170
pds@lemming.webo.dg.com (Paul D. Smith) (10/01/90)
In article <7365@darkstar.ucsc.edu> funkstr@ucscb.ucsc.edu (Larry Hastings) writes: [] #define smart_free(x) { if (x != NULL) { free(x); x = NULL; } } It should be pointed out that in ANSI C free(NULL) is defined, and is legal (any conforming implementation of free() must ignore being passed a NULL pointer). So, you could save yourself some execution time (if you have an ANSI compiler) by writing: #define smart_free(x) { free(x); x = NULL; } (you may also want to peruse the seperate thread in this newsgroup on multi-statement macros and `while(0)' loops, etc.) -- paul ----- ------------------------------------------------------------------ | Paul D. Smith | pds@lemming.webo.dg.com | | Data General Corp. | | | Network Services Development | "Pretty Damn S..." | | Open Network Applications Department | | ------------------------------------------------------------------
rtidd@ccels3 (Randy Tidd) (10/01/90)
In article <1990Oct01.020420.3401@virtech.uucp> cpcahil@virtech.UUCP (Conor P. Cahill) writes: > > [ ... ] > >A while back I put together a debugging library for malloc and it's >associated functions which was posted to comp.sources.unix back in may/june. >This library purposely trashes data pointed to by the free'd pointer to >ensure that you aren't using a freed pointer (in addition to lots >of other checks, like overrunning the amount of malloc data that you >asked for). > >If you are working with malloc'd data, you might want to get a copy of >the library. It makes solving most malloc problem easy. I checked comp.sources.unix on my news server and it doesn't have ANY messages in it, much less the ones from may/june. If anyone has a copy of the routines Conor talks about here, can they mail them to me? I tried mailing him directly but it bounced. Thanks in advance! Randy Tidd rtidd@mwunix.mitre.org "It's easier to get forgiveness than permission."
roger@everexn.com (Roger House) (10/02/90)
In <7365@darkstar.ucsc.edu> funkstr@ucscb.ucsc.edu (Larry Hastings) writes: >#define smart_free(x) { if (x != NULL) { free(x); x = NULL; } } >This takes care of two problems: > 1) If you access a pointer after smart_free()ing it, you are > dereferencing a null pointer, which gives you a lovely error message > (except on DOS, where I am doomed to stay). > 2) If you smart_free() something twice, nothing bad happens. (The > pointer gets set to NULL the first time, and gets blocked by the > "if" the second time.) The ANSI C standard states that when the argument to free is a null pointer, nothing happens. So if your free function is ANSI, there is no need to check for NULL to avoid calling free. As for setting the pointer to NULL after freeing, I have done this for quite some time, and it has quickly caught several bugs that could have turned into nightmares. However, I define a function, myfree, so I don't need to worry about side-effects (the argument to the function is void **). Another ad- vantage of having a function is that then all heap operations are funneled through a couple of my functions (mymalloc, myfree, myrealloc, etc.) This is very useful if you decide you want to do things like keep track of the maximum amount of heap memory in use at a given time, etc. Also, on occasion I use test versions of mymalloc and myfree which do things like this: my malloc saves all its return values in a table, and when myfree is called it checks that the address of the space to be freed is in the table, and then removes it from the table. This mechanism has also saved me from a few nasty heap bugs. Roger House
6sigma2@polari.UUCP (Brian Matthews) (10/02/90)
In article <7365@darkstar.ucsc.edu> funkstr@ucscb.ucsc.edu (Larry Hastings) writes: |#define smart_free(x) { if (x != NULL) { free(x); x = NULL; } } A run-time solution to a compile-time problem. Blecch. -- Brian L. Matthews blm@6sceng.UUCP
cpcahil@virtech.uucp (Conor P. Cahill) (10/02/90)
In article <PDS.90Oct1095707@lemming.webo.dg.com> pds@lemming.webo.dg.com (Paul D. Smith) writes: >It should be pointed out that in ANSI C free(NULL) is defined, and is >legal (any conforming implementation of free() must ignore being >passed a NULL pointer). While this is a true statement, I would never recommend that one take advantage of this feature. If you know the variable is NULL don't pass it to free. The performance cost of the following statement: if( ptr != NULL ) free(ptr); as opposed to: free(ptr); will be unmeasurable in most, if not all, circumstances. In addition, by adding the if() you get code that is portable across all implementations. Anyway, this is really a moot point because you should never be calling free() unless you KNOW WHAT IS IN THE PTR that you will be passing to it. If you don't, then something is wrong with your code. -- Conor P. Cahill (703)430-9247 Virtual Technologies, Inc., uunet!virtech!cpcahil 46030 Manekin Plaza, Suite 160 Sterling, VA 22170
kdq@demott.COM (Kevin D. Quitt) (10/02/90)
In article <PDS.90Oct1095707@lemming.webo.dg.com> pds@lemming.webo.dg.com (Paul D. Smith) writes: >In article <7365@darkstar.ucsc.edu> funkstr@ucscb.ucsc.edu (Larry Hastings) writes: > > >[] #define smart_free(x) { if (x != NULL) { free(x); x = NULL; } } > > >It should be pointed out that in ANSI C free(NULL) is defined, and is >legal (any conforming implementation of free() must ignore being >passed a NULL pointer). > >So, you could save yourself some execution time (if you have an ANSI >compiler) by writing: > >#define smart_free(x) { free(x); x = NULL; } > Actually, execution time will be saved by the original definition, since it avoids the call/return overhead in invoking free when the pointer is null. This was discussed a month or so ago, and timings were published. -- _ Kevin D. Quitt demott!kdq kdq@demott.com DeMott Electronics Co. 14707 Keswick St. Van Nuys, CA 91405-1266 VOICE (818) 988-4975 FAX (818) 997-1190 MODEM (818) 997-4496 PEP last 96.37% of all statistics are made up.
pds@lemming.webo.dg.com (Paul D. Smith) (10/03/90)
In article <1990Oct02.132313.6659@virtech.uucp> cpcahil@virtech.uucp (Conor P. Cahill) writes: [] In article <PDS.90Oct1095707@lemming.webo.dg.com> pds@lemming.webo.dg.com (Paul D. Smith) writes: [] >It should be pointed out that in ANSI C free(NULL) is defined, and is [] >legal (any conforming implementation of free() must ignore being [] >passed a NULL pointer). [] [] While this is a true statement, I would never recommend that one [] take advantage of this feature. If you know the variable is NULL [] don't pass it to free. Obviously if you know it's NULL, why would you call free()? This is a no-brainer. The problem arises when you *don't* know if it's NULL or not -- I thought that's why we have the if() test! [] The performance cost of the following statement: [] [] if( ptr != NULL ) [] free(ptr); [] [] as opposed to: [] [] free(ptr); [] [] will be unmeasurable in most, if not all, circumstances. Well, IMHO, this is just silliness. What are you saying, that no one should use ANSI extensions if they have an ANSI compiler just because they didn't *used* to be legal? While your simple case might indeed not be much of a performance hit, what about something like: #define ARRAY_LEN 10000 char *array[ARRAY_LEN], *ap; int i; for (ap = array, i = 0; i < ARRAY_LEN; ++i, ++ap) { if (ap != NULL) free(ap) } Now, *this* is a significant performance hit, if you consider an extra 10000 comparisons. Before you retort about using memset() or bzero(), please read the FAQ on NULL pointers ... and no, I wouldn't do it this way either, but it is not hard to see where extraneous tests *can* cause some loss of performance, not to mention loss of programmer time typing them in! Besides, I think it is correct behavior for free() to handle a NULL pointer, and it should have done all along. [] Anyway, this is really a moot point because you should never be calling [] free() unless you KNOW WHAT IS IN THE PTR that you will be passing to it. [] If you don't, then something is wrong with your code. So what are you saying, that in the above case I should have a bitmap with ARRAY_LEN bits which tells me which of the pointers in `array' actually have values and which are NULL? More silliness. [] In addition, by adding the if() you get code that is portable [] across all implementations. Ok, now *this* is a valid concern. So, rewrite the macro in question: #ifdef __STDC__ #define smart_free(_p) { free(_p); (_p)=NULL; } #else #define smart_free(_p) { if ((_p)!=NULL) { free(_p); (_p)=NULL; } } #endif -- paul ----- ------------------------------------------------------------------ | Paul D. Smith | pds@lemming.webo.dg.com | | Data General Corp. | | | Network Services Development | "Pretty Damn S..." | | Open Network Applications Department | | ------------------------------------------------------------------
jeenglis@alcor.usc.edu (Joe English Muffin) (10/04/90)
pds@lemming.webo.dg.com (Paul D. Smith) writes: >Well, IMHO, this is just silliness. What are you saying, that no one >should use ANSI extensions if they have an ANSI compiler just because >they didn't *used* to be legal? That's a valid concern. There are a LOT of systems out there that don't have an ANSI C compiler, and there will be for a long long time to come. ... > #define ARRAY_LEN 10000 > char *array[ARRAY_LEN], *ap; > int i; > for (ap = array, i = 0; i < ARRAY_LEN; ++i, ++ap) > { > if (ap != NULL) > free(ap) > } >Now, *this* is a significant performance hit, if you consider an extra >10000 comparisons. Doing the test will most likely INCREASE performance: a test is usually cheaper than a function call, and free() is not a trivial function. Ever profiled a program that made heavy use of malloc() & free()? They eat up a lot of cycles. (Unless the RTL is implemented really well; personally, I've never seen a fast implementation of malloc() & free().) --Joe English jeenglis@alcor.usc.edu
cpcahil@virtech.uucp (Conor P. Cahill) (10/04/90)
It appears you took my comments as a personal attack, which they were not meant to be. However, you raised some points that I will respond to... In article <PDS.90Oct3103126@lemming.webo.dg.com> pds@lemming.webo.dg.com (Paul D. Smith) writes: >In article <1990Oct02.132313.6659@virtech.uucp> cpcahil@virtech.uucp (Conor P. Cahill) writes: >[] While this is a true statement, I would never recommend that one >[] take advantage of this feature. If you know the variable is NULL >[] don't pass it to free. > >Obviously if you know it's NULL, why would you call free()? This is a >no-brainer. The problem arises when you *don't* know if it's NULL or >not -- I thought that's why we have the if() test! You say this and then you make an argument for calling free with a NULL anyway? >[] The performance cost of using if( ptr!= NULL) free(ptr) as opposed to >[] free(ptr) (with no if) will be unmeasurable in most if not all >[] circumstances. > >Well, IMHO, this is just silliness. What are you saying, that no one >should use ANSI extensions if they have an ANSI compiler just because >they didn't *used* to be legal? I am saying that the if(ptr!=NULL) is almost a "free" operation (using only one or two instructions on many machines). If you use it, the code will work correctly on ANSI and pre-ANSI, and the peformance difference will not be measurable. (The key word is measurable). >While your simple case might indeed not be much of a performance hit, >what about something like: > > #define ARRAY_LEN 10000 > char *array[ARRAY_LEN], *ap; > int i; > > for (ap = array, i = 0; i < ARRAY_LEN; ++i, ++ap) > { > if (ap != NULL) > free(ap) > } > >Now, *this* is a significant performance hit, if you consider an extra No it is not. Actually, if array has greater than a small percentage of NULL pointers, the savings of the function call by the if test will be substantial. Rember, comparisons (especially comparisons against zero) are a very cheap operation. Function calls are not. >10000 comparisons. Before you retort about using memset() or bzero(), >please read the FAQ on NULL pointers ... and no, I wouldn't do it this I didn't meantion bzero or memset anywhere so I'm not sure why the reference is here. >way either, but it is not hard to see where extraneous tests *can* >cause some loss of performance, not to mention loss of programmer time >typing them in! Before you say it *can*, try it and you will find that you can't measure the difference in a *real* program. >Besides, I think it is correct behavior for free() to handle a NULL >pointer, and it should have done all along. I don't, but that is just personal opinion and both of us can have our own. >[] Anyway, this is really a moot point because you should never be calling >[] free() unless you KNOW WHAT IS IN THE PTR that you will be passing to it. >[] If you don't, then something is wrong with your code. > >So what are you saying, that in the above case I should have a bitmap >with ARRAY_LEN bits which tells me which of the pointers in `array' >actually have values and which are NULL? More silliness. No. if you assigned null to all the pointers originally, then you only need to call free if the pointer is not NULL. >[] In addition, by adding the if() you get code that is portable >[] across all implementations. > >Ok, now *this* is a valid concern. So, rewrite the macro in question: > >#ifdef __STDC__ >#define smart_free(_p) { free(_p); (_p)=NULL; } >#else >#define smart_free(_p) { if ((_p)!=NULL) { free(_p); (_p)=NULL; } } >#endif While this is a valid construct, I still maintain that you won't be able to measure the difference in execution time and therefore make your code more complex needlessly. -- Conor P. Cahill (703)430-9247 Virtual Technologies, Inc., uunet!virtech!cpcahil 46030 Manekin Plaza, Suite 160 Sterling, VA 22170
browns@iccgcc.decnet.ab.com (Stan Brown, Oak Road Systems) (10/05/90)
In article <7365@darkstar.ucsc.edu>, funkstr@ucscb.ucsc.edu (Larry Hastings) writes: > [ ...] > > #define smart_free(x) { if (x != NULL) { free(x); x = NULL; } } <<sigh>> How quickly they forget... From the thread on how to do if's in a macro: #define smart_free(x) ( ((x) !=NULL) && (free(x),0) ) From the thread on the meaning of NULL: #define smart_free(x) ( ((x) != 0) && (free(x),0) ) which collapses to #define smart_free(x) ( (x) && (free(x),0) ) Now, somebody please remind ME: Is "(free(x),0)" what the netsters came up with as the best wat to do a void function, or should it be something else? BTW, I'm not taking sides on whether one _should_ test the value of x before calling free(x). My point is just that I hate to see all the other good comments about macros and NULL disappear into oblivion. The above is my own opinion and not attributable to any other person or organization. email: browns@iccgcc.decnet.ab.com Stan Brown, Oak Road Systems, Cleveland, Ohio, U.S.A. (216) 371-0043
gegu@bii.UUCP (Gerhard Gucher) (10/05/90)
> In article <PDS.90Oct3103126@lemming.webo.dg.com>, pds@lemming.webo.dg.com (Paul D. Smith) writes: > #define ARRAY_LEN 10000 > char *array[ARRAY_LEN], *ap; > int i; > > for (ap = array, i = 0; i < ARRAY_LEN; ++i, ++ap) > { > if (ap != NULL) > free(ap) > } > > Now, *this* is a significant performance hit, if you consider an extra > 10000 comparisons. Before you retort about using memset() or bzero(), > please read the FAQ on NULL pointers ... and no, I wouldn't do it this > way either, but it is not hard to see where extraneous tests *can* > cause some loss of performance, not to mention loss of programmer time > typing them in! > > Besides, I think it is correct behavior for free() to handle a NULL > pointer, and it should have done all along. > > >> In addition, by adding the if() you get code that is portable >> across all implementations. > > Ok, now *this* is a valid concern. So, rewrite the macro in question: Let's think a bit about "this significant performance hit". case 1: ap == NULL for > 90% of all cases WE GAIN by saving more than 9000 dummy function calls !! case 2: ap == NULL for 10% ... 90% of all cases WE GAIN by trading function calls for if's ( if's are MUCH cheaper ) case 3: ap == NULL for < 10% of all cases WE LOOSE VERY LITTLE because we can't measure >9000 if's compared to those >9000 fully executed frees. Now again, how was that with that *significant* performance hit ?? And as we all agree (I hope), the gain of portability to non ANSI systems is well worth it anyways. (Keep in mind, most in use systems don't carry ANSI yet ( Mess - DOS doesn't count as a system (:-) ). -- Disclaimer: My employer has nothing to to with this. -- +------------------------------------------------------------------+ | Gerry Gucher uunet!bii!gegu gegu@bii.bruker.com | | Bruker Instruments Inc. Manning Park Billerica MA 01821 | +------------------------------------------------------------------+
rtm@christmas.UUCP (Richard Minner) (10/05/90)
I personally like all `destroy_thing()' functions to quietly accept a non-existent (NULL) `thing'. (After all, what I want is for the thing to be gone, and if it's already not there, that's fine with me. :-) I find all the `if (ptr)' tests cluttersome (not a real word). If the thing really should not be null, I'll do an assert(thing) before destroying it. One particular usage this model simplifies is the multiple create, e.g: thing1 = create_thing(); thing2 = create_thing(); ... thingN = create_thing(); if (!thing1 || !thing2 || ... || !thingN) { destroy_thing(thing1); ... destroy_thing(thingN); <fail> } which to me reads nicely as: "try to get things, if didn't get them all, get rid of any you got." As a final bit, I second the recommendation of using your own `shell' functions around the standard malloc family, rather than macros; it's more flexible (as noted by ??, sorry) and the overhead of the `extra' call is (almost always) insignificant compared to the work the library functions will be doing. -- Richard Minner || {uunet,sun,well}!island!rtm (916) 736-1323 || || Island Graphics Corporation Sacramento, CA ||
seanf@sco.COM (Sean Fagan) (10/05/90)
In article <PDS.90Oct3103126@lemming.webo.dg.com> pds@lemming.webo.dg.com (Paul D. Smith) writes: >While your simple case might indeed not be much of a performance hit, >what about something like: > > #define ARRAY_LEN 10000 > char *array[ARRAY_LEN], *ap; > int i; > for (ap = array, i = 0; i < ARRAY_LEN; ++i, ++ap) > { if (ap != NULL) free(ap); } > >Now, *this* is a significant performance hit, if you consider an extra >10000 comparisons. And now an ANSI compliant library must have free() check for a NULL parameter, which means that, instead of 10000 tests, you are now doing 20000 tests. Yep. Just love those performance increases, don't you? Incidently, in reformating the included text to make news happy, I very nicely got rid of the syntax error (a missing semicolon). Tsk tsk tsk 8-). -- -----------------+ Sean Eric Fagan | "Never knock on Death's door: ring the bell and seanf@sco.COM | run away! Death really hates that!" uunet!sco!seanf | -- Dr. Mike Stratford (Matt Frewer, "Doctor, Doctor") (408) 458-1422 | Any opinions expressed are my own, not my employers'.
kdq@demott.COM (Kevin D. Quitt) (10/07/90)
In article <1990Oct04.110928.16788@virtech.uucp> cpcahil@virtech.uucp (Conor P. Cahill) writes: >It appears you took my comments as a personal attack, which they were not >meant to be. However, you raised some points that I will respond to... > >In article <PDS.90Oct3103126@lemming.webo.dg.com> pds@lemming.webo.dg.com (Paul D. Smith) writes: >>While your simple case might indeed not be much of a performance hit, >>what about something like: >> >> #define ARRAY_LEN 10000 >> char *array[ARRAY_LEN], *ap; >> int i; >> >> for (ap = array, i = 0; i < ARRAY_LEN; ++i, ++ap) >> { >> if (ap != NULL) >> free(ap) >> } >> >>Now, *this* is a significant performance hit, if you consider an extra > >No it is not. Actually, if array has greater than a small percentage >of NULL pointers, the savings of the function call by the if test will >be substantial. Rember, comparisons (especially comparisons against >zero) are a very cheap operation. Function calls are not. > >>10000 comparisons. Before you retort about using memset() or bzero(), >>please read the FAQ on NULL pointers ... and no, I wouldn't do it this On the three systems I'm using, this is faster than the call without the if, not slower! Testing for 0 is *much* faster than the overhead of a function call - which function starts with a test for zero. So if I test first, I pay the penalty for comparing against zero. If it's zero I have a major win; if it's not, I pay a few percent in performance penalty. Have you folks actually tried timing your examples instead of just using gedanken experiments? -- _ Kevin D. Quitt demott!kdq kdq@demott.com DeMott Electronics Co. 14707 Keswick St. Van Nuys, CA 91405-1266 VOICE (818) 988-4975 FAX (818) 997-1190 MODEM (818) 997-4496 PEP last 96.37% of all statistics are made up.
rtm@christmas.UUCP (Richard Minner) (10/08/90)
In article <8026@scolex.sco.COM> seanf (Sean Fagan) writes: >In article <PDS.90Oct3103126@lemming.webo.dg.com> pds@lemming.webo.dg.com (Paul D. Smith) writes: >>Now, *this* is a significant performance hit, if you consider an extra >>10000 comparisons. >And now an ANSI compliant library must have free() check for a NULL >parameter, which means that, instead of 10000 tests, you are now doing 20000 >tests. Yep. Just love those performance increases, don't you? Sorry, I just can't stand it anymore. This is about the fourth or fifth posting talking about `performance' in this way. Isn't someone going to comment? (I guess I am.) Quick Quiz: Is saving an hour of CPU time significant? a) Yes b) No c) Not enough information If you answered a) or b), go back and re-read the chapter on performance and efficiency. If you don't consider the whole job, you can't talk about performance in any meaningful way. E.g. go to Bank of America and tell them how you can save them an hour of CPU time each year. I don't think they'll be very impressed. Tell me how I can cut my image conversion from 80 minutes to 20 and you'll have my full attention. Tell me how I can cut my nightly batch job from 80 minutes to 20 and I might be curious, but won't really care. Please stop talking about `10000 comparisons' as if it meant something. I'm sorry, but you might as well make it 10 million; performance is relative. The time for one more `if' is not signifcant compared to the rest of the work free() has to do. (If you have an implementation of free() for which one test *is* significant, I'd like to know about it. By the way, I don't consider 1% very significant.) As someone recently mentioned, the big performance gains are from good algorithms and design; shaving instructions is the last concern and only when you have good reason to believe you are doing so in a very critical portion of the code. For example, if you have to do 10000 allocations/frees where performance matters, you're probably going to want your own memory manager tuned to your needs, rather than using malloc/free which are quite general and often not the most efficient for a particular task. The ANSI behavior for free() is a good thing. I don't want to read any more complaints about it ;-) -- Richard Minner || {uunet,sun,well}!island!rtm (916) 736-1323 || || Island Graphics Corporation Sacramento, CA ||
msb@sq.sq.com (Mark Brader) (10/09/90)
> While your simple case might indeed not be much of a performance hit, > what about something like: > #define ARRAY_LEN 10000 > char *array[ARRAY_LEN], **ap; > int i; > for (ap = array, i = 0; i < ARRAY_LEN; ++i, ++ap) > { > if (*ap != NULL) > free(*ap); > } /* Syntax and type errors corrected - msb */ That's probably still not a significant performance hit. On the machine I'm typing this on, it appears to cost somewhat under 0.1 second of CPU. Even on a slower machine, a real-life program would be *doing* something with those ten thousand malloc()ed objects, and the cost of ten thousand compares and branches would probably be negligible in comparison. Or to put it another way: if you need to execute "if (p) free (p);" so many times that the "if (p)" tests contribute significantly to the cost of the program, then you probably need to reorganize the program. -- Mark Brader "The last 10% of the performance sought contributes Toronto one-third of the cost and two-thirds of the problems." utzoo!sq!msb, msb@sq.com -- Norm Augustine This article is in the public domain.
dkeisen@Gang-of-Four.Stanford.EDU (Dave Eisen) (10/10/90)
In article <11@christmas.UUCP> rtm@island.uu.net (Richard Minner) writes: >In article <8026@scolex.sco.COM> seanf (Sean Fagan) writes: >>And now an ANSI compliant library must have free() check for a NULL >>parameter, which means that, instead of 10000 tests, you are now doing 20000 >>tests. Yep. Just love those performance increases, don't you? > > >The ANSI behavior for free() is a good thing. I don't want to read >any more complaints about it ;-) > Perfromance isn't really the issue, it's a shame that's what everyone keeps bringing up. The performance hit of testing if (ptr == NULL) is insignificant whether the test is made before the call to free or within free itself. I'd prefer free not check for NULL pointers because I'd rather have my sloppy (and probably incorrect) programming caught by a core dump than slipping by untouched. I never check for NULL pointers in library routines that I write unless there is a useful action that should be taken when that pointer is NULL. -- Dave Eisen Home: (415) 323-9757 dkeisen@Gang-of-Four.Stanford.EDU Office: (415) 967-5644 1447 N. Shoreline Blvd. Mountain View, CA 94043
bilbo@bisco.kodak.COM (Charles Tryon) (10/11/90)
In <1990Oct10.155448.1465@Neon.Stanford.EDU>, dkeisen@Gang-of-Four.Stanford.EDU (Dave Eisen) writes: > In article <11@christmas.UUCP> rtm@island.uu.net (Richard Minner) writes: > >In article <8026@scolex.sco.COM> seanf (Sean Fagan) writes: > >>And now an ANSI compliant library must have free() check for a NULL > >>parameter, which means that, instead of 10000 tests, you are now doing 20000 > >>tests. Yep. Just love those performance increases, don't you? > > > >The ANSI behavior for free() is a good thing. I don't want to read > >any more complaints about it ;-) > .... > I'd prefer free not check for NULL pointers because I'd rather have > my sloppy (and probably incorrect) programming caught by a core dump > than slipping by untouched. I never check for NULL pointers in library > routines that I write unless there is a useful action that should be taken > when that pointer is NULL. Wouldn't it be more graceful to check for invalid data (such as, but not limited to NULL pointers), and on an error condition print a MESSAGE and exit gracefully (perhaps with a core dump to allow a debugger to give you trace-back information). Assuming that a program will crash is a very dangerous thing (not to mention, not very friendly), since it might choose instead to just hose up memory and continue on as if nothing had happened. Remember that YOU probably won't be the only person using your software, and other people strongly frown upon unexplained crashes. > Dave Eisen Home: (415) 323-9757 -- Chuck Tryon (PLEASE use this address, as Kodak foobars one in header!) <bilbo@bisco.kodak.com> USmail: 46 Post Ave.;Roch. NY 14619 B. Baggins <<...include standard disclamer...>> At Your Service "Then again, squirrels could be stupid." (D. Mocsny)
steve@taumet.com (Stephen Clamage) (10/11/90)
dkeisen@Gang-of-Four.Stanford.EDU (Dave Eisen) writes: >I'd prefer free not check for NULL pointers because I'd rather have >my sloppy (and probably incorrect) programming caught by a core dump >than slipping by untouched. I never check for NULL pointers in library >routines that I write unless there is a useful action that should be taken >when that pointer is NULL. The problem with this approach is that you can't depend on an immediate core dump just because the current pointer is incorrectly null. The core dump may occur at any arbitrary later time due to following garbage pointers -- or the program may not abort, but loop forever or do something bizarre. In particular, the problem may occur only after doing some irreversible bad thing -- like deleting all the files from your disk, or launching a missile with a nuclear warhead. It is inconvenient to have to rebuild your disk (or San Francisco) before trying to track down the program bug. IMHO, it is best to program defensively and catch errors as soon as possible. A library function should return an explicit or implicit error code -- or do nothing -- rather than try to use invalid data. -- Steve Clamage, TauMetric Corp, steve@taumet.com
blodgett@apollo.HP.COM (Bruce Blodgett) (10/12/90)
If you are trying to compile code which may call free() with a NULL argument, and use an implementation of free() that does not handle NULL gracefully, try adding one of the following to <stdlib.h>: #define free(x) ( (x) ? free(x) : ( (void)0 ) ) or #define free(x) { void * ptr = (x); if ( ptr != NULL ) free(ptr); } The former has the side-effect of evaluating the argument to free() twice. The latter is a statement rather than an expression of type void, and therefore wouldn't work if someone tried to embed a call to free() in an expression (there are not many uses for subexpressions of type void). Bruce Blodgett blodgett@apollo.hp.com (508) 256-0176 x4037
cpcahil@virtech.uucp (Conor P. Cahill) (10/12/90)
I know I hate people pushing thier own software, but I thought just one more time.... In article <9010111342.AA18267@bisco.kodak.COM> nobody@Kodak.COM writes: > Wouldn't it be more graceful to check for invalid data (such as, but not > limited to NULL pointers), and on an error condition print a MESSAGE and > exit gracefully (perhaps with a core dump to allow a debugger to give you > trace-back information). This is exactly how the debuggin malloc library that was posted to c.s.u back in may works. You link it with your program (no changes are necessary to your program, you don't even have to re-compile it - just relink it) and you have a full set of checks on the typical problems that are prevalent in malloc usage. Try it, you'll like it. -- Conor P. Cahill (703)430-9247 Virtual Technologies, Inc., uunet!virtech!cpcahil 46030 Manekin Plaza, Suite 160 Sterling, VA 22170
gdtltr@freezer.it.udel.edu (Gary Duzan) (10/12/90)
In article <4d5780ad.20b6d@apollo.HP.COM> blodgett@apollo.HP.COM (Bruce Blodgett) writes: => =>If you are trying to compile code which may call free() with a NULL =>argument, and use an implementation of free() that does not handle NULL =>gracefully, try adding one of the following to <stdlib.h>: => =>#define free(x) ( (x) ? free(x) : ( (void)0 ) ) => or =>#define free(x) { void * ptr = (x); if ( ptr != NULL ) free(ptr); } => =>The former has the side-effect of evaluating the argument to free() =>twice. The latter is a statement rather than an expression of type =>void, and therefore wouldn't work if someone tried to embed a call to =>free() in an expression (there are not many uses for subexpressions of =>type void). Both will also have the property of recursively expanding free() forever. Better to call it something else. Your cpp will thank you for it. Gary Duzan Time Lord Third Regeneration -- gdtltr@freezer.it.udel.edu _o_ -------------------------- _o_ [|o o|] An isolated computer is a terribly lonely thing. [|o o|] |_O_| "Don't listen to me; I never do." -- Doctor Who |_O_|
brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (10/12/90)
In article <4d5780ad.20b6d@apollo.HP.COM> blodgett@apollo.HP.COM (Bruce Blodgett) writes: > If you are trying to compile code which may call free() with a NULL > argument, and use an implementation of free() that does not handle NULL > gracefully, try adding one of the following to <stdlib.h>: > #define free(x) ( (x) ? free(x) : ( (void)0 ) ) > #define free(x) { void * ptr = (x); if ( ptr != NULL ) free(ptr); } Much better: #define free(x) ( ( __frx = x ) , ( __frx ? __frol(__frx) : (void) 0 ) ) extern void *__frx; extern void (*__frol)(); In the library source, undef free, define __frx, and define __frol initialized to &free. ---Dan
rbutterworth@watmath.waterloo.edu (Ray Butterworth) (10/12/90)
In article <10066:Oct1212:30:5790@kramden.acf.nyu.edu> brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes: >Much better: > #define free(x) ( ( __frx = x ) , ( __frx ? __frol(__frx) : (void) 0 ) ) > extern void *__frx; > extern void (*__frol)(); Which will blow up if an interrupt occurs and changes the value of __frx between the assignment and the test, or the test and the __frol call. (Considering the environment under which C was developed, it's amazing how non-reentrant so much of the library is.) In article <4d5780ad.20b6d@apollo.HP.COM> blodgett@apollo.HP.COM (Bruce Blodgett) writes: > #define free(x) { void * ptr = (x); if ( ptr != NULL ) free(ptr); } You should call it FREE, but even then something like "if (test) FREE(thing); else something_else();" would give a syntax error. Macros like that should be written as #define NAME(arg) do { auto thing=arg; ... ; } while(0) They still can't be used as expressions, but at least they can be used in "if" statements.
brnstnd@kramden.acf.nyu.edu (Dan Bernstein) (10/14/90)
In article <1990Oct12.162928.21807@watmath.waterloo.edu> rbutterworth@watmath.waterloo.edu (Ray Butterworth) writes: > In article <10066:Oct1212:30:5790@kramden.acf.nyu.edu> brnstnd@kramden.acf.nyu.edu (Dan Bernstein) writes: > >Much better: > > #define free(x) ( ( __frx = x ) , ( __frx ? __frol(__frx) : (void) 0 ) ) > > extern void *__frx; > > extern void (*__frol)(); > Which will blow up if an interrupt occurs and changes the value of __frx > between the assignment and the test, or the test and the __frol call. So what? The system's free() isn't reentrant either. Now do you see something incorrect about my implementation, or are you just posting so you can complain about how difficult it is to use threads in C? If the latter, try proposing some solutions in alt.lang.cfutures. ---Dan
pds@lemming.webo.dg.com (Paul D. Smith) (10/15/90)
[] ... try adding one of the following to <stdlib.h> Oh no! Not that! *Never* *ever* *change* the standard libraries which ship with your compiler! (unless they don't work ;-) Put it in some local header file please, I don't want to change my nice, working, ASNI-compliant header files in order to compile your program... -- This has been a public service announcement from your local -- ANSI-promoter; any flames by e-mail please! -- paul ----- ------------------------------------------------------------------ | Paul D. Smith | pds@lemming.webo.dg.com | | Data General Corp. | | | Network Services Development | "Pretty Damn S..." | | Open Network Applications Department | | ------------------------------------------------------------------
jtc@van-bc.wimsey.bc.ca (J.T. Conklin) (10/16/90)
In article <PDS.90Oct15104036@lemming.webo.dg.com> pds@lemming.webo.dg.com (Paul D. Smith) writes: >Oh no! Not that! *Never* *ever* *change* the standard libraries which >ship with your compiler! (unless they don't work ;-) Put it in some >local header file please, I don't want to change my nice, working, >ANSI-compliant header files in order to compile your program... At UniFax, we ANSIfy the development environment on all of our development machines. Header files get protoized and missing functions get added to the C library. It is hoped that the vendors will finally get the idea, but until then we feel that maintaining these development environments is worth the effort. --jtc -- J.T. Conklin UniFax Communications Inc. ...!{uunet,ubc-cs}!van-bc!jtc, jtc@wimsey.bc.ca
pds@lemming.webo.dg.com (Paul D. Smith) (10/17/90)
[] In article <PDS.90Oct15104036@lemming.webo.dg.com> pds@lemming.webo.dg.com (Paul D. Smith) writes: [] >Oh no! Not that! *Never* *ever* *change* the standard libraries which [] >ship with your compiler! (unless they don't work ;-) Put it in some [] >local header file please, I don't want to change my nice, working, [] >ANSI-compliant header files in order to compile your program... [] At UniFax, we ANSIfy the development environment on all of our [] development machines. Header files get protoized and missing [] functions get added to the C library. I'd say all this falls under the "unless they don't work" category! :-) Even so, as has already been mentioned, there are probably better ways of doing it than changing the standard includes. I have more than once been bitten by adding/changing things in the / and /usr directories which were shipped with the product, and having many things not work (I once changed the owner of /usr/bin/login to "bin" instead of root; now just *try* to login as anything except root! And it took a whole day to discover the problem.) What do you do if you need to compile a program which relies on the old headers? -- paul ----- ------------------------------------------------------------------ | Paul D. Smith | pds@lemming.webo.dg.com | | Data General Corp. | | | Network Services Development | "Pretty Damn S..." | | Open Network Applications Department | | ------------------------------------------------------------------
jtc@van-bc.wimsey.bc.ca (J.T. Conklin) (10/18/90)
[Followup to comp.lang.c] In article <PDS.90Oct17102409@lemming.webo.dg.com> pds@lemming.webo.dg.com (Paul D. Smith) writes: >[] At UniFax, we ANSIfy the development environment on all of our >[] development machines. Header files get protoized and missing >[] functions get added to the C library. > >I'd say all this falls under the "unless they don't work" category! :-) >Even so, as has already been mentioned, there are probably better ways >of doing it than changing the standard includes. If it can me done well, it is a definite bonus. The source code of your project or product can remain relatively free of #ifdef's. I have found that this has significantly improved maintainability. >I have more than once been bitten by adding/changing things in the / >and /usr directories which were shipped with the product, and having >many things not work (I once changed the owner of /usr/bin/login to >"bin" instead of root; now just *try* to login as anything except >root! And it took a whole day to discover the problem.) >What do you do if you need to compile a program which relies on the >old headers? It is possible to carefully edit the standard header files to work with both old and new behaviors; but it is inevitable that once you have everything working, someone will do an OS upgrade and blow away your hard work. Since we use gcc on most platforms, we don't convert the headers --- we just copy everything in /usr/include into /usr/local/lib/gcc-include and make modifications there. In this manner, the stock development system is independent of our custom "ANSIzed" version. Other systems may have flags that point the compiler to look in another directory for your header directories. --jtc -- J.T. Conklin UniFax Communications Inc. ...!{uunet,ubc-cs}!van-bc!jtc, jtc@wimsey.bc.ca
darcy@druid.uucp (D'Arcy J.M. Cain) (10/19/90)
In article <PDS.90Oct17102409@lemming.webo.dg.com> pds@lemming.webo.dg.com (Paul D. Smith) writes: Seems an attribution was left off but looks like ?@van-bc.wimsey.bc.ca said: >[] In article <PDS.90Oct15104036@lemming.webo.dg.com> pds@lemming.webo.dg.com (Paul D. Smith) writes: >[] >Oh no! Not that! *Never* *ever* *change* the standard libraries which > >[] At UniFax, we ANSIfy the development environment on all of our > >I'd say all this falls under the "unless they don't work" category! :-) >Even so, as has already been mentioned, there are probably better ways >of doing it than changing the standard includes. > When I installed gcc on my system I modified it to look in /usr/newinclude for headers and then in /usr/include if not found. I then copied header files into the new directory and modified them. This leaves the original header files untouched and in fact cc will still work if necessary using the old header files. What's the point of having an ANSI compiler if you don't have the ANSI standard prototypes? -- D'Arcy J.M. Cain (darcy@druid) | D'Arcy Cain Consulting | I support gun control. West Hill, Ontario, Canada | Let's start with the government! + 416 281 6094 |
bright@nazgul.UUCP (Walter Bright) (10/25/90)
In article <1990Oct02.132313.6659@virtech.uucp> cpcahil@virtech.UUCP (Conor P. Cahill) writes: <In article <PDS.90Oct1095707@lemming.webo.dg.com> pds@lemming.webo.dg.com (Paul D. Smith) writes: <<It should be pointed out that in ANSI C free(NULL) is defined, and is <<legal (any conforming implementation of free() must ignore being <<passed a NULL pointer). <While this is a true statement, I would never recommend that one take advantage <of this feature. If you know the variable is NULL don't pass it to free. <The performance cost of the following statement: < if( ptr != NULL ) < free(ptr); <as opposed to: < free(ptr); <will be unmeasurable in most, if not all, circumstances. In addition, by <adding the if() you get code that is portable across all implementations. I'd prefer to use, on non-conforming implementations of free(): #if NONCONFORMINGFREE #define free(p) ((p) && free(p)) #endif
bright@nazgul.UUCP (Walter Bright) (10/25/90)
In article <335@bii.UUCP> gegu@bii.UUCP (Gerhard Gucher) writes:
<And as we all agree (I hope), the gain of portability to non ANSI
<systems is well worth it anyways. (Keep in mind, most in use systems
<don't carry ANSI yet ( Mess - DOS doesn't count as a system (:-) ).
In my experience, MS-DOS has the most advanced and polished programming
tools available on it. (Probably because of the intense competition
among programming tool vendors.) Practically all of the C compilers
for it that have any significance are nearly 100% ANSI conformant. I
can't say that for other systems I have used.
If other systems are so superior, why aren't their programming environments
up to the standards of the MS-DOS world?
arnold@audiofax.com (Arnold Robbins) (10/26/90)
In article <117@nazgul.UUCP> bright@nazgul.UUCP (Walter Bright) writes: >I'd prefer to use, on non-conforming implementations of free(): > > #if NONCONFORMINGFREE > #define free(p) ((p) && free(p)) > #endif Note that this requires an ANSI compliant cpp or C compiler. The original discussion was about using an ANSI compiler with non-ansi libraries, so that's fine, but if you try this macro on a pre-ansi cpp it'll recurse forever... -- Arnold Robbins AudioFAX, Inc. | Laundry increases 2000 Powers Ferry Road, #200 / Marietta, GA. 30067 | exponentially in the INTERNET: arnold@audiofax.com Phone: +1 404 933 7612 | number of children. UUCP: emory!audfax!arnold Fax-box: +1 404 618 4581 | -- Miriam Robbins
martin@mwtech.UUCP (Martin Weitzel) (10/26/90)
In article <280@audfax.audiofax.com> arnold@audiofax.com (Arnold Robbins) writes: :In article <117@nazgul.UUCP> bright@nazgul.UUCP (Walter Bright) writes: :>I'd prefer to use, on non-conforming implementations of free(): :> :> #if NONCONFORMINGFREE :> #define free(p) ((p) && free(p)) :> #endif : :Note that this requires an ANSI compliant cpp or C compiler. The original :discussion was about using an ANSI compiler with non-ansi libraries, so that's :fine, but if you try this macro on a pre-ansi cpp it'll recurse forever... And NEVER use this macro with code that contains something like `free(*ptr++)'. The latter construct is not unlikely, if there are arrays of pointers and the space each pointer points to is dynamically allocated ... -- Martin Weitzel, email: martin@mwtech.UUCP, voice: 49-(0)6151-6 56 83
henry@zoo.toronto.edu (Henry Spencer) (10/26/90)
In article <119@nazgul.UUCP> bright@nazgul.UUCP (Walter Bright) writes: ><... ( Mess - DOS doesn't count as a system (:-) ). > >If other systems are so superior, why aren't their programming environments >up to the standards of the MS-DOS world? Because they don't have 10^10 mindless lemmings buying them and thus underwriting development costs. -- The type syntax for C is essentially | Henry Spencer at U of Toronto Zoology unparsable. --Rob Pike | henry@zoo.toronto.edu utzoo!henry
floyd@hayes.ims.alaska.edu (Floyd Davidson) (10/27/90)
In article <1990Oct26.154315.26612@zoo.toronto.edu> henry@zoo.toronto.edu (Henry Spencer) writes: >In article <119@nazgul.UUCP> bright@nazgul.UUCP (Walter Bright) writes: >><... ( Mess - DOS doesn't count as a system (:-) ). >> >>If other systems are so superior, why aren't their programming environments >>up to the standards of the MS-DOS world? > >Because they don't have 10^10 mindless lemmings buying them and thus >underwriting development costs. Not to mention that "up to the standards of" seems to apply to mindless programmers and their idea of "standards". My perception of comparing UNIX to MS-DOS as a programming environ is that one has a lot of frills and no meat to it. The latest "thing" for MS-DOS doesn't hold a candle to what UNIX was 5 years ago, much less today, when it comes to getting some work done. -- Floyd L. Davidson floyd@hayes.ims.alaska.edu floydd@chinet.chi.il.us Salcha, AK 99714 connected by paycheck to Alascom, Inc. When *I* speak for them, one of us will be *out* of business in a hurry.
feg@moss.ATT.COM (Forrest Gehrke,2C-119,7239,ATTBL) (10/31/90)
In article <1990Oct26.154315.26612@zoo.toronto.edu> henry@zoo.toronto.edu (Henry Spencer) writes: >In article <119@nazgul.UUCP> bright@nazgul.UUCP (Walter Bright) writes: >><... ( Mess - DOS doesn't count as a system (:-) ). >> >>If other systems are so superior, why aren't their programming environments >>up to the standards of the MS-DOS world? > >Because they don't have 10^10 mindless lemmings buying them and thus >underwriting development costs. >-- And so far as programming in C is your desire, you have a choice of working with a crippled OS or a crippled compiler. Besides which the crippled compiler probably is working on a pricey computer with an similarly pricey OS. Worse yet, even the busted compiler often costs more than the computer with the crippled OS! (;-)) Forrest Gehrke feg@moss.att.com very pricey
bright@nazgul.UUCP (Walter Bright) (11/01/90)
In article <280@audfax.audiofax.com> arnold@audiofax.com (Arnold Robbins) writes: <In article <117@nazgul.UUCP> bright@nazgul.UUCP (Walter Bright) writes: <> #define free(p) ((p) && free(p)) <Note that this requires an ANSI compliant cpp or C compiler. The original <discussion was about using an ANSI compiler with non-ansi libraries, so that's <fine, but if you try this macro on a pre-ansi cpp it'll recurse forever... I've used similar constructs on a number of pre-ansi preprocessors, and it worked fine (it did not recurse). When I implemented a preprocessor, years before ansi, I made the mistake of it recursing. This was fixed quickly...
gwyn@smoke.brl.mil (Doug Gwyn) (11/07/90)
In article <1990Oct26.154315.26612@zoo.toronto.edu> henry@zoo.toronto.edu (Henry Spencer) writes: >In article <119@nazgul.UUCP> bright@nazgul.UUCP (Walter Bright) writes: >>If other systems are so superior, why aren't their programming environments >>up to the standards of the MS-DOS world? >Because they don't have 10^10 mindless lemmings buying them and thus >underwriting development costs. Also, the best UNIX software development environments are fully as nice as the best MS-DOS ones, plus the other numerous benefits of using UNIX. The worst UNIX software development environments are pretty ordinary, but at least one has the other UNIX advantages to compensate for that.