4

I know it free memory from the heap. But how does the program know that the memory being freed (or not freed). If I have to guess, there's some kind of "available-memory-list" somewhere in the program's memory. If that's the case, how does that list structured? Is it managed by the program or by the operating system?

I created a simple program to tryna find out whats going on :

#include <iostream>
int main () {
    int* ptr = new int;

    *ptr = 0xFFFFFFFF;

    std::cout << ptr << std::endl;      //some random 64-bit address
    std::cout << *ptr << std::endl;     //-1

    delete ptr;

    std::cout << ptr << std::endl;      // always 0x0000000000008123
    std::cout << *ptr << std::endl;     // Exception thrown: read access violation.

    return 0;
}

Memory location pointed by ptr before the delete operator:

memory location pointed by ptr

That same memory location but after the delete operator:

That same memory location but after the delete operator

Why is that old memory location always filled with 0xDDDDDDDD after being deleted? Is it a mark that indicates the memory is freed? Why is it even bother doing so if it already keeps track of it in the assuming "available-memory-list"? I mean writing to memory take some effort (even though negligible in this example), why don't just leave it there until something else overwrite on it.

Although initially the ptr is pointing to some random address, but after the delete operation, it always pointing to 0x0000000000008123. Is it also a mark that indicates the pointer is now pointing to an inaccessible memory block?

(I'm using visual studio 2022 on a windows 10, 64-bit operating system)

Just some links to a good article can also be helpful. Thank you.

canh25xp
  • 53
  • 4
  • 6
    Are you in a debug build? I'm not sure anything changes in a release (optimized) one. In a debug build there are conveniences like that to expose Use-After-Free bugs. You're effectively creating one by referencing `*ptr` here after it's been deleted, and the memory overwrite causes a crash as intended. – tadman Aug 11 '23 at 13:39
  • 4
    _"how does the program know"_ Your program is not required to "know". After deleteing an object, accessing that memory is simply Undefined Behavior. – Drew Dormann Aug 11 '23 at 13:40
  • 3
    Possible duplicate: [When and why will a compiler initialise memory to 0xCD, 0xDD, etc. on malloc/free/new/delete?](https://stackoverflow.com/questions/370195/when-and-why-will-a-compiler-initialise-memory-to-0xcd-0xdd-etc-on-malloc-fre?r=Saves_AllUserSaves) – πάντα ῥεῖ Aug 11 '23 at 13:42
  • 1
    Allocations are handled by both the operating system and the heap manager, which in C++ is encapsulated in the [Allocator](https://en.wikipedia.org/wiki/Allocator_(C%2B%2B)) concept. Although details vary considerably from one OS to another, and one compiler to another, even within different versions, the user process (program) will request blocks of memory from the OS, then carve those up into smaller allocations managed internally. – tadman Aug 11 '23 at 13:42
  • 7
    A quick follow-up to @tadman's comment: that behaviour is Windows-specific (MSVC, not MinGW), and applies to Debug builds only. As he says, it's to protect you from yourself. Don't expect it anywhere else. – Paul Sanders Aug 11 '23 at 13:47
  • 1
    Note the C++ standard doesn't describe how memory managment should work (it doesn't have to be a heap). Only that objects have for example automatic (scoped variables) or dynamic storage (which is managed by new/delete). Note the numbers you are seeing are compiler specific debug values, func fact here are more : https://www.liquisearch.com/deadbeef/magic_debug_values – Pepijn Kramer Aug 11 '23 at 13:57
  • You may want to write your own memory manager as an exercise. For example, you could have a linked list of memory blocks (each block has a size field). Deleting memory would consist of adding a memory block to the list. For advance understanding, your delete operation could try to merge the delete memory block with a memory block from your linked list. – Thomas Matthews Aug 11 '23 at 17:20

1 Answers1

4

Why is that old memory location always filled with 0xDDDDDDDD after being deleted?

Your platform's debug build does a memset on the memory to 0xDD after being freed.

It is not specified in the standard. It is an implementation detail, specific to your platform.

q.v. magic number for the DDDDDDDD value.

Is it a mark that indicates the memory is freed? Why is it even bother doing so if it already keeps track of it in the assuming "available-memory-list"? I mean writing to memory take some effort (even though negligible in this example), why don't just leave it there until something else overwrite on it.

It is there to aid in debugging.

Although initially the ptr is pointing to some random address, but after the delete operation, it always pointing to 0x0000000000008123. Is it also a mark that indicates the pointer is now pointing to an inaccessible memory block?

Probably not. It's undefined behavior even to access ptr after the delete ptr; statement. You should ptr = nullptr; after the delete so it is legal to access the value of ptr again.

Sneftel
  • 40,271
  • 12
  • 71
  • 104
Eljay
  • 4,648
  • 3
  • 16
  • 27