[comp.lang.c] free

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