Dangling pointers are pointers whose memory has been freed but which have not been set to null (or 0x0). This allows a particularly tricky class of bug to arise, because it is often possible for subsequent code to keep on using the dangling pointer and to keep on getting valid-looking data – until suddenly that memory is repurposed for something else!
They can lead to unpredictable behavior, silent corruption and program crashes.
Arm Forge 6.0 has better memory debugging than ever - fully-integrated, scalable and packed with features for tracking down and fixing problems. One of the new additions is a feature to find and fix dangling pointers so quickly it feels like magic!
Arm advocates using the scientific method to debug problems that are not solved within a few minutes of ad-hoc investigation. In this case, our hypothesis is that our program behaves in a particular way because of a dangling pointer problem. We will test this with an experiment, then draw our conclusions and come up with a new hypothesis until we arrive at the root cause.
DDT is a powerful tool for uncovering information about all kinds of memory errors, including dangling pointers. In this case we want to use DDT's hardware free protection feature. This advanced feature adds very little overhead to your program but allows DDT to instantly stop your program at the exact line of code that tries to re-use a dangling pointer.
To enable it, put a tick in the “Memory Debugging” option in the Run dialog, then click on “Details...” to open the Memory Debugging Options window. Turn up the “Heap Debugging” to one level higher than Fast. You'll see “free-protect” appears in the “Enabled Checks” window. Click on the “More Information” link to read our documentation on the rich variety of protection DDT can add to your code.
This level of memory debugging is usually all you need to find dangling pointer problems. Now click “Run” to start your program under DDT. If a dangling pointer is reused, DDT will stop your program at the exact line of code that reuses it with an error like this one:
Our hypothesis was proven correct! We know we have a dangling pointer error – and that this line of code is using memory that has been freed. Sometimes that's all we need to know to understand where the problem came from, but frequently it's only the first step of the journey.
DDT can also tell us which pointer is dangling and exactly where it was originally allocated. Click “Pause” to pause execution on the line of code with the error, then look at the variables being used on the line. These also appear in the “Current Line(s)” window on the right. Right-click on any pointers or dynamically-allocated arrays and choose “View Pointer Details” from the menu:
This window shows a wealth of information about any pointer in your program:
Arm DDT tells us at once that this pointer is dangling (it says it points to an allocation that has already been freed) and shows us the full stack of function calls that led to its allocation. In particular, we can see that it was allocated at hello.c:88 and simply clicking on this jumps us to that location in the source code viewer right away.
It also tells us where this memory was deallocated. In this case, at hello.c:89.
We now have all the information we need to help us solve this puzzle. We have identified:
With all the locations relating to this pointer's lifecycle just a click away we can now read the source code to understand why the pointer was used like this and to understand whether it was released too early, not cleared to NULL, or reused inappropriately. After all, the tools can only take you so far – ultimately the program does exactly as it was told to do. The real error is in our expectation that it would work, when we unambiguously wrote that it should not!
Arm Forge helps you to navigate and understand complex parallel codebases efficiently, getting you back on track as quickly as possible. We also provide on-site training courses in effective debugging at all scales using the scientific method and the appropriate tools – including Arm DDT.
Read more about what the memory debugger can help with by visiting the memory debugging in Arm DDT page.
Good hunting!
If I try attaching to an existing program running on my ARM Cortex M3 via gdbserver in OpenOCD, I can't see the "Memory Debugging" option mentioned above, but can otherwise debug the program.
If I go to the "Run", it tries to run the ARM binary on my x86-64 host (resulting in an "exec format error" message) instead on the Cortex M3 where it's needed.
How do I enable memory debugging when debugging a Cortex M3 target?