Visual Studio 2012 introduced a new framework for writing debugger visualizers for C++ types that replaced the old autoexp.dat file. The new framework offers xml syntax, better diagnostics, versioning and multiple file support.

Visualizers are defined in XML files with extension .natvis. These visualizers are loaded each time the debugger starts. That means if you make a change to visualizers, it is not necessary to re-start Visual Studio, just re-start the debugger (for instance detach and re-attach the debugger to the process you debug).

These files can be located under one of these locations:

  • %VSINSTALLDIR%\Common7\Packages\Debugger\Visualizers (requires admin access)
  • %USERPROFILE%\My Documents\Visual Studio 2012\Visualizers\
  • VS extension folders

In Visual Studio “14” CTP (in response to a UserVoice request) these files can also be added to a Visual C++ project for easier management and source control integration. All you have to do is add the .natvis file to your .vcxproj file.

Here is an example. Suppose we have the following code:

If you run this in debugger you can inspect the value of p and it looks like this:
natvis1

To change the way the point objects are visualized create a file called point.natvis with the following content:

Add this file to the project.
natvis3
When you run the application in debugger again the point object is visualized according to the per-project .natvis file.
natvis2

UPDATE
There are two things to note:

  • changes in the natvis files are now picked up automatically by the debugger; you no longer need to stop the debugging session and then start again if you make changes to a natvis file
  • natvis files from the project are evaluated after all the other files from the other possible locations; that means you can override existing (general) visualizers with project-specific visualizers

For more see Project Support for Natvis.

, , , , , Hits for this post: 33536 .

CPtrArray is a nasty MFC container that should not be used. However, if you deal with legacy code you may not have a choice and have to work with it. Unfortunately, the Visual Studio debugger is not able to display its elements, since these are pointers to void and that can be anything. In this post I will explain how to write a visualizer for Visual Studio 2012 to address this problem.

Overview

Visual Studio 2012 has introduced a new framework for writing debugger visualizers for C++ types. This replaces the old autoexp.dat (that you might be familiar with). The new framework offers xml syntax, better diagnostics, versioning and multiple file support.

Visualizers are defined in XML files with extension .natvis. These visualizers are loaded each time the debugger starts. That means if you make a change to visualizers, it is not necessary to re-start Visual Studio, just re-start the debugger (for instance detach and re-attach the debugger to the process you debug). These files can be located under one of these locations:

  • %VSINSTALLDIR%\Common7\Packages\Debugger\Visualizers (requires admin access)
  • %USERPROFILE%\My Documents\Visual Studio 2012\Visualizers\
  • VS extension folders

You can read how to write visualizers in these articles:

Writing the visualizer

There are two things you must do to enable Visual Studio debugger to display CPtrArrays in a nice way.

The first step is to define a type derived from CPtrArray. This type will not be used in code, but will allow the visualizer to figure what is the type of the array elements.

The second step is to create a .natvis file (let’s call it mfc.natvis) under %USERPROFILE%\My Documents\Visual Studio 2012\Visualizers\ with the following content:

And that’s all. Let’s see how this works. Assume we have the following code:

In the Watch window cast the pointer to the array object to CPtrArray<T>. This is where the template type defined above is used. Even though your array is not an instance of CPtrArray<T> it will still work since the derived type does not add anything.

vscptrarrayvis1
As you can see in the screenshot, the content of the CPtrArray is nicely expanded.

You probably noticed the nd specifier in the watch expression. This specifier (probably standing for “no derived”) displays only the base class info of the object, and not the derived parts (see Format Specifiers in C++). Without this specifier, when the MFC symbols are loaded (for mfc110xx.dll) the array is not visualized correctly.
vscptrarrayvis2

A simpler hard-coded solution

If you don’t want (or cannot) add the generic type CPtrArray<T> you can still accomplish the same, but with some drawbacks.

In this case the .natvis file should look like this:

You must change the placeholder TYPE with the actual type of the array elements in ValueNode. Then, all you have to do is add the object in the watch window.

However, the big disadvantage of this solution is that all the CPtrArrays in your code are treated in the same manner, as storing elements of type TYPE*. That means if you want to watch arrays of different types, you have to stop the debugger, change the visualizer and attach again. It is impossible to watch arrays that store different element types in the same debugging session.

, , , , , Hits for this post: 45943 .

When you run your (unmanaged/C++) application in debugger, you see at the end a report of memory leaks (if any are detected). Something like this:

Detected memory leaks!
Dumping objects ->
f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\strcore.cpp(141) : {381} normal block at 0x001FFC30, 54 bytes long.
Data: < x > 0C 00 B9 78 12 00 00 00 12 00 00 00 01 00 00 00
d:\marius\vc++\memoryleakstest\memoryleakstestdlg.cpp(163) : {380} normal block at 0x001FFBF0, 4 bytes long.
Data: <@ > 40 FC 1F 00
f:\dd\vctools\vc7libs\ship\atlmfc\src\mfc\thrdcore.cpp(306) : {374} client block at 0x001FFA38, subtype c0, 68 bytes long.
a CWinThread object at $001FFA38, 68 bytes long
Object dump complete.

