[comp.lang.c] Why 'life after free'.

quan@sol.surv.utas.oz (Stephen Quan) (09/30/90)

Hi, I'm the original poster (stephen quan@sol.surv.utas.edu.au), and I
wish to make some more comments on 'life after free'.

From: wuxing@comp.mscs.mu.edu (Xing Wu)
>In article <quan.654410256@sol> you write:
>>  tmp = (char *) malloc(100);
>>  for (i=0; i<=99 ; i++) *(tmp+i) = ch;
>>  free(tmp);
>>  return tmp;
>
>>Any comments on free-ing tmp before it is return-ed?
>
>You mean, other than "why?"

>According to my manpage, free makes the space "available for further
>allocation, but its contents are undisturbed."
>
>This would lead me to believe that, depending on the compiler, and
>depending on your OS, and depending on the phase of the moon, the 
>pointer would still point to the buffer you malloc'ed.  Maybe.

I interpreted the MAN page just the same.  However, I was hoping that the
man page implied that the memory contents is still valid for at least one
instruction more.  Why?  I'll tell you in a sec ...

>Is there any particular reason you don't return the pointer, use
>it, and then free it?

I normally do what you suggest, the reason why a brought up this issue is
that if what I propose wasn't so unpredictable then I can have something
like :

  printf("%s\n",funny('c'));
  printf("%s\n",funny('x'));

Where funny will create a string of 100 c's or 100 s's.  The string is
displayed in 'printf' (hopefully) and you don't need to worry about
free-ing the memory.

(For keen programmers, the C definition for funny up-up above is not quite
 correct, but I think you get the picture, anyway.  ie missing 0 string
 terminator.).

stephen quan@sol.surv.utas.edu.au

dylan@ibmpcug.co.uk (Matthew Farwell) (09/30/90)

In article <quan.654673946@sol> quan@sol.surv.utas.oz (Stephen Quan) writes:
> From: wuxing@comp.mscs.mu.edu (Xing Wu)
> >In article <quan.654410256@sol> you write:
> >>  tmp = (char *) malloc(100);
> >>  for (i=0; i<=99 ; i++) *(tmp+i) = ch;
> >>  free(tmp);
> >>  return tmp;
> I normally do what you suggest, the reason why a brought up this issue is
> that if what I propose wasn't so unpredictable then I can have something
> like :
> 
>   printf("%s\n",funny('c'));
>   printf("%s\n",funny('x'));
> 
> Where funny will create a string of 100 c's or 100 s's.  The string is
> displayed in 'printf' (hopefully) and you don't need to worry about
> free-ing the memory.

Forgive me if I'm wrong, but whats wrong with doing ....

char *
funny(c)
char c;
{
	static char a[100];
	int i;

	for (i=0 ; i<99 ; i++) a[i] = c;
	a[99] = '\0';
	return (&a[0]);
}

Dylan.
-- 
Matthew J Farwell                 | Email: dylan@ibmpcug.co.uk
The IBM PC User Group, PO Box 360,|        ...!uunet!ukc!ibmpcug!dylan
Harrow HA1 4LQ England            | CONNECT - Usenet Access in the UK!!
Phone: +44 81-863-1191            | Sun? Don't they make coffee machines?

karl@haddock.ima.isc.com (Karl Heuer) (10/02/90)

In article <quan.654673946@sol> quan@sol.surv.utas.oz (Stephen Quan) writes:
>I normally do what you suggest, the reason why a brought up this issue is
>that if what I propose wasn't so unpredictable then I can have something
>like :
>  printf("%s\n",funny('c'));
>  printf("%s\n",funny('x'));

Bad idea, even under the old rules.  This depends on the funny-buffer
retaining its contents until printf() copies it into the stdio buffer.
So it will break if malloc() is called by printf() or any of the stdio
routines it calls--which is sometimes the case.

I generally recommend
	temp = funny('c');  printf("%s\n", temp);  free(temp);
instead.  If you have enough of these that it's painful, consider writing
your own allocation package on top of malloc()/free(), and include a function
that will garbage collect the temporaries.  Shouldn't be difficult.

Karl W. Z. Heuer (karl@kelp.ima.isc.com or ima!kelp!karl), The Walking Lint

burley@world.std.com (James C Burley) (10/02/90)

