Wednesday, August 19, 2015

Debugging memory errors using Application Verifier

Debugging memory management errors

Few days ago, one of my applications started crashing both on Linux and Windows because of a memory corruption. Many tools are available to debug such issues; I usually use the open source valgrind on Linux, while I prefer instrumentation based tools on Windows.
But the application I had to debug was so large that the instrumentation based tools either failed to instrument it or succeeded in instrumenting the binary but then failed quite soon at runtime. Valgrind was successful in running my application, but generated such a large number of false positives that it was really difficult to locate the source of the error I was interested at.
I finally found information about Application Verifier and tried it for the first time: and it was really successful in helping me finding the memory issue, by pinpointing the line of code that executed the wrong memory access.
The reminder of this article shows how to use Application Verifier to debug memory issues, using a simple example.

Using Application Verifier to debug memory issues

Let's start with a simple example, that shows how Application Verifier helps in diagnosing memory issues:
struct A { int i; };

int main(int argc, char *argv[]) {
    A *a = new A;
    a->i = 0;
    delete a;
    a->i = 1; // Writes in a freed memory region
    return 0;
}
In this example, it is quite obvious which is the error: a write in a freed memory region.
But if you run it, even in debug mode, under Visual Studio, the program completes successfully, with no error. In a more complex program it is possible that an error gets reported at a later time when the memory region gets reused and reallocated. But at that point it is very complex to understand which line of code corrupted it.
And this is exactly what was happening to my application: when the error was reported I had absolutely no idea of when and where the corruption occurred.

And now Application Verifier enters into the picture. You can find it in the start menu: All Apps -> Windows Kits -> Application Verifier.
Once started, Application Verifier shows a simple dialog:


Now you have to tell Application Verifier to monitor your executable. You can add your executable by either right clicking in the left pane or by pressing Ctrl-A. A file selection dialog appears and you have to select the debug version of your executable. Visual Studio usually creates it in the Debug folder of your Project or Solution:


As you can see from the above picture, Application Verifier offers, for each executable, many options. The Basic checks (selected by default) are enough to debug memory issues.
The next step is to run again, preferably in debug mode, your executable from Visual Studio. This time the result is:


So now the runtime throws an exception as soon as the bad memory write occurs. Pressing the Break button the debugger stops at the code line that executes the write:


So Application Verifier is simple to use and the results are good: it allows to discover the source of a bad memory access, stopping the program exactly at the time (and code line) where the access occurs and not at a later time, i.e. when the effects of the bug start to be apparent but when it is also too late to understand the source of the issue.
It really helped me in solving my bug.

No comments:

Post a Comment