Some of them can be fixed immediately, because when you double click on them Visual Studio will take you to the line where the allocation was made. Some of them are harder to spot, because Visual Studio is not able to do the same. Question is how do you find the source of those allocations? Luckily, there is this global variable called _crtBreakAlloc, that can be used to force the debugger to stop the execution when a certain block is allocated.

In order to use that, you should follow several steps:

  • First, you have to find a reproducible sequence that produces the same memory allocation number. When memory blocks are allocated, they are identified with a number, called allocation number. This number is reported by Visual Studio in brackets when it lists the memory leaks (e.g. {381}).
  • Second, you have to put a breakpoint somewhere in your program to force a stop at the beginning of the execution. That means you could use function main(), your CWinApp derived class constructor, function InitInstance() or other, depending on your application type and how early in the execution of the program the block that leaks is allocated. The smaller the allocation number is, the earlier in the execution the allocation occurs.
  • Run your program in debugger.
  • When the program stops (at the first breakpoint) open the Watch window and add the following expression: {,,msvcr90d.dll}_crtBreakAlloc in the Name column. In the Value column (which by default should have the value -1) write the allocation number. Take notice that msvcr90d.dll (which is the DLL that contains the C++ runtime library) is specific to Visual Studio 2008 (and is the debug version). If you use another version of Visual Studio, you have to use the appropriate DLL.
  • Continue debugging.
  • When the block identified by the allocation number set in the Watch window is allocated, the debugger will stop the execution and jump to a line from dbgheap.c.

    In order to see the line in your code that triggered the allocation, open the Call Stack window and find, from top down, the first function from your own code.

    That will lead you to the source of the memory leak.

To read more about this topic see:
How to: Set Breakpoints on a Memory Allocation Number
How to use _crtBreakAlloc to debug a memory allocation

, Hits for this post: 49866 .

I’ve recently discovered a new nice feature in the natice debugger of Visual Studio 2008: the visualization of bit flags.

Let’s take this enumeration for example. Notice that each constant is basically a bit flag.

If we used those bitfields like this:

The debugger shows them like this:

Bit fields visualization in debugger.

However, if the constants are not bit flags, they are not shown. If you declare the enum like this:

you won’t get that in the debugger.

, , , Hits for this post: 41884 .

Suppose you have the following code:

When running the program, the following window is popped up:


When running it in the debugger, a different window is popped up:


and the debugger takes you to the line of code that threw the exception. Looking into the output window, you can see something like this:

First-chance exception at 0x7c812a5b in win32test.exe: Microsoft C++ exception: std::runtime_error at memory location 0x0012fd70..
Unhandled exception at 0x7c812a5b in win32test.exe: Microsoft C++ exception: std::runtime_error at memory location 0x0012fd70..

It shows a first-chance and an unhandle (also knows as second-chance) exception message. When running a program in debugger, the debugger always sees the exception before the program does. Thus, it is said that the debugger gets a first chance to handle the exception. If it does not do that, and the execution continues, the program will see the exception and has a chance to handle it. If the exception is not handled by the program, the debugger gets a second-chance to see the unhandled exception. This is the point when in the absense of the debugger, the program crashes.

So, what happened with the program above: the debugger saw an exception and printed the first-chance exception message, but did not handle it, and the program was allowed to continue. However, the program did not handle the exception either, and the debugger got its second-chance with the unhandled-exception; the unhandle exception messages was printed and the exception windows was popped.

Of course, you could change to code in function main to this:

In this case when run, the program will not crash. But when running in the debugger, you will see the first-chance exception message:

First-chance exception at 0x7c812a5b in win32test.exe: Microsoft C++ exception: std::runtime_error at memory location 0x0012fd5c..

In this case, the program handled the exception (by doing nothing) and the debugger did not get the second-chance.

Now, suppose your program is much langer than the several lines of code shown above. When running in the debugger you see first-chance exception messages, but not the second-chance exception message, because your program handles the exception. Should you investigate the cause of the exception, problems arise simply because you don’t know where the exception was thrown. The good news is that you can customize the debugger to break on first-chance exception.

From the Debug menu, use the Exceptions command to open the dialog that allows you to specify on which exception should the debugger break.

There are several categories:

  • C++ exceptions
  • Common Language Runtime Exceptions
  • Managed Debugging Assistants
  • Native Run-Time Checks
  • Win32 Exceptions

By default, none of the C++ exceptions is checked. That means if you check std::exception (as shown in the picture), the debugger should stop when and exception of a type derived from std::exception is thrown. (To verify that run the code aboe in the debugger again.)

What if std::runtime_exception was replaced with a custom exception, foo_exception?

Of course, the debugger would not stop when having the first-exception to handle it, because foo_exception is not in its list. You can however, change than by adding foo_exception to the list from the Exceptions dialog (as shown below) and check it for breaking on first-chance.

Running again would stop the debugger when foo_exception is thrown.

, , Hits for this post: 32165 .