In article <1990Sep30.163824.12974@ibmpcug.co.uk> dylan@ibmpcug.co.uk (Matthew Farwell) writes:

   In article <quan.654673946@sol> quan@sol.surv.utas.oz (Stephen Quan) writes:
   > From: wuxing@comp.mscs.mu.edu (Xing Wu)
   > >In article <quan.654410256@sol> you write:
   > >>  tmp = (char *) malloc(100);
   > >>  for (i=0; i<=99 ; i++) *(tmp+i) = ch;
   > >>  free(tmp);
   > >>  return tmp;
   > I normally do what you suggest, the reason why a brought up this issue is
   > that if what I propose wasn't so unpredictable then I can have something
   > like :
   > 
   >   printf("%s\n",funny('c'));
   >   printf("%s\n",funny('x'));
   > 
   > Where funny will create a string of 100 c's or 100 s's.  The string is
   > displayed in 'printf' (hopefully) and you don't need to worry about
   > free-ing the memory.

   Forgive me if I'm wrong, but whats wrong with doing ....

   char *
   funny(c)
   char c;
   {
	   static char a[100];
	   int i;

	   for (i=0 ; i<99 ; i++) a[i] = c;
	   a[99] = '\0';
	   return (&a[0]);
   }

   Dylan.
   -- 
   Matthew J Farwell                 | Email: dylan@ibmpcug.co.uk
   The IBM PC User Group, PO Box 360,|        ...!uunet!ukc!ibmpcug!dylan
   Harrow HA1 4LQ England            | CONNECT - Usenet Access in the UK!!
   Phone: +44 81-863-1191            | Sun? Don't they make coffee machines?

It fails if you then do something like:

    printf("%s %s\n",funny('a'),funny('b'));

On the practical side, one might want to use a statement like the above
frequently as a debugging/testing feature in a program, where conciseness
and "lack of interference" with the surrounding production code is a must.
Yet the above statement (using two invocations of funny in one call, hence
overwriting the results of one call with the results of the other, in effect,
before invoking printf itself) might occur frequently.

So, if you need to have some function like "funny" that you expect to reside
in printf or similar calls, and there might be more than one, and you are
willing to "assert" to yourself that there are never more than, say, eight
(better yet, say MAX_PARALLEL_INVOCATIONS), then you can do something like:

   char *
   funny(c)
   char c;
   {
   #define MAX_PARALLEL_INVOCATIONS 8
	   static char a[MAX_PARALLEL_INVOCATIONS][100];
           static int cur = 0;
	   int i;
           char *ptr;

	   for (i=0 ; i<99 ; i++) a[cur][i] = c;
	   a[cur][99] = '\0';
	   ptr = &a[cur][0];
           if (++cur == MAX_PARALLEL_INVOCATIONS)
               cur = 0;  /* Wrap around to first area. */
           return ptr;
   }

This way you have enough static storage for 8 simultaneous ("parallel")
results of invoking funny() before results get effectively overwritten.
Define the value as large as you like.

I wouldn't recommend using this approach for production code (I mean
lines of code performing production duties) or anything other than small,
tight projects.  Use the "temp = funny(...); printf(...,temp,...); free(temp);"
solution outlined in another post (where funny doesn't free) for those.
The above approach, however, is useful as debug/test code because it doesn't
clutter up code with extra temps -- furthermore, the particular example
above adds no malloc/free sequences (except via invoking printf, perhaps),
which might make a buggy program a bit easier to debug.  (Remember, the best
debugger in the toughest situations is one that has the smallest impact on
its target environment, all else being equal; for that reason, I'd even
suggest using fputs(funny(...)); fputs(" ... "); fputs(funny(...)); and so on.
Debugging code should try to use the lowest-level stuff possible in case you
have to debug at a low level, as in checking for heap corruption and such.
But don't torture yourself and your debugging code to fit into this model;
if you're doing printfs to show how object states evolve during execution or
other such higher-level things, then just make sure you can turn them all of
easily via #define if you do run into a low-level bug.)

James Craig Burley, Software Craftsperson    burley@world.std.com

pl@news.funet.fi.tut.fi (Lehtinen Pertti) (10/02/90)

From article <1990Sep30.163824.12974@ibmpcug.co.uk>, by dylan@ibmpcug.co.uk (Matthew Farwell):
> 
> Forgive me if I'm wrong, but whats wrong with doing ....
> 
> char *
> funny(c)
> char c;
> {
> 	static char a[100];
> 	int i;
> 
> 	for (i=0 ; i<99 ; i++) a[i] = c;
> 	a[99] = '\0';
> 	return (&a[0]);
> }
> 

	With this function call's like

	printf( "%s %s\n", funny( 'x' ), funny( 'y' ) );

	do not work as expected.

---
pl@tut.fi				! All opinions expressed above are
Pertti Lehtinen				! purely offending and in subject
Tampere University of Technology	! to change without any further
Software Systems Laboratory		! notice

mikey@ontek.com (michelle (krill-woman) lee) (10/05/90)

| > char *
| > funny(c)
| > char c;
| > {
| > 	static char a[100];
| > 	int i;
| > 
| > 	for (i=0 ; i<99 ; i++) a[i] = c;
| > 	a[99] = '\0';
| > 	return (&a[0]);
| > }
| > 
| 
| 	With this function call's like
| 	printf( "%s %s\n", funny( 'x' ), funny( 'y' ) );
| 	do not work as expected.

      This sort of thing wouldn't work with malloc/free as originally
proposed either.  If funny freed the block its return pointer pointed 
at,  the second invocation (not necessarily the one for y, btw) might 
cause malloc to stomp on the thing that was just freed, before printf
even has a chance to print it.  It's either that or don't free it and 
get a memory leak.  Better solutions have been mentioned elsewhere in
this thread of articles,  i.e. using variables in the caller to store
the result.

the krill, i/o bound