Search code examples
cmemorymemory-managementmallocfree

Why Can I Trust Memory Allocation?


I'm currently taking an introductory CS course that uses C. My textbook seems to imply that a pointer variable still holds the address for memory previously allocated to it, even after free() was called on it -- assume I previously used malloc(). Does this mean that portions of memory become "locked" when malloc() is called so the data of my pointer remains constant? What prevents other processes -- say google chrome or some app -- from messing with my variable? I could easily assign a value to an array at an invalid index, causing things to break. I could also access memory improperly, again using an array at an invalid index, giving me garbage or, if I'm really really lucky, a value that is meaningful to me. What is preventing a computer from spiraling into chaos!


Solution

  • What is preventing a computer from spiraling into chaos!

    The modern processors have a mode of operation called protected mode with virtual memory - a normal program (process) runs in so-called user-mode, and sees a memory space distinct from other currently running processes. The operating system then makes sure that all such misbehaviour is contained within one such process - while it is probable that such access would cause a crash, it would be contained into just this one process.

    This wasn't true in older versions of Windows - while the Windows 3 could use the x86 protected mode, it ran all programs under the same privilege level - there the dreaded Blue Screen of Death might have taken the whole system down:

    BSOD


    As for the part that

    My textbook seems to imply that a pointer variable still holds the address for memory previously allocated to it, even after free() was called on it -- assume I previously used malloc().

    This isn't actually strictly true. The C standard specifically says that after free is called on a pointer, the value of the pointer itself becomes indeterminate. It might still point to the same address on your implementation, but all bets are off. The following program might even crash on some platform:

    void *ptr = malloc(42);
    free(ptr);
    
    // some other code that is between here...
    
    if (ptr) {
        ...
    }
    

    As the C standard says at 6.2.4p2

    The value of a pointer becomes indeterminate when the object it points to (or just past) reaches the end of its lifetime.

    And Appendix J.2. Undefined behavior:

    The value of a pointer to an object whose lifetime has ended is used (6.2.4).

    One possible behaviour could be caused by the compiler knowing that the value is not needed after free. Thus if ptr in the above code was stored in a register, the compiler is free to overwrite the value for some code in between there, and subsequently the variable ptr could behave as it was an uninitialized value by the time it was used in the if.

    Using a pointer whose value is indeterminate will result in all sorts of funny behaviour, such as evidenced by this question here. The compiler need not produce the value that you'd expect, it just needs to conform to the standard.


    In any case, the book is correct in that you're not to use the ptr after free(ptr) until you've set a new value to it, it is just that the specific example in the book is misleading as it is just one of the many possible outcomes, as is common for undefined behaviour in C.