C, C++ Pointers: Dangling & Wild Pointers

 

Dangling Pointers

  • Dangling pointer and Wild pointers are pointers that do not point to a valid object of the appropriate type.
  • Dangling references and Wild references are references that do not resolve to a valid destination.

Wild Pointers

  • Wild pointers arise when a pointer is used prior to initialization.

Issues

  • Unpredictable Behaviour - if the pointed memory location is reallocated and valid
  • Segmentation Fault - if the pointed memory location is invalid or unallocated

Causes

1)    In C/C++, deleting an object from memory explicitly or by destroying the stack frame on return does not alter associated pointers. The pointer still points to the same location in memory even though the reference has since been deleted and may now be used for other purposes.

  {
		   char *dp = NULL;
		   /* ... */
		   {
			   char c;
			   dp = &c;
		   } 
			 /* c falls out of scope */
			 /* dp is now a dangling pointer */
	}
  • Solution:
    • If the operating system is able to detect run-time references to NULL pointers, a solution to the above is to assign 0 (NULL) to dp immediately before the inner block is exited.
    • Another solution would be to somehow guarantee dp is not used again without further initialization.

2)    Another frequent source of dangling pointers is a jumbled combination of malloc() and free() library calls: a pointer becomes dangling when the block of memory it points to is freed.

    #include <stdlib.h>
    void func()
    {
      char *dp = (char *)malloc(A_CONST);
      /* ... */
      free(dp);         /* dp now becomes a dangling pointer */
      dp = NULL;        /* dp is no longer dangling */
      /* ... */
    }
  • Solution:
    • one way to avoid this is to make sure to reset the pointer to null after freeing its reference—as demonstrated above.

3)    An all too common misstep is returning addresses of a stack-allocated local variable: once a called function returns, the space for these variables gets deallocated and technically they have “garbage values”.

```
int *func(void)
{
  int num = 1234;
  /* ... */
  return &num;
}
```
  • Attempts to read from the pointer may still return the correct value (1234) for a while after calling func, but any functions called thereafter will overwrite the stack storage allocated for num with other values and the pointer would no longer work correctly.
  • Solution:
    • If a pointer to num must be returned, num must have scope beyond the function—it might be declared as static.

4) Wild pointers are created by omitting necessary initialization prior to first use. Thus, strictly speaking, every pointer in programming languages which do not enforce initialization begins as a wild pointer. This most often occurs due to jumping over the initialization, not by omitting it. Most compilers are able to warn about this.

  int f(int i)
  {
    char *dp;            /* dp is a wild pointer */
    static char *scp;    /* scp is not a wild pointer:

  }
  • static variables are initialized to 0 at start and retain their values from the last call afterwards.
  • Using this feature may be considered bad style if not commented.

Security holes involving dangling pointers

  • Like buffer-overflow bugs, dangling/wild pointer bugs frequently become security holes.
    • If the pointer is used to make a virtual function call, a different address (possibly pointing at exploit code) may be called due to the vtable pointer being overwritten.
    • If the pointer is used for writing to memory, some other data structure may be corrupted.
      • Even if the memory is only read once the pointer becomes dangling, it can lead to Information Leaks (if interesting data is put in the next structure allocated there) or to Privilege Escalation (if the now-invalid memory is used in security checks).
    • When a dangling pointer is used after it has been freed without allocating a new chunk of memory to it, this becomes known as a “use after free” vulnerability.

Avoiding dangling pointer errors

  • The simplest technique is to reset the pointer to NULL, immediately after memory is released.
  • Among more structured solutions, a popular technique to avoid dangling pointers in C++ is to use smart pointers. A smart pointer typically uses reference counting to reclaim objects.
  • Note:
    • In languages like Java, dangling pointers cannot occur because there is no mechanism to explicitly deallocate memory. Rather, the garbage collector may deallocate memory, but only when the object is no longer reachable from any references.

Dangling pointer detection

  • To expose dangling pointer errors, one common programming technique is to set pointers to the null pointer or to an invalid address once the storage they point to has been released. When the null pointer is dereferenced (in most languages) the program will immediately terminate—there is no potential for data corruption or unpredictable behavior. This makes the underlying programming mistake easier to find and resolve. (This technique does not help when there are multiple copies of the pointer.)
Reference