21B. Dangling Pointers

A dangling pointer is a pointer to memory that your program should not use.

Using a dangling pointer is a serious mistake that can be difficult to fix. It can cause a program to behave in strange and unpredictable ways. But the symptoms often become apparent only far from the point where the mistake was made. Using a dangling pointer in one module can cause another module to run amok. It all depends on which place in memory the dangling pointer referred to.

There is a simple rule: Pay attention to what you are doing. Do hand simulations and use pointer diagrams. Make very sure that you do not use dangling pointers.

The standards require your program not to use any dangling pointers in any way. Your program must not fetch or store anything at a memory address given by a dangling pointer, even if it does not affect the execution of the program.

Memory outside this process's memory

Using memory that the OS knows does not belong you always leads to a memory fault. That is the best-case scenario for using a dangling pointer, because you find out about it right away, and you can use a debugger to isolate it quickly.

Memory owned by the heap manager

Storing information into memory that is currently owned by the HM is serious trouble. After performing steps

  int* p = new int;
  *p = 0;
  delete p;
variable p holds a dangling pointer that points to memory that is own by the HM.

The HM needs keep track of which pieces of memory are owned by the running program and which are not, and the HM stores that information in the part of the heap that it owns. When you delete memory, the HM quite likely stores information into the deleted memory. For example, suppose you do the following.

  int* p = new int;
  *p = 25;
  delete p;
  int x = *p;
What would you expect x be? There is really no expectation that you can have, since p is a dangling pointer, and the HM might have stored something into the memory that was just deleted.

Memory that has been deleted and reallocated

Memory that has been deleted does not necessarily belong to the HM. Look at the following.

  int* p = new int;
  delete p;
  int* q = new int;
  *p = 0;
It is entirely possible (but not a sure thing) that the memory that was allocated to p and then given back to the HM is used again for q. By changing *p, you might also change *q because p and q might point to the same place. Your program unwittingly uses the same memory for two different purposes.

The & operator

Using the & operator, you can get the address a of a variable in a function's frame in the run-time stack. After the function returns, the function's frame is removed, and address a becomes a dangling pointer.

Suppose that p is a dangling pointer that points into the run-time stack. What happens when you use p depends on what other things your program has done.

  1. If p points to memory that does not belong to any allocated frame, then your process will get a memory fault.

  2. It is possible that your program has done more function calls, causing more frames to be allocated, and now p points into one of those new frames. Using p will not cause a memory fault, but you cannot know what will happen with it. Storing information into *p will clobber memory in some frame. The consequence of doing that can be arbitrarily bad, so bad that even a debugger cannot tell what has happened. Really.

Uninitialized pointer variables

An uninitialized pointer variable is usually called a dangling pointer simply because you do not know where it points. Performing

  int* p;
  *p = 0;
has unpredictable effects. It is never good. If you draw pointer diagrams and do hand simulations, you will not make this error.

Exercises

  1. What is a dangling pointer? Answer

  2. What are the consequences of using a dangling pointer? Answer

  3. Look at the following.

      int* p = new int;
      int* q = p;
      *p = 50;
      *q = 100;
      delete p;
      printf("*q = %i\n", *q);
      delete q;
    
    Comment on what happens when this is run. Answer

  4. Look at the following.

      int* p;
      *p = 50;
      printf("*p = %i\n", *p);
    
    Comment on what happens when this is run. Answer