Malloc/Free - freeing memory allocated by malloc

Discussion in 'C Programming' started by Peter, Sep 20, 2004.

  1. Peter

    Peter Guest

    Is it really necessary to call free()? Can I make the assumption that
    the OS will do the clean up once the program terminates?

    For a linked list, I can step through the list and free one node at a
    time, but what about a dynamic array created by malloc?

    int *data = malloc(100 * sizeof(int));

    Does free(data) frees all 100 elements or only the first one? Do I
    have to do the following in a loop?


    I appreciate your input.

    Peter, Sep 20, 2004
    1. Advertisements

  2. On most OS's you can, but if that's a good idea is another question,
    especially if the code may become part of a larger program later on
    (so what's now main() becomes a function of that larger program).
    It frees all of them. You must call free() exactly once for each time
    you called malloc() (or calloc() etc.). You are only allowed to use
    the pointer as you received it from malloc() in the call of free(),
    nothing else.
    Regards, Jens
    Jens.Toerring, Sep 20, 2004
    1. Advertisements

  3. Is it really necessary to call free()? Can I make the assumption that
    You cannot make the assumption that the program is supposed to
    terminate. Daemons don't. (and code that is reusable may be
    incorporated into a daemon.) Sloppy programming with memory leaks
    is likely to result in a system that has to be rebooted frequently
    just to get back leaked memory.
    One malloc, one free. Many mallocs, many frees.
    If you got it in one malloc, all you need is one free.
    malloc() does NOT know how you are using the memory.
    free() takes a pointer as an argument. You are feeding it an integer
    argument here.

    Gordon L. Burditt
    Gordon Burditt, Sep 20, 2004
  4. Peter

    Jason Curl Guest

    I remember for the AmigaOS, it didn't reclaim lost memory. It didn't use
    an MMU. So, it's not really a good idea to assume the OS will clean it
    up for you.
    Jason Curl, Sep 20, 2004
  5. Peter

    SM Ryan Guest

    (Peter) wrote:
    # Is it really necessary to call free()? Can I make the assumption that
    # the OS will do the clean up once the program terminates?

    It depends on the OS. You have to check your OS documentation to find out.

    I think it's a good idea in most cases. If someday you or someone else wants to take
    your entire program and change it into a package loaded into another program, doing
    complete memory management in the first place is a big help.

    # For a linked list, I can step through the list and free one node at a
    # time, but what about a dynamic array created by malloc?
    # int *data = malloc(100 * sizeof(int));

    You should have one free for each malloc and for the last pointer returned by realloc.
    malloc probably is unaware whether you want a very large struct or a hundred elements;
    it returns one block for each call, and it is the block that has to be freed.
    SM Ryan, Sep 20, 2004
  6. Peter

    Malcolm Guest

    No decent OS will allow normal applications to hog memory, even after being
    However inability to free your memory on program exit is usually a sign that
    you don't have memory management under control. In particular, how will you
    find genuine memory leaks?
    Malcolm, Sep 20, 2004
  7. Peter

    Peter Guest

    Thanks everyone for replying, I will definitely "free" after each
    "malloc". Something strange is that after calls to "free", the linked
    list is still accessible, the values are still there. Should I also
    assign NULL value to each node?
    Peter, Sep 21, 2004
  8. Peter

    pete Guest

    Any test of a freed pointer invokes undefined behavior.
    It may be that the memory was simply not yet reallocated
    by the time that you checked it, but by checking it,
    your program was still using memory that it didn't own.
    I wouldn't.

    This is what I use to free a list:

    void list_free(list_type *node, void (*free_data)(void *))
    list_type *next;

    while (node != NULL) {
    free_data(node -> data);
    next = node -> next;
    node = next;

    where list_type is defined as:

    #define LIST_TYPE \
    struct list_node { \
    struct list_node *next; \
    void *data; \

    typedef LIST_TYPE list_type;
    pete, Sep 21, 2004
  9. Memory may still be accessible via the pointer and it may even still
    hold what it did before you called free(). But that's by pure chance,
    what the pointer was pointing to may also have become inaccessible or
    the memory it's pointing to may contain some other data. You simply
    can't know and using the pointer after free() invokes undefined beha-
    vior, i.e. everything can happen. So be very careful never to do that.

    If setting the pointer to NULL after the call of free() helps you in
    not using the pointer anymore then set it to NULL - but you don't
    have to zero out the memory before free()ing it, that would just be
    a waste of time. Setting the pointer to NULL is not required - all
    you must do is refrain from using that pointer for anything at all
    (including even just looking at its value).

    int *x = malloc( 100 * sizeof *x );
    free( x );

    Both the following lines would invoke undefined behavior.

    printf( "%d %d\n", x[ 11 ], *( x + 42 ); /* wrong! */
    printf( "%p\n", ( void * ) x ); /* wrong! */

    even though on some machines you might get away with doing that. All
    you're allowed to do with 'x' after calling free() on it is to assign
    a new value to it, e.g. by using a further call of malloc()

    x = mallod( 20 * sizeof *x );

    or setting it to NULL
    Regards, Jens
    Jens.Toerring, Sep 21, 2004
  10. Peter

    Dan Pop Guest

    If you can still access those addresses, it means that the freed memory
    still belongs to your program (it is available for further allocation).
    The free() function typically doesn't touch the contents of the memory it

    However, there are implementations where, under certain conditions, the
    deallocated memory no longer belongs to the program. Trying to access
    the freed memory will crash your program.
    What for? If you're concerned about security issues (you don't want your
    data to be available to whatever program might "inherit" the memory you
    have freed), don't worry: the operating system is supposed to clear the
    memory before allocating it to another program.

    Dan Pop, Sep 21, 2004
  11. Peter

    CBFalconer Guest

    Don't toppost. Your answer belongs after, or intermixed with, the
    material you are quoting, after snipping away anything not germane
    to your reply.

    Having the 'values still there' is one valid form of undefined
    behavior. Another is erasing your hard disk, or setting off
    nuclear bombs. Don't do that.
    CBFalconer, Sep 21, 2004
  12. Peter

    Dan Pop Guest

    Nope, he did the right thing. The rule has exceptions, but you need to
    engage your brain to detect them.

    His text was not directly related to anything he quoted, so there
    was no point in not top posting. The quoted material was only
    providing background context for those joining the thread at that
    particular point and was of no interest for the other participants
    to the discussion. No need to go again over it in order to find the
    new stuff.

    The ultimate proof that he did the right thing is the fact that you
    didn't have to reformat his post in order to provide a meaningful reply:
    all the included text could be deleted with one editor command, because
    it was irrelevant to your answer.

    Dan Pop, Sep 21, 2004
  13. Peter

    Jason Curl Guest

    I have a question about this particular line, printing the value of 'x'.
    Why is this wrong? The memory allocated by x is on the function stack,
    and I didn't believe you are accessing any invalid memory region?

    Sure, I don't really see a point in accessing x, unless you have a
    complex datastructure and you wish to free the memory, and then set
    everything that was assigned to 'x' to NULL (even that can be avoided, I
    only wanted to provide an example).

    For example, I can see a malloc library for debugging (e.g.
    ElectricFence) complaining on the first line, but not the second.
    Jason Curl, Sep 22, 2004
  14. No, 'x' is obbviously not dereferenced in the second line, so no
    memory is accessed that isn't owned by the program. But even
    determining the address stored in the pointer after free() has
    been called on it invokes undefined behavior. In the C89 standard
    (or draft) you will find in the section where malloc() and free()
    etc. are described the sentence

    The value of a pointer that refers to freed space is indeterminate.

    And later in the appendix, listing the circumstances under which
    undefined behavior results, you have

    The behavior in the following circumstances is undefined:

    * The value of a pointer that refers to space deallocated by a call
    to the free or realloc function is referred to ($4.10.3).

    That means using the value of the pointer itself (which, of course,
    is unchanged by the call of free()) and not what it is (or was)
    pointing to. That was also quite a surprise for me when I first
    learned about it;-)

    But it allows to write a conforming C compiler even on a machine
    that e.g. has dedicated address registers and automatically checks
    on loading an address into such a register if the address belongs
    to the address space of the process and traps (e.g. kills the pro-
    gram) if it doesn't (with an exception for the NULL pointer). If
    on such a machine free()ed memory would be removed from the pro-
    cesses address space the pointer would, after the call of free(),
    be invalid in the sense that loading it into an address register
    would trap, even though the content (i.e. the bits stored in the
    pointer) didn't changed at all. But I haven't seen a machine yet
    were that would happen, but my experience isn't very large in that
    ElectricFence (and probably also most of the other memory debuggers)
    don't seem to check for the problem with the second line. I guess
    that's using the value of a free()ed pointer isn't an issue on most
    machines and checking for that could be rather difficult.

    Regards, Jens
    Jens.Toerring, Sep 22, 2004
  15. I think it is not necessarily true, not all operating systems clear the
    memory before allocating it to another program. Probably if he is really
    concerned about security issues on his data that is freed he should
    clear it before freeing, and even ask the SO to not let it go to its
    swap space.

    Felipe Magno de Almeida
    UIN: 2113442
    email: [email protected] unicamp br, [email protected] com
    I am a C, modern C++, MFC, ODBC, Windows Services, MAPI developer
    from synergy, and Computer Science student from State
    University of Campinas(UNICAMP).
    To know more about:
    current work:
    Felipe Magno de Almeida, Sep 22, 2004
  16. Peter

    Dan Pop Guest

    Concrete examples, please.
    Before calling exit() or returning from main(), do you also clear all the
    statically allocated data? What about the sensitive information that
    might be still existing in the stack segment, but your program can no
    longer reach? What about the copy of the data that might be still
    existing on the swap partition?

    There is no point in attempting to do the OS job: it can do it better,
    faster and more reliably.

    Dan Pop, Sep 22, 2004
  17. [Posted only to comp.lang.c; my server doesn't carry alt.comp.lang.c.]

    While this is true (there has existed at least one operating
    environment where memory was not cleared before being allocated to a
    program), all operating systems which meet the Orange Book C2
    security criteria, or a higher level, must have "object reuse"
    protection, which includes such clearing of memory.

    That means that most C programmers writing code for general-purpose
    OSes will not have to worry about manually clearing memory, at least
    for this purpose.

    Of course, as we point out to people all the time on c.l.c, not all C
    programs are written for general-purpose OSes. However, the subset
    of conforming C implementations which provide malloc (ie either are
    hosted, or provide it as an extension in a freestanding implementa-
    tion), which have any "operating system" to speak of and support
    multiple "processes" (so one can allocate memory freed by another),
    and which also do not provide object reuse protection, is likely to
    be quite small - and people working in it probably know who they are.
    If he's really concerned with the security of his data, he's looking
    at a subject far too large and off-topic to discuss in comp.lang.c.
    There's a wealth of research and commentary on this subject readily
    available on the Internet; this is not the place to rehash a few bits
    of it.

    Michael Wojcik

    Company Secretary Finance Manager
    1) Half-grey haired executives.
    2) Must be waist-deep in their field of activities.
    3) Must be having the know-how and the do-how of the latest
    developments in their respective fields.
    -- from "Appointments Vacant" section of Business India
    Michael Wojcik, Sep 22, 2004
  18. Peter

    Chris Torek Guest

    [posted only to comp.lang.c -- alt.comp.lang.c does not exist on
    Let me back things up a bit. Suppose instead of "int *x" or even
    "int y", or "float z", I tell you only that I have four bytes in
    memory that are set to 0x12, 0x34, 0x56, and 0x78 in sequence.

    What is the value stored in this four-byte region? Is it 0x12345678?
    Is it perhaps 0x78563412? Or could it even be something like

    The answer is: it depends. Those four bytes are, as a 32-bit int,
    the first value (0x12345678) on a SPARC or 680x0-based machine,
    but the second (0x78563412) on an Intel x86-based machine. The
    third (1.73782e34, or 7019017 * pow(2,91)) occurs if those four
    bytes are meant to be interpreted as a 32-bit floating point number
    on the x86.

    Clearly, then, the value of some sequence of bytes depends on the
    *interpretation* of that byte-sequence. The next question I would
    like to ask, then, is this: How are the bytes making up a pointer

    On many machines, they happen to be interpreted in precisely the
    same way as some integer; but this is not the only possible
    interpretation. Those who used the x86 in its early 80186 and
    80286 incarnations should remember the "1-megabyte pointer", in
    which the upper 16 bits represented the top 16 of the 20 bits of
    the address, and the lower 16 bits represented the bottom 16 of
    the 20 bits of the address, with those two values being summed:

    real_20_bit_address = ((upper_16(ptr) << 4) + lower_16(ptr)) & 0xfffff;

    (This means that any given physical address has lots of different
    32-bit values that refer to it. This particular "feature" was the
    source of a lot of problems and the term "pointer normalization".
    It is also one reason that the C standards define "a < b" only for
    pointers a and b into a single object, while "a == b" is defined
    even if a and b point to different objects -- the equality operators
    must normalize their pointers, while the relational operators are
    allowed to compare only the offsets.)

    Yet another interpretation was allowed on some varieties of the
    x86, in which the upper 16 bits of the pointer were an index into
    an (external) table, and the lower 16 bits were an offset to be
    applied to the result of the table:

    real_NN_bit_address = table[upper_16(ptr)] + lower_16(ptr);
    /* more or less */

    All of these interpretations -- and indeed almost any other
    interpretation anyone can think of yesterday, today, or tomorrow
    -- are allowed (but not required) by the C standard. The last of
    the above, with the table-lookup step, happens to allow something
    else the x86 did: the table need not contain just a "base address".
    It can also contain a "valid" flag:

    if (table[upper_16(ptr)].valid == 0)
    throw_runtime_error("invalid address");
    real_NN_bit_address = table[upper_16(ptr)].base + lower_16(ptr);

    Now, all free() needs to do is contain, as one of its steps:

    table[upper_16(ptr)].valid = 0;

    and suddenly a bit pattern that *was* valid, before the call to
    free(), is no longer valid. An attempt to print it, which used
    to work, may now cause a runtime "invalid address" error.

    The bit pattern has not changed. What changed is the external
    table. The C standard allows this, and tells you -- the C programmer
    -- not to attempt to use the value in x after passing that value
    to free(), just in case free() cleared the table's "valid" bit.

    Of course, as Jens wrote, you *are* allowed to overwrite x with a
    new value, or with NULL. Any C compiler must make sure this works,
    even if it has this kind of "valid/invalid table entry" action that
    goes on with malloc() and free().

    This is all part of a more fundamental issue, which C programmers
    in particular should consider, because C has "C bytes" that can be
    used to access hardware-level "representations" instead of
    language-level "values". That issue is: the *representation* of
    a value, and value itself, are different things. Values arise
    through *interpretation* of some bit pattern (a "representation"),
    and the process of interpretation can be quite complex. We see
    this now, today, on conventional architectures, only in floating-point
    numbers -- but in the past, we saw such things elsewhere. There
    were good reasons for complicated interpretations for pointers,
    and those reasons may well recur in the future.

    ["Methods of interpretation" are also the reason we see byte-order
    issues in integers. If some entity takes a long string of bits
    and breaks it up into groups of, say, 8 at a time, it is that entity
    that chooses which order to put out the groups, and then to
    re-assemble them for later re-interpretation as a larger group.
    Any given machine may have its own method(s) for splitting and
    combining to get 8-bit groups, but if you, as a C programmer, deal
    in terms of (integral) *values*, and do your own splitting and
    combining, *you* can control the results, rather than being at the
    mercy of your machine(s).]
    Chris Torek, Sep 23, 2004
  19. I know gpg has a lot of code to try to make it more secure wherever it
    runs on, trying even to not let the OS to put its data on the swap, and
    not all OSes must do it, if all do, better. And I agree with Michael
    Wojcik that here is not the place for this discussion.

    Felipe Magno de Almeida
    UIN: 2113442
    email: [email protected] unicamp br, [email protected] com
    I am a C, modern C++, MFC, ODBC, Windows Services, MAPI developer
    from synergy, and Computer Science student from State
    University of Campinas(UNICAMP).
    To know more about:
    current work:
    Felipe Magno de Almeida, Sep 23, 2004
  20. Peter

    Dan Pop Guest

    Does this prove *anything* at all?
    Then why did you start it here in the first place?

    Dan Pop, Sep 24, 2004
    1. Advertisements

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments (here). After that, you can post your question and our members will help you out.