Lably
Skip to content

Dangling pointer

Pointer that does not point to a valid object

  • 11 min read
  • 6 chapters

Related on Lably

Through Computer programming, Reference (computer science) and Object-oriented programming

Dangling pointers arise during object destruction, when an object that is pointed to by a given pointer is deleted or deallocated, without modifying the value of that said pointer, so that the pointer still points to the memory location of the deallocated memory. The system may reallocate the previously freed memory, and if the program then dereferences the (now) dangling pointer, unpredictable behavior may result, as the memory may now contain completely different data. If the program writes to memory referenced by a dangling pointer, a silent corruption of unrelated data may result, leading to subtle bugs that can be extremely difficult to find. If the memory has been reallocated to another process, then attempting to dereference the dangling pointer can cause segmentation faults (UNIX, Linux) or general protection faults (Windows). If the program has sufficient privileges to allow it to overwrite the bookkeeping data used by the kernel's memory allocator, the corruption can cause system instabilities. In object-oriented languages with garbage collection, dangling references are prevented by only destroying objects that are unreachable, meaning they do not have any incoming pointers; this is ensured either by tracing or reference counting. However, a finalizer may create new references to an object, requiring object resurrection to prevent a dangling reference.

Wild pointers, also called uninitialized pointers, arise when a pointer is used prior to initialization to some known state, which is possible in some programming languages. They show the same erratic behavior as dangling pointers, though they are less likely to stay undetected because many compilers will raise a warning at compile time if declared variables are accessed before being initialized.

Cause of dangling pointers

In many languages (e.g., the C programming language) 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 that location may now be used for other purposes.

A straightforward example is shown below:

<span id="mwKg"></span><span class="p" id="mwKw">{</span> <span class="w" id="mwLA"> </span><span class="kt" id="mwLQ">char</span><span class="o" id="mwLg">*</span><span class="w" id="mwLw"> </span><span class="n" id="mwMA">dp</span><span class="w" id="mwMQ"> </span><span class="o" id="mwMg">=</span><span class="w" id="mwMw"> </span><span class="nb" id="mwNA">NULL</span><span class="p" id="mwNQ">;</span> <span class="w" id="mwNg"> </span><span class="c1" id="mwNw">// ...</span> <span class="w" id="mwOA"> </span><span class="p" id="mwOQ">{</span> <span class="w" id="mwOg"> </span><span class="kt" id="mwOw">char</span><span class="w" id="mwPA"> </span><span class="n" id="mwPQ">c</span><span class="p" id="mwPg">;</span> <span class="w" id="mwPw"> </span><span class="n" id="mwQA">dp</span><span class="w" id="mwQQ"> </span><span class="o" id="mwQg">=</span><span class="w" id="mwQw"> </span><span class="o" id="mwRA">&</span><span class="n" id="mwRQ">c</span><span class="p" id="mwRg">;</span> <span class="w" id="mwRw"> </span><span class="p" id="mwSA">}</span><span class="w" id="mwSQ"> </span> <span class="w" id="mwSg"> </span><span class="c1" id="mwSw">// c falls out of scope</span> <span class="w" id="mwTA"> </span><span class="c1" id="mwTQ">// dp is now a dangling pointer</span> <span class="p" id="mwTg">}</span>

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.

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. As with the previous example one way to avoid this is to make sure to reset the pointer to null after freeing its reference—as demonstrated below.

<span id="mwVg"></span><span class="cp" id="mwVw">#include</span><span class="w" id="mwWA"> </span><span class="cpf" id="mwWQ"><stdlib.h></span> <span class="kt" id="mwWg">void</span><span class="w" id="mwWw"> </span><span class="nf" id="mwXA">func</span><span class="p" id="mwXQ">()</span><span class="w" id="mwXg"> </span><span class="p" id="mwXw">{</span> <span class="w" id="mwYA"> </span><span class="kt" id="mwYQ">char</span><span class="o" id="mwYg">*</span><span class="w" id="mwYw"> </span><span class="n" id="mwZA">dp</span><span class="w" id="mwZQ"> </span><span class="o" id="mwZg">=</span><span class="w" id="mwZw"> </span><span class="p" id="mwaA">(</span><span class="kt" id="mwaQ">char</span><span class="o" id="mwag">*</span><span class="p" id="mwaw">)</span><span class="n" id="mwbA">malloc</span><span class="p" id="mwbQ">(</span><span class="k" id="mwbg">sizeof</span><span class="p" id="mwbw">(</span><span class="kt" id="mwcA">char</span><span class="p" id="mwcQ">)</span><span class="w" id="mwcg"> </span><span class="o" id="mwcw">*</span><span class="w" id="mwdA"> </span><span class="mi" id="mwdQ">10</span><span class="p" id="mwdg">);</span> <span class="w" id="mwdw"> </span><span class="c1" id="mweA">// ...</span> <span class="w" id="mweQ"> </span><span class="n" id="mweg">free</span><span class="p" id="mwew">(</span><span class="n" id="mwfA">dp</span><span class="p" id="mwfQ">);</span><span class="w" id="mwfg"> </span><span class="c1" id="mwfw">// dp now becomes a dangling pointer</span> <span class="w" id="mwgA"> </span><span class="n" id="mwgQ">dp</span><span class="w" id="mwgg"> </span><span class="o" id="mwgw">=</span><span class="w" id="mwhA"> </span><span class="nb" id="mwhQ">NULL</span><span class="p" id="mwhg">;</span><span class="w" id="mwhw"> </span><span class="c1" id="mwiA">// dp is no longer dangling</span> <span class="w" id="mwiQ"> </span><span class="c1" id="mwig">// ... </span> <span class="p" id="mwiw">}</span>

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".

<span id="mwjw"></span><span class="kt" id="mwkA">int</span><span class="o" id="mwkQ">*</span><span class="w" id="mwkg"> </span><span class="nf" id="mwkw">func</span><span class="p" id="mwlA">(</span><span class="kt" id="mwlQ">void</span><span class="p" id="mwlg">)</span><span class="w" id="mwlw"> </span><span class="p" id="mwmA">{</span> <span class="w" id="mwmQ"> </span><span class="kt" id="mwmg">int</span><span class="w" id="mwmw"> </span><span class="n" id="mwnA">num</span><span class="w" id="mwnQ"> </span><span class="o" id="mwng">=</span><span class="w" id="mwnw"> </span><span class="mi" id="mwoA">1234</span><span class="p" id="mwoQ">;</span> <span class="w" id="mwog"> </span><span class="c1" id="mwow">// ... </span> <span class="w" id="mwpA"> </span><span class="k" id="mwpQ">return</span><span class="w" id="mwpg"> </span><span class="o" id="mwpw">&</span><span class="n" id="mwqA">num</span><span class="p" id="mwqQ">;</span> <span class="p" id="mwqg">}</span>

Attempts to read from the pointer may still return the correct value (1234) for a while after calling func, but any functions called thereafter may overwrite the stack storage allocated for num with other values and the pointer would no longer work correctly. If a pointer to num must be returned, num must have scope beyond the function—it might be declared as static.

Sign in to keep reading

5 more chapters are free with a Lably account.

More in Computing and communication