malloc/free questions 
Author Message
 malloc/free questions

Hi Charles.

:>As I understand it, when malloc allocates a block of memory, it has to mark
:>that block some how so that free will know how much memory to free.  The
:>pointer that malloc returns identifies the block and information about the
:>block.  It it the address of the block that is important, so doing something
:>like changing the variable that has the address of the block is unimportant.
:>However, changing the address malloc returns means losing access to the
:>information about how the block was allocated.

If you are interested, here is a portion of my malloc/free code
(taken from .h file):

#ifdef DEBUG
   #define FREESIG 0x12345678L
   #define USEDSIG 0x87654321L
   #define NONESIG 0x00000000L
#endif

#pragma pack(1)
typedef struct _memBlock {
#ifdef DEBUG
   ULONG             ulSig;
#endif
   ULONG             ulSize;
   struct _memBlock *next;

Quote:
} memBlock, * pmemBlock;

#define BLOCK_OVERHEAD (sizeof(memBlock))

#pragma pack()

Best regards,
Rok Papez.

Student at Faculty of Computer and Information Science,
University of Ljubljana.

--



Fri, 03 Nov 2000 03:00:00 GMT  
 malloc/free questions


Quote:
> I have some questions about malloc/free.  While the case with which I am
> working is more complex, the concepts can be tested with simple types.  
> (Yes, of course, in real code I would check malloc's return value.)

> Case 1: freeing a pointer that has been modified since allocation

>    char *foo_p;
>    foo_p = malloc(100);
>    foo_p++;
>    free(foo_p);

>    /* Did I just leak?  Or is this even legal? */

What you should get is an SIGBUS based on your attempt to perform
a misaligned free().  If it succeeds, however, then you've leaked
your first unit.

Quote:
> Case 2: freeing a pointer that is called by a different name

>    char *foo_p, *bar_p;
>    foo_p = malloc(100);
>    bar_p = foo_p;
>    free(bar_p);

>    /* Is this legal? */

Sure.  It's a good idea, too, particularly if you want to free()
the space pointed to by foo_p after diddling with it like in your
first case.

Quote:
> Case 3: a combination, with function calls

>    char* get_mem(void)
>    {
>            return malloc(100);
>    }

I'm just being {*filter*}here, but

        return (char *)malloc(100);  /* malloc(100 * sizeof(char)) */

Quote:
>    void release_mem(char* in_p)
>    {
>            free(in_p);
>    }      

>    char *foo_p, *bar_p;
>    foo_p = get_mem();
>    bar_p = ++foo_p;
>    release_mem(bar_p);

>    /* Legal?  Leaks?  What if the last line is */

It's a misaligned free() again.  If it doesn't generate a SIGBUS, then
it's a leak.

Quote:
>    release_mem(foo_p);

>    /* ? */

It's a misaligned free(); bar_p is &(foo_p[1]) not &(foo_p[0]).

--
All of reality is just a simulation running in God's computer.  So chill.

// If you'd like to drop me a note: net dot earthlink at huddler
--



Fri, 03 Nov 2000 03:00:00 GMT  
 malloc/free questions

Quote:

> I have some questions about malloc/free.  While the case with which I am
> working is more complex, the concepts can be tested with simple types.
> (Yes, of course, in real code I would check malloc's return value.)

> Case 1: freeing a pointer that has been modified since allocation

>         char *foo_p;
>         foo_p = malloc(100);
>         foo_p++;
>         free(foo_p);

>         /* Did I just leak?  Or is this even legal? */

Your next allocation will probably crash if the free manages to return.
At any rate, what you did here was incontestably unwise and unsupported
and undefined.

Quote:
> Case 2: freeing a pointer that is called by a different name

>         char *foo_p, *bar_p;
>         foo_p = malloc(100);
>         bar_p = foo_p;
>         free(bar_p);

>         /* Is this legal? */

This is perfectly legal -- just don't free bar_p again or foo_p.

Quote:
> Case 3: a combination, with function calls

>         char* get_mem(void)
>         {
>                 return malloc(100);
>         }

>         void release_mem(char* in_p)
>         {
>                 free(in_p);
>         }

>         char *foo_p, *bar_p;
>         foo_p = get_mem();
>         bar_p = ++foo_p;
>         release_mem(bar_p);

>         /* Legal?  Leaks?  What if the last line is */

You've incremented the pointer which is disastrous.  Without the
increment, all would be OK.  With the increment, something is going to
fail soon.

Quote:
>         release_mem(foo_p);

Double freeing the space is disastrous too.  Don't do it!

Yours,

--



Fri, 03 Nov 2000 03:00:00 GMT  
 malloc/free questions

Quote:

> >Case 1: freeing a pointer that has been modified since allocation

> >       char *foo_p;
> >       foo_p = malloc(100);
> >       foo_p++;
> >       free(foo_p);

> >       /* Did I just leak?  Or is this even legal? */

>    I think this will cause memory leak.

[snip]

When considering what is and is not an error, it helps to know what
malloc() and free() might be doing.

In K&R's example of how to implement these functions (ed.2, section 8.7),
malloc() accounts for memory in the following way. (Use a fixed-width font
like Courrier to view the diagram.)

                  HEADER
    _________________^_________________
   /                                   \

   ***********************************************************************
   *                 *                  *                                *
   *  POINTER TO     *  SIZE OF THE     *  BLOCK WHOSE ADDRESS IS        *
   *  NEXT FREE      *  BLOCK RETURNED  *  RETURNED BY malloc()          *
   *  BLOCK          *  TO THE USER     *                                *
   *                 *                  *   array of at least the        *
   *  Header *       * unsigned int     *  requested size                *
   *                 *                  *                                *
   ***********************************************************************

   ^  ^                                 ^  ^
   |  |                                 |  |
   |  |                                 |  |
   | ((Header *) (foo_p+1)) - 1      foo_p |
   | MISALIGNED POINTER                    |
   |                                      foo_p+1
  ((Header *) foo_p) - 1
  CORRECT ADDRESS OF HEADER

The diagram shows an area of memory containing the block whose address is
returned by malloc(), plus some adjacent house-keeping information used by
malloc() and free(). The rough position of some relevant addresses is also
given.

free() expects to be able to find the header for the block whose address
it is passed just before this in memory, i.e. at address (Header *)
foo_p-1. But in the above code, free() is actually passed the address
foo_p+1 rather than foo_p. free() will calculate the location of the start
of the header incorrectly, leading to misbehaviour at run-time.

This is just one way malloc() and free() might be implemented, but gives
insight into how free()-ing an address NOT returned by malloc(), calloc()
or realloc() can wreak havoc.

Daniel Barker,
Biocomputing Research Unit,
Institute of Cell and Molecular Biology,
Swann Building,
King's Buildings,
Mayfield Road,
Edinburgh
EH9 3JR
UK
--



Fri, 03 Nov 2000 03:00:00 GMT  
 malloc/free questions


: > Case 3: a combination, with function calls
: >
: >  char* get_mem(void)
: >  {
: >          return malloc(100);
: >  }

: I'm just being {*filter*}here, but

        Presumably you mean "{*filter*}retentive", but now maybe _I'm_... :-)

:       return (char *)malloc(100);  /* malloc(100 * sizeof(char)) */

        Exactly what does this accomplish? Are there still systems in wide
use that declare malloc as something other than "void *malloc( size_t )"?
If not, I'd like to make a plea for using the committe-given ability to
assign a void * to any data pointer without a cast. Why? because "{*filter*}"
casts are often a good tip-off to dubious code. If you get used to sprinkling
casts through your code to "shut the compiler up", then someday you will
cast an int** to an int* and since you used a cast, to say "Shut up,
compiler, I know what I'm doing", but you _don't_ really know what you're
doing, you will be in a world of hurt. I was under the impression that
void * was invented partially for this purpose, but I'd gladly hear a
reasoned argument to the contrary.

        My rule, not that I don't break it once in a while because I
am a fallible being, is "no casts outside well-checked macros". Of
course, I have to violate it in, e.g. cases where a function is declared
to return a char * and take a const char * (strchr() springs to mind)
The inability to specify such functions (or am I just stupid, please
enlighten me) to "inherit" the qualifiers of their arguments is just
one of those prices I pay for programming in a ubiquitous language.

                                        Mike

--



Sun, 05 Nov 2000 03:00:00 GMT  
 malloc/free questions


[other okay cases deleted]

: > Case 3: a combination, with function calls
: >
: >  char* get_mem(void)
: >  {
: >          return malloc(100);
: >  }

: I'm just being {*filter*}here, but

:       return (char *)malloc(100);  /* malloc(100 * sizeof(char)) */

Having such a functions is a good thing for allocating and initilizing
memory for an "object", such as a structure. The subsequent release_mem()
function is good for the cleanup...

: >  void release_mem(char* in_p)
: >  {
: >          free(in_p);
: >  }      

--

|| Research Programmer
--



Sun, 05 Nov 2000 03:00:00 GMT  
 malloc/free questions



Quote:

>> I have some questions about malloc/free.  While the case with which I am
>> working is more complex, the concepts can be tested with simple types.  
>> (Yes, of course, in real code I would check malloc's return value.)

>> Case 1: freeing a pointer that has been modified since allocation

>>       char *foo_p;
>>       foo_p = malloc(100);
>>       foo_p++;
>>       free(foo_p);

>>       /* Did I just leak?  Or is this even legal? */

>What you should get is an SIGBUS based on your attempt to perform
>a misaligned free().

Alignment isn't the issue here. The problem is simply that the value being
passed to free() is not a value previously returned by malloc/calloc/realloc
(that has not subsequently been freed) or a null pointer.

Quote:
> If it succeeds, however, then you've leaked
>your first unit.

There's no reason to believe that a memory leak will be the result. As
a consequence of undefined behaviour *anything at all* can happen. It
might even free the block of memory successfully in its entirety.

Quote:
>> Case 2: freeing a pointer that is called by a different name

>>       char *foo_p, *bar_p;
>>       foo_p = malloc(100);
>>       bar_p = foo_p;
>>       free(bar_p);

>>       /* Is this legal? */

>Sure.  It's a good idea, too, particularly if you want to free()
>the space pointed to by foo_p after diddling with it like in your
>first case.

Note also tha after the call to free() the values of both foo_p and bar_p
are indeterminate i.e. it is an error even to look at them (but you can
assign new values to them).

Quote:
>> Case 3: a combination, with function calls

>>       char* get_mem(void)
>>       {
>>               return malloc(100);
>>       }

>I'm just being {*filter*}here, but

>        return (char *)malloc(100);  /* malloc(100 * sizeof(char)) */

The original is better. It is a bad idea to cast the return value of malloc
since it doesn't buy you anything and it can mask (but not correct) errors
such as forgetting to include <stdlib.h>. sizeof(char) is, by definition, 1
so it is normal to omit it as a constant factor in a context like this.

Quote:
>>       void release_mem(char* in_p)
>>       {
>>               free(in_p);
>>       }      

>>       char *foo_p, *bar_p;
>>       foo_p = get_mem();
>>       bar_p = ++foo_p;
>>       release_mem(bar_p);

>>       /* Legal?  Leaks?  What if the last line is */

>It's a misaligned free() again.  If it doesn't generate a SIGBUS, then
>it's a leak.

Again, the result is undefined behaviour. A memory leak is what happens
when you lose any way to reference allocated memory. In C that typically
happens when you fail to free a malloc'd object before getting rid of all
accessible pointer references to it. Memory leaks can eatup resources but
are otherwise not an error and don't affect the behaviour of the program.
The code above results in undefined behaviour which is a totally different
situation.

Quote:
>>       release_mem(foo_p);

Bad, however

         release_mem(foo_p-1);

would be fine.

--
-----------------------------------------


-----------------------------------------
--



Sun, 05 Nov 2000 03:00:00 GMT  
 malloc/free questions


Quote:


> : > Case 3: a combination, with function calls
> : >
> : >     char* get_mem(void)
> : >     {
> : >             return malloc(100);
> : >     }

> : I'm just being {*filter*}here, but

>    Presumably you mean "{*filter*}retentive", but now maybe _I'm_... :-)

> :  return (char *)malloc(100);  /* malloc(100 * sizeof(char)) */

>    Exactly what does this accomplish? Are there still systems in wide
> use that declare malloc as something other than "void *malloc( size_t )"?
> If not, I'd like to make a plea for using the committe-given ability to
> assign a void * to any data pointer without a cast. Why? because "{*filter*}"
> casts are often a good tip-off to dubious code. If you get used to sprinkling
> casts through your code to "shut the compiler up", [....]

Who said anything about "sprinkling casts through code...to shut the
compiler up"?  Compiler warnings are your best friend.

I acquired the habit, long ago, of explicitly casting the type from
malloc(), calloc(), and realloc().  

I agree that it's not necessary these days.  Whether or not it represents
dubious code, however, is another matter.  I tend to think that the
programmer doing such a thing is specifying exactly what s/he wants to
occur, committee or no committee.  Much like expressing

        (void)printf( .... ) ;

does.  

As with any use of power, an explosion can result if the person using it
is an idiot.

--
All of reality is just a simulation running in God's computer.  So chill.

// If you'd like to drop me a note: net dot earthlink at huddler
--



Sat, 11 Nov 2000 03:00:00 GMT  
 malloc/free questions


Quote:



> >> I have some questions about malloc/free.  While the case with which I am
> >> working is more complex, the concepts can be tested with simple types.  
> >> (Yes, of course, in real code I would check malloc's return value.)

> >> Case 1: freeing a pointer that has been modified since allocation

> >>       char *foo_p;
> >>       foo_p = malloc(100);
> >>       foo_p++;
> >>       free(foo_p);

> >>       /* Did I just leak?  Or is this even legal? */

> >What you should get is an SIGBUS based on your attempt to perform
> >a misaligned free().

> Alignment isn't the issue here. The problem is simply that the value being
> passed to free() is not a value previously returned by malloc/calloc/realloc
> (that has not subsequently been freed) or a null pointer.

Yes and no.  From the standpoint of the C language, yes.  From the
standpoint of the underlying memory allocation mechanisms, no.  See the

Quote:
> > If it succeeds, however, then you've leaked your first unit.

> There's no reason to believe that a memory leak will be the result. As
> a consequence of undefined behaviour *anything at all* can happen. It
> might even free the block of memory successfully in its entirety.

True.  My answer was implementation-specific, rather than the one in the
lanaguage specification.

- Show quoted text -

Quote:
> >> Case 2: freeing a pointer that is called by a different name

> >>       char *foo_p, *bar_p;
> >>       foo_p = malloc(100);
> >>       bar_p = foo_p;
> >>       free(bar_p);

> >>       /* Is this legal? */

> >Sure.  It's a good idea, too, particularly if you want to free()
> >the space pointed to by foo_p after diddling with it like in your
> >first case.

> Note also tha after the call to free() the values of both foo_p and bar_p
> are indeterminate i.e. it is an error even to look at them (but you can
> assign new values to them).

> >> Case 3: a combination, with function calls

> >>       char* get_mem(void)
> >>       {
> >>               return malloc(100);
> >>       }

> >I'm just being {*filter*}here, but

> >        return (char *)malloc(100);  /* malloc(100 * sizeof(char)) */

> The original is better. It is a bad idea to cast the return value of malloc
> since it doesn't buy you anything and it can mask (but not correct) errors
> such as forgetting to include <stdlib.h>. sizeof(char) is, by definition, 1
> so it is normal to omit it as a constant factor in a context like this.

In general, I agree.  I've been casting that baby for a long time,
however, and will continue to do so.

- Show quoted text -

Quote:
> >>       void release_mem(char* in_p)
> >>       {
> >>               free(in_p);
> >>       }      

> >>       char *foo_p, *bar_p;
> >>       foo_p = get_mem();
> >>       bar_p = ++foo_p;
> >>       release_mem(bar_p);

> >>       /* Legal?  Leaks?  What if the last line is */

> >It's a misaligned free() again.  If it doesn't generate a SIGBUS, then
> >it's a leak.

> Again, the result is undefined behaviour. [...definitions...]

True.  My answer was implementation-specific, rather than the one in the
lanaguage specification.

--
All of reality is just a simulation running in God's computer.  So chill.

// If you'd like to drop me a note: net dot earthlink at huddler
--



Sat, 11 Nov 2000 03:00:00 GMT  
 malloc/free questions



[ ... ]

Quote:
> I acquired the habit, long ago, of explicitly casting the type from
> malloc(), calloc(), and realloc().  

> I agree that it's not necessary these days.  Whether or not it represents
> dubious code, however, is another matter.  I tend to think that the
> programmer doing such a thing is specifying exactly what s/he wants to
> occur, committee or no committee.  Much like expressing

>    (void)printf( .... ) ;

> does.  

I agree -- both of them are ill-advised and foolish.  If you're going
to make explicit the fact that you're ignoring the value produced by
printf, you should _clearly_ also make explicit the fact that you're
ignoring the values produced by all the other things in your program.  
For example:

        x = 1;

is _obviously_ BAD!  To be explicit, what you really meant was that
you were going to assign 1 to x, and then _ignore the value that
produced_:

        (void)x=1;

if one makes any sense at all, so does the other.  Of course, in
reality, both are absurd...

--
    Later,
    Jerry.

The Universe is a figment of its own imagination.
--



Mon, 13 Nov 2000 03:00:00 GMT  
 malloc/free questions

Quote:




>> : >                 return malloc(100);
>> :      return (char *)malloc(100);  /* malloc(100 * sizeof(char)) */

>> If you get used to sprinkling
>> casts through your code to "shut the compiler up", [....]
>Who said anything about "sprinkling casts through code...to shut the
>compiler up"?  Compiler warnings are your best friend.
>I acquired the habit, long ago, of explicitly casting the type from
>malloc(), calloc(), and realloc().  

You did. If you cast the return value of malloc to the required type,
you will shut up almost any compiler, even when the conversion is
dubious. As a practical example, let's consider a compiler where
sizeof(int) != sizeof(void *), like the compilers for the good ole 8086
in some memory models (int == 16 bit, ptr == 32 bit) or the DEC Alpha
(int == 32 bit, ptr == 64 bit). Lets say, you forgot to include
<stdlib.h>, so the compiler assumes that malloc will return an int. If
you don't use a cast, the compiler will probably complain that you are
converting an int to a pointer. If you do use a cast, the compiler will
assume that you know what you are doing, and keep quiet. The resulting
code will replace half of the bits in the pointer with zeros, and you
will get a core dump if you are lucky (a thrashed hard disk if you are
unlucky). Now, I know, that most compilers have other warnings they
might issue in this case ("implicit function declaration" for example),
but why turn off a useful diagnostic if there is no need?

        hp

--
   _  | Peter J. Holzer             | But now it's
|_|_) | Sysadmin WSR                | implementation-defined

__/   | http://wsrx.wsr.ac.at/~hjp/ |     -- Clive Feather
--



Mon, 13 Nov 2000 03:00:00 GMT  
 malloc/free questions



...

Quote:
>For example:

>        x = 1;

>is _obviously_ BAD!  To be explicit, what you really meant was that
>you were going to assign 1 to x, and then _ignore the value that
>produced_:

>        (void)x=1;

>if one makes any sense at all, so does the other.  Of course, in
>reality, both are absurd...

Probably more so once you realise that this isn't the same thing as:

         (void)(x=1);

:-)

--
-----------------------------------------


-----------------------------------------
--



Tue, 14 Nov 2000 03:00:00 GMT  
 malloc/free questions

|>   (void)x=1;

This must be
        (void)(x=1);

--
Andreas Schwab                                      "And now for something


--



Tue, 14 Nov 2000 03:00:00 GMT  
 malloc/free questions

Quote:

>is _obviously_ BAD!  To be explicit, what you really meant was that
>you were going to assign 1 to x, and then _ignore the value that
>produced_:

>    (void)x=1;

You mean

        (void)(x = 1);

The cast has higher operator precedence than the assignment. :)

You are right of course; if one is going to cast the discarded return
values of functions like printf(), then to be consistent, one should
cast all expression-statements to void. This is, of course, absurd
to say the least.  I also don't see how it can prevent errors.

An error that could arise out of a failure to observe the return
value of a function falls into two categories: the function
could return a pointer (or other reference) to some object that
was allocated in the function, in which case a memory leak results
from ignoring the return value; and the function could return an error
indicator which would cause a subsequent operation to fail.
The first of these two cases is rare because the return value is
of central interest to the surrounding code: it represents some
allocated object, file or what have you, which is subject to
further operations.

The habit of writing (void) casts will help with neither of these
errors, since it only encourages such discarding.

Occurences of (void) printf(/*...*/) in acual programs are evidence
of this. A robust program does in fact check the return value of
printf, which is negative if an error occured. Such a check could
be the difference between a program which silently discards
data and one which reports that an error has occured (because
the disk filled up, say).
--



Tue, 14 Nov 2000 03:00:00 GMT  
 
 [ 14 post ] 

 Relevant Pages 

1. malloc - free question

2. malloc/free question

3. basic malloc/free question

4. dumb malloc free question

5. malloc/free question with Purify

6. Bonehead malloc/free question

7. Intersting malloc() / free() question

8. malloc/free question

9. malloc, realloc, free questions

10. Dumb question concerning malloc/free

11. a question about malloc and free

12. simple question about malloc & free

 

 
Powered by phpBB® Forum Software