   [code, debugging] Superpig on Debugging
ArticleAuthor: Our very own Richard Fine   
  I'm on this one. Looks good initially. I'll have a more complete edit/review by this evening.   ;  Ok, first impressions: It's very Windows/MSVC heavy. While we can't really do anything to really fix this without severly disrupting the flow of the article, we can apply a few patches. One way is to mention some more *nix or multi-platform instrumentation and static analysis tools such as Valgrind, Paul Nettle's mmgr, RATS, ITS4 and FlawFinder. Another way is to beef up the preventative measures section, such as mentioning preferring std::vector and std::string to manual memory management or avoiding C style I/O, memory and string management functions.One missing detail in the MSVC debugger coverage: breaking on an exception even if the exception is handled. Also, I noticed that the article is title an Introduction to Debugging. Is there a follow up intended?   ;  No, no followup intended.I'll add references to more platform-independent analysis tools - the main reason I didn't mention them is because I'm not generally familiar with them. I'll also add to the preventative measures section as you suggest.If you'd prefer, we could change the name of the article to "An Introduction to Debugging with Microsoft Visual Studio," but I'm concerned that it might put off people who aren't using Visual Studio (and I reckon it still contains useful information for them).(I deliberately headed in a Win32/MSVS direction partly because it's the area in which my knowledge is strongest, partly because that's what most newbies seem to be using, and partly because it's the area where I've got the necessary contacts in DevDiv @ MS to guarantee accuracy of information).   ;Quote:Original post by superpigIf you'd prefer, we could change the name of the article to "An Introduction to Debugging with Microsoft Visual Studio," but I'm concerned that it might put off people who aren't using Visual Studio (and I reckon it still contains useful information for them).I think '..with Microsoft Visual Studio' title fits the content a bit better to be honest. I also don't think it'd have that much of a "put off" effect. Up to you guys though [smile]Cheers,Jack   ;  I think we can leave the title. Though if there is no follow up planned we might want to write/commission an article on the MSVC debug heap.   ;New version, with the changes you requested implemented.   ;  Ok, grammar edit version  here. Mostly breaking up some of the longer sentences and some word choice stuff. But now that I've gone over it in depth, I've got more content comments.First off, the operating system can have more debugging information that just detecting crash situations. For example, run this program on Win XP SP2:#include <windows.h>int main(int, char **) {  HANDLE heap = GetProcessHeap();    void * ptr = HeapAlloc(heap, 0, 125);  ZeroMemory(ptr, 128);  HeapFree(heap, 0, ptr);  return 0;}Outside the debugger it should run fine. Inside the debugger, HeapFree() should trigger a user breakpoint that indicates that there has been heap corruption: the process has written past the end of the allocated range. This should also be the behavior on earlier XP versions as well as Win2K, but I don't have any such machines to test on.Also, you say that the simplest way of setting a breakpoint is to click on the line and press F9. This is patently false. The simplest way of setting a breakpoint is to click just to the left of the line of code. One click, no keys.In the symbols section, you make the claim that symbols are removed from executables. That's not always the case. Debug builds often contain symbol information embedded in the executable, making them debuggable without a PDB. Even release builds can contain limited symbol information, if the symbols have been properly exported.In the description of the call stack, you mention that WinMainCRTStartup() and _tmainCRTStartup() are provided by Windows. They aren't; they're provided by MSVC. The linker sets the entry point to WinMainCRTStartup(), which is what Windows sees as the first function to be called by the system after the loader has gotten the executable into memory. These function initialize the C runtime, which then calls WinMain() after the C runtime is intialized (such as setting up the free store and CRT specific locks).You mention that the disassembly view is not frequently used. I would have to disagree. I use the disassembly view all the time. Since C++ has so much implicitly generated code, diassembly view is often the fastet way to see what the program is doing at steps between certain sequence points. For example, to see what order the compiler decided to call a set of overloaded operators without stepping through the sodding mess. Of course, this one is fairly opinion based.In the access violation section you mention 0xFEEEFEE being a probable recently deleted variable, which doesn't really match anything I've seen. However, the MSVC debug heap puts 0xFDFDFDFD in the no-mans land, so a value in that area actually probably means reading past the end of an allocated buffer.The section on warnings is a bit misleading. Many, if not most, compilers cannot disable warnings via pragmas. MSVC, which can, allows you to disable a warning for a small scope by pushing the warning state and then popping it again, making disabling warnings via pragmas less troublesome than you indicate in the article. This leads to useful techniques such as creating headers to wrap the inclusion of third part headers that have benign warnings. What you need to watch out for is disabling warnings via command line/project settings.Also, would mind redoing some of the images, like the watch window stuff. Basically anything that won't fit on a word page probably won't work well on 1024 in the featured article page by page layout. (Stupid sidebars)There'll probably another semi-large edit to break it into smaller sections to make it fit better into the featured article format.   ;  Updated version based on this feedback is here. It also includes a couple of edits in response to further feedback I've had from Microsoft. Responses to issues you raised:Quote:Original post by SiCraneFirst off, the operating system can have more debugging information that just detecting crash situations...Note added, but I don't want to add a demonstration of it. The sort of people that this article is aimed at won't generally be working with custom heaps.Quote:Also, you say that the simplest way of setting a breakpoint is to click on the line and press F9. This is patently false. The simplest way of setting a breakpoint is to click just to the left of the line of code. One click, no keys.Good call, don't know how I missed that. Fixed.Quote:In the symbols section, you make the claim that symbols are removed from executables. That's not always the case. Debug builds often contain symbol information embedded in the executable, making them debuggable without a PDB. Even release builds can contain limited symbol information, if the symbols have been properly exported.You're quite right, though the default on VS.NET 2005 seems to be to create PDBs in both instances. I've clarified the section a little to talk about symbols-in-executable versus symbols-in-PDB.Quote:In the description of the call stack, you mention that WinMainCRTStartup() and _tmainCRTStartup() are provided by Windows. They aren't; they're provided by MSVC.Fixed.Quote:You mention that the disassembly view is not frequently used. I would have to disagree. I use the disassembly view all the time. Since C++ has so much implicitly generated code, diassembly view is often the fastet way to see what the program is doing at steps between certain sequence points. For example, to see what order the compiler decided to call a set of overloaded operators without stepping through the sodding mess. Of course, this one is fairly opinion based.Well, I've added an 'in my experience' qualifier. I think I'd like to assert again that the audience for this article won't be needing to do that too often (not everybody can write wicked sick "vector1 <cross> vector2" code, y'know). If they're operating at a level where they'd be able to make sense of the information, then I'd imagine they can figure out that the disassembly view is the correct tool for viewing fine-grained program flow. And besides there's always Step Into. [smile]Quote:In the access violation section you mention 0xFEEEFEE being a probable recently deleted variable, which doesn't really match anything I've seen.From here. Quote:However, the MSVC debug heap puts 0xFDFDFDFD in the no-mans land, so a value in that area actually probably means reading past the end of an allocated buffer.Added.Quote:The section on warnings is a bit misleading. Many, if not most, compilers cannot disable warnings via pragmas.Added. GCC doesn't seem to be able to; I don't know about any others.Quote:MSVC, which can, allows you to disable a warning for a small scope by pushing the warning state and then popping it again, making disabling warnings via pragmas less troublesome than you indicate in the article. This leads to useful techniques such as creating headers to wrap the inclusion of third part headers that have benign warnings.Added. I may have been deliberately overly-doomsaying on disabling warnings as I really want to discourage people from using it (i.e. it would be better to get in touch with the third party and get them to fix their headers than to disable the warnings).Quote:What you need to watch out for is disabling warnings via command line/project settings.I'm not sure I even want to mention that such a thing is possible [grin] Note added.Quote:Also, would mind redoing some of the images, like the watch window stuff. Basically anything that won't fit on a word page probably won't work well on 1024 in the featured article page by page layout. (Stupid sidebars)Can do. What sort of sizes do you want me to target?;Quote:Original post by superpigNote added, but I don't want to add a demonstration of it. The sort of people that this article is aimed at won't generally be working with custom heaps.Well... on many MSVC versions when run from the debugger (including release builds), the CRT just forwards calls to HeapAlloc(). So you don't need to be running custom heap allocations in order to run into the OS flagging heap corruption for you. Ex: On my computer with MSVC 7.1, this program exhibits the same behavior as the previous program if run from the debugger in release mode:#include <cstdlib>#include <cstring>int main(int, char **) {  void * ptr = malloc(125);  memset(ptr, 0, 128);  free(ptr);    return 0;}(This is just conversational, what you have in the article now is fine for me.)Quote:What sort of sizes do you want me to target?I'd try to bring them down to 750 px wide. Though we can probably get away with 850-900.Overall, it's looking good. Hopefully sometime this week I can take the time to go line-by-line and format this guy.   