Bugslayer's Tips (zz)

Bugslayer's Tips
//z 2012-09-04 17:56:57 IS2120@CSDN.T1187852306[T12,L120,R4,V119]
At the end of all my Bugslayer columns in MSDN Magazine (and previously Microsoft Systems Journal), I have included a couple of tips. While numerous folks have asked for the complete collection, I'd never had them in one place. Sairama Jamalapuram did us all a big favor and extracted them off the MSDN Magazine web site. If you have a tip you'd like to see in the Bugslayer column so you can play the "search for my name on MSDN" game, shoot me an email.

Happy Debugging! - John Robbins


Tip #1 Get rid of the MSDEV splash screen when using Just In Time debugging. First, run REGEDIT and open the key HKEY_LOCAL_MACHINE\Software\Microsoft\ Windows NT\CurrentVersion\AeDebug. Then, change the Debugger key from "\msdev.exe -p %ld -e %ld" to "\msdev.exe -nologo -p %ld -e %ld."

Source: http://www.microsoft.com/msj/1097/bugslayer.aspx
Tip #2 Always check CloseHandle's return value. Even though there is not much you can do when CloseHandle returns FALSE, it is generally indicative of a serious problem. Since Win32 will reuse handle values, it is quite easy to accidentally close an open handle being used elsewhere in your code, causing weird random bugs. When you call CloseHandle on a handle that has already been closed, it can sometimes cause random crashes that are impossible to track down. Place all your calls to CloseHandle in VERIFY macros so that you stand a fighting chance of finding those bugs in _DEBUG builds. (Thanks to Jim Austin.)

Source: http://www.microsoft.com/msj/1097/bugslayer.aspx
Tip #3 Always use /W4 and /WX with CL.EXE. Why track down bugs yourself when the Visual C++ compiler will find many of them for you, simply by compiling your code? Always set the warning level to 4 so you can catch excellent problems like using uninitialized stack variables, unused variables, and signed/unsigned mismatches. The /WX switch makes the compiler treat all warnings as errors so nothing slips through the cracks. These two command-line switches have caught thousands of bugs for me.

There's only one drawback: many of the standard windows and OLE headers do not compile without warnings. In these cases you can use the #pragma warning directive around those files to turn off warnings and then turn them back on. I have header files called WarningsOff.h and WarningsOn.h that I use in many of my projects to bracket the standard files so they compile.

Source: http://www.microsoft.com/msj/1297/bugslayer1297.aspx
Tip #4 Use /GF to combat really strange memory bugs. The other day at work, we had a case where there was a super-bizarre memory corruption. We eventually tracked it down to someone accidentally using a static string buffer

char szBuff[] = "Static String"
and passing that string to a function that writes to the buffer. If you use the /GF switch on CL.EXE, it places all the static strings into a read-only section of the binary. If any part of the program tries to write to one of the static buffers it immediately causes an access violation. If we had used /GF on all of our code, this bug would have been caught immediately. (Thanks to Matt Pietrek.)

Source: http://www.microsoft.com/msj/1297/bugslayer1297.aspx
Tip #5 This tip is certainly not high-tech, but it helps stop one of the most annoying C/C++ errors people run into. I often compare a variable to a constant, a number, or the return value of a function in a conditional statement. Although it is slightly harder to read, if you get into the habit of placing the operand that cannot be used as a l-value (numbers, constants, functions, and so on) on the left-hand side of the == operator, forgetting to type the second equals sign in the == operator will result in a (more than obvious) compiler error (a five-second fix) rather than having to track down the logic error later (a five-minute fix).

int some_variable;
...
// use this form
if( 3 == some_variable) { ... }
if( SOME_CONSTANT == some_variable) { ... }
if( some_function() == some_variable) { ... }
...
// instead of this form
if( some_variable == 3) { ... }
if( some_variable == SOME_CONSTANT) { ... }
if( some_variable == some_function() ) { ... }
I find that most programmers are not in this habit, and almost everyone says they have run into the "I can't believe I forgot the darn equals sign" problem at least once. A few little habits can save a lot of frustration! (Thanks to Warren Stevens.)

Source: http://www.microsoft.com/msj/0298/bugslayer0298.aspx
Tip #6 One of the best parts about writing this column is getting to talk to a lot of really smart folks who are committed to true software quality. Scot Doyle told me about a Web page authored by one of his coworkers, Andy Lowe, that helped him think about combating software bugs. Andy's page at http://www.pswtech.com/~andy/ten.html [NOTE: Page no longer there! Fortunately saved at:http://www.multimedia-people.co.uk/misc/bugs.html] categorizes the 10 known bugs that programmers make. It's a great discussion of some of the issues that come up in all parts of software development. I strongly suggest that you take a look at it. My favorite line is from the introduction: "(Edsger) Dijkstra deprecates even the concept of debugging as being necessitated by sloppy thinking." Andy, who is also the author of Porting Unix Applications to Windows NT (Macmillan Technical Publishing, 1997), has a few other interesting pieces of writing you might want to check out. Make sure to take a look at his epic poem, "Wiegand."

(Thanks to both Scot, scot@pswtech.com, and especially Andy, andy@pswtech.com.)

Source: http://www.microsoft.com/msj/0298/bugslayer0298.aspx
Tip #7 Back in the October 1997 Bugslayer column, I wrote a library that helped you avoid memory leaks and other memory problems. Simon Bullen has a freeware library (with source code!) called Fortify that works with all ANSI C and C++ compilers. Fortify is far more complete than the code I presented. It has some excellent features for handling things like strdup, as well as a very nice scheme for checking for corrupted memory.

One of the nicest features is the scope leak checking function. While seeing memory leaked at the end of the application is nice, you almost never know exactly where the leak occurred, only where it was allocated. Fortify has some macros that you can call at the start and end of scope and have it dump any memory leaked between the two. Fortify is worth looking at and can be found athttp://www.geocities.com/SiliconValley/Horizon/8596/. Simon mentioned that he is hard at work on the next version and it should be posted by the time you read this. (Thanks to Simon Bullen, sbullen@cybergraphic.com.au.)

Source: http://www.microsoft.com/msj/0498/bugslayer0498.aspx
Tip #8 You know all those Windows structs that have cbSize as the first parameter? If I am going to be using them, I always write my own derived class that initializes the struct. For example:

struct CMenuItemInfo : public MENUITEMINFO {
     CMenuItemInfo( )
    {
        memset ( this , 0 , sizeof ( MENUITEMINFO ) ) ;
        cbSize = sizeof ( MENUITEMINFO ) ;
    }
} ;
I have often spent 10 or 15 minutes tracking down a bug where it turned out I forgot to initialize one of these structs with the #!$% size! (Thanks to Paul DiLascia, askpd@pobox.com.)

Source: http://www.microsoft.com/msj/0498/bugslayer0498.aspx
Tip #9 The Visual C++ debugger has a nasty habit of forgetting any breakpoints you set in a dynamically loaded DLL. Hopefully, the next version of the debugger will have deferred breakpoints like those WinDBG has been offering since the first version of the Win32 SDK shipped with Windows NT 3.1. For now, to keep your breakpoints in dynamically loaded DLLs, you must find the feature buried in the Project Settings Dialog. Open your project and select Project|Settings. In the Debug tab, click in the Catagory dropdown and select Additional DLLs. In the Modules listbox, add the complete path and name of the DLL.

Source: http://www.microsoft.com/msj/0698/bugslayer0698.aspx
Tip #10 The Visual C++ debugger has a very cool and seemingly undocumented AutoExpand feature. The AutoExpand allows the Variables window to automatically show the pertinent data for the different types in their commonly used format. For example, a CRect variable is automatically expanded to show each of the member fields. The file that controls autoexpansion is AUTOEXP.DAT, located in the MSDEV\Shared IDE\BIN directory. The comments at the top of the file list all of the rules for adding new types to the file. The format specifier section shows the items that can be used directly in the Variables window. Some of the more useful items are: s to show strings, su to expand Unicode strings, and c to show character values. To use a format specifier, type in the variable or value followed by a comma, then the format specifier. For example, m_strData,su would view the value as a Unicode string. You can also use C/C++ cast operations in the Variables window to view different items. To view the value at address 0x00404410 as a character string, type in (char*)0x404410.

Source: http://www.microsoft.com/msj/0698/bugslayer0698.aspx

 

Tip #11 One simple thing I've learned to do is to invalidate that which has been deallocated. For example, if you delete a pointer, set that pointer to NULL immediately afterward. If you close a handle, set that handle to NULL (or INVALID_HANDLE_VALUE) immediately afterward. This is especially true when these are members of a class. By setting a pointer to NULL, you prevent double delete calls. delete NULL is valid. (Thanks to Sam Blackburn, sblackbu@erols.com.)

Source: http://www.microsoft.com/msj/0898/bugslayer0898.aspx
Tip #12 In the April 1998 column, I presented a tip about automatically initializing structures that require a size field to be filled out. Reader Simon Salter (simon@chersoft.co.uk) offered an even better way to accomplish this using C++ templates:

template <typename T>
class SWindowStruct : public T
{
public :
     SWindowStruct()
{
     memset ( this , 0 , sizeof ( T ) ) ;
     cbSize = sizeof ( T ) ;
}
} ;
Using this class, you just need to declare a structure like the following and it is taken care of automatically:

SWindowStruct<REBARBANDINFO> stRBBI ;


Source: http://www.microsoft.com/msj/0898/bugslayer0898.aspx
Tip #13 From Dave Angel: in your June column, you mentioned using the debugger as a code coverage tool. Your debugger makes a useful performance tool as well. Run your application under the debugger and when it starts a time-consuming operation, keep hitting the Debug|Break menu to break into your application at regular intervals, and note which function the debugger stops in. This is the same technique that a sampling profiler uses, albeit at a faster pace.

If you are doing a multithreaded application, make sure to check the current location for each thread. If one function (or a group of related functions) is your bottleneck, this will become obvious very quickly. Sometimes it's helpful to check the top few levels of the call stack, because even if a single function isn't the culprit, children of the function may be, and some attention to the common logic is warranted.

The bottom line is that you can use this approach to do a sanity check on your program. If you get a different function each time you halt, or if you get the functions you expect, then you understand the code. But if you see something unusual, it's time for a closer look. That closer look may be with a formal performance tool, or it may be with some custom measurement code you insert yourself.

Source: http://www.microsoft.com/msj/1098/bugslayer/bugslayer1098.aspx
Tip #14 Since a bunch of managers are going to be spending a lot of money thanks to this column (because they need to go out and buy multiprocessor machines), here is a tip for them I learned through real-world commercial development. One thing that has worked well for me is having two-week code freezes before milestones. When you limit code freezes to a week, you end up fixing bugs and never actually freeze. If you schedule two-week code freezes, the idea is to spend the first week at absolute feature freeze, but allow your developers to fix bugs. The second week is total code freeze for everyone. When you do this, you are scheduling bug fix time and giving yourself enough space to really put your release through the ringer. When I started doing this, my milestone alphas and betas became significantly more stable and useful for external testers.

Source: http://www.microsoft.com/msj/1098/bugslayer/bugslayer1098.aspx
Tip #15 When debugging drivers, especially those that can be unloaded, I swap back and forth between the free and checked builds to ensure that the free build behaves the same as the checked build. To make this easier, I have my INI registration file register two drivers: the free build is the normal driver name Foo, and the checked build is FooC. I also set the ImagePath field for each to point to the appropriate driver. For example:

ImagePath = \??\d:\dev\foo\obj\i386\free\foo.sys.


Source: http://www.microsoft.com/msj/0199/bugslayer/bugslayer0199.aspx
Tip #16 In my August 1998 column I showed you how to write crash handlers that display a dialog with crash information for the user. Reader Chris Kirmse suggests having your crash handler fill out bug reports for you. When Chris's application crashes, he has the crash handler show a dialog with a Report Error button. When the user presses the button, Chris has their browser jump to his Web site with the crash data. At the Web site he asks for additional information to help him track down the problem. Chris says he gets much better information from his users because the crash is definitely fresh in their mind. Another benefit is that users are impressed that he's so proactive in handling their problems.

Source: http://www.microsoft.com/msj/0199/bugslayer/bugslayer0199.aspx
Tip #17 After you have figured out what product you are going to develop, gotten the signoff from marketing, designed the algorithms, and done the research, what is the very first thing that you develop? The installation, of course! This is one of the most important parts of your product and can be one of the best team bugslaying tools around. Unfortunately, most teams leave the installation to the last possible moment, and that leads to massive numbers of support calls. First impressions matter, and if your users have trouble installing, they will probably not look favorably on your product. If you have been in this business for more than five minutes, I am sure you can recall an installation horror story for some product that you have purchased.

If you develop the installation as soon as you can, you get the benefit of debugging the install over long periods of time. You will also make it easier for others in your organization to actually start using your software earlier. If your technical support engineers and others in your organization have something that they can install and start playing with well before you go to beta, you not only get extra testers for free, you also get real user input when you can actually do something about it.

Also, develop your installation so that it can install a debug build as well. If you are getting reports of problems because of a particular machine configuration, you can just install a debug build and quickly start finding the problem instead of spending the day fiddling around with the registry and different files.

Source: http://www.microsoft.com/msj/0299/bugslayer/bugslayer0299.aspx
Tip #18 Faithful readers know I believe in turning on maximum warnings with /W4. However, if you are using the supplied STL implementation or including headers from cross-platform code, /W4 can generate a ton of warning messages. Visual C++ 6.0 now supports setting and restoring the error level through the #pragma warning directive. When I include headers that do not compile with /W4, I bracket the problem headers with the appropriate warning levels like the following:

#pragma warning( push, 3 )
#include <vector>br> #pragma warning( pop )
While this new feature is not a replacement for fixing the errors in the first place, it is a great help when you need it.

Source: http://www.microsoft.com/msj/0299/bugslayer/bugslayer0299.aspx
Tip #19 If you have a user who is reporting that your application is running out of memory or resources, you can have them use the Windows NT TaskManager to check memory consumption for you. Have them add the Memory Usage Delta column (select the Processes tab, then Select Column from the View menu). Right after they start your application, have them set the update speed to Paused. As soon as they get the out-of-memory problem, they can select Refresh Now on the View menu. The Mem Delta column will tell you how much memory has been used by your application between startup and the memory problem.

Source: http://www.microsoft.com/msj/0499/bugslayer/bugslayer0499.aspx
Tip #20 I always have trouble deciding which properties, methods, and events to support and how to name them when doing a COM object. In MSDN, Dave Stearns from Microsoft has written an excellent article called "The Basics of Programming Model Design." If you do anything with any sort of COM control, I highly recommend that you read this article.

Source: http://www.microsoft.com/msj/0499/bugslayer/bugslayer0499.aspx

 

Tip #21 From John Maver: I found a spiffy trick you can do with the debugger watch window. Putting a function in the watch window will cause the function to be executed.

Compile a debug build of VectorWalk.cpp (see Figure 7) and single-step in the debugger until the active line is the vector constructor in main. Notice that the function vectorwalk is not called in the main program at all. Switch to the watch window and type in vectorwalk(a), then run to the for loop. Notice that the value after vectorwalk(a) is zero, which is what you would expect because vectorwalk returns the size of the vector.

Step over the push_back call once and you see the magic happen. The vectorwalk(a) value in the watch window changes to 1, and if you look at the console window for the program, you will see that the value of a[0] has gone to count! Each time you execute the push_back, you see a new value in the watch window reflecting the size as well as the dump each time vectorwalk(a) is reevaluated.

While I am sure you do not want to have the function you place in the watch window calculate pi to 100,000 places, I have found it very useful to have some small functions in key parts of my code that I only call from the debugger. I use them to do some extra data validation and to help me look at convoluted data structures. Just make sure that your special functions treat everything as read-only because you do not need your debugger messing with the real data.

Source: http://www.microsoft.com/msj/0699/Bugslayer/Bugslayer0699.aspx
Tip #22 From Brad Ek: I really hate trying to figure out problems when you get an error in a C/C++ macro. The bugslaying trick I use is to compile with the CL.EXE /P switch so it will generate the completely preprocessed file, original filename.i, that CL will then compile. This makes it a snap to find out where a macro went bad. Be prepared; the .i files can get huge, on the scale of three to four megabytes if you are doing MFC development.

Source: http://www.microsoft.com/msj/0699/Bugslayer/Bugslayer0699.aspx
Tip #23 If you are buried way down deep in your application during a debugging session and you want to quickly go back up the call stack, open the Call Stack window, highlight the function you want to return to, and hit your breakpoint key. The Visual C++ debugger allows you to set breakpoints in the Call Stack window

Source: http://www.microsoft.com/msj/0899/bugslayer/bugslayer0899.aspx
Tip #24 Now that Visual C++ 6.0 is able to read export symbols as well as the operating system symbols, a few folks have written me asking how they can set a breakpoint on the first instruction of an exported system function. The trick is to check if the symbols have been loaded in the debugger by checking the debugger output window. If it says "Loaded symbols for XXX", where XXX is the name of the DLL you are interested in, the symbols are loaded.

If the symbols have not been loaded, open the Breakpoints dialog and click on the arrow next to the Break At edit control to bring up the Advanced Breakpoints dialog. In the Location edit control, type in the name of the function as it is exported from the DLL. (You can check the name with the "DUMPBIN /EXPORTS" command.) Tab down to the Executable File edit control and type in the name of the DLL that exports the function. For example, if you do not load the symbols to KERNEL32.DLL, you can break on LoadLibrary with the following breakpoint syntax:

{,,KERNEL32.DLL}LoadLibraryA
If the symbols are loaded, you will need to do a little more work. You will still fill out the same information in the Advanced Breakpoints dialog, except that you must manually calculate the symbol name for the location field. If you do load the symbols for KERNEL32.DLL, the correct symbol for LoadLibrary is _LoadLibraryA@4. The breakpoint syntax is

,KERNEL32.DLL}_LoadLibraryA@4
The number after the @ sign indicates that the function is a __stdcall function and represents the number of bytes that are in the parameter list. Calculating the byte count is easy; it is the total size of all parameters, each size-aligned to a multiple of four bytes. Keep in mind that the @ sign and number are still needed, even for those functions that do not have parameters. For example, the correct translation for TlsAlloc is _TlsAlloc@0.

Source: http://www.microsoft.com/msj/0899/bugslayer/bugslayer0899.aspx
Tip #25 You can do rudimentary profiling in the debugger watch window with the undocumented @clk pseudo register. While the times returned include debugger overhead and such, it can be very helpful to get an idea of how long an operation took. The trick is to add two watches to the watch window. The first is @clk, and the second is @clk=0. Each time the watch window is reevaluated, the first @clk will show you the time in nanoseconds it took to execute. If you want to see the time in milliseconds, you can always enter the first watch as @clk*1000,d.

Source: http://www.microsoft.com/msj/1099/bugslayer/bugslayer1099.aspx
Tip #26 If a pointer to an array only expands to a single item, the undocumented numerical format specifier will force the expansion. For example, if you have an LPDWORD pointer, pVals, that points to an array of 10 items, you can display all 10 by entering pVals,10 in the watch window. The number after the comma tells the watch window how many items to display.

Source: http://www.microsoft.com/msj/1099/bugslayer/bugslayer1099.aspx
Tip #27 Since I talked about WinDBG this month, here's a WinDBG tip. The WinDBG ? command can also be used to call a debugging function. Back in Tip 21 (MSJ,June 1999) John Maver discussed how to do this with the Visual C++ debugger. For WinDBG, just type in the function with parentheses. For example, if your debugging function prototype is

void CheckMyMem ( void )
you would just type in

? CheckMyMem()


Source: http://www.microsoft.com/msj/1299/Bugslayer/Bugslayer1299.aspx
Tip #28 By default, Windows NT and Windows 2000 always bring up the crash dialog to tell you that you had a crash and make you press Cancel to start the debugger. If you want to automatically jump into the debugger (or bring up the DbgChooser utility I'll describe in my next column), set the Auto value to 1 in HKLM\Software\ Microsoft\Windows NT\CurrentVersion\AeDebug. The default value of zero brings up the initial crash dialog.

Source: http://www.microsoft.com/msj/1299/Bugslayer/Bugslayer1299.aspx
Tip #29 Ziv Caspi sent an interesting idea on how you can get a reasonable name for the active thread when debugging Windows NT and Windows 2000-based applications. The debugger's Thread dialog only shows the thread ID. If you have multiple threads in your application, you can quickly get lost trying to figure out which thread is active in the debugger. The Thread Information Block (TIB), which Matt Pietrek covered way back in the May 1996 issue of MSJ, has a fieldpvArbitrary (at offset 0x14)that can be used by applications for any purpose. Since this field exists on a per-thread basis, Ziv's idea was to use it to store a string pointer.

I took Ziv's idea, wrote two functions (SetThreadName and GetThreadName) and included a sample project called ThreadName in this month's code listing. I encourage you to run the code in the debugger to see everything in action. When it comes to naming threads, setting the thread name is just half the battle. The other half is viewing the thread name in the debugger. In the Watch window, set up the watch

"(char*)(DW(@TIB_0x14))"
For full Unicode builds, use the watch

"(unsigned char*)(DW(@TIB_Ox14))"
Then whenever you stop in a different thread, you will see its name and always know which thread you're looking at. Thanks for the great tip, Ziv!

Source: http://www.microsoft.com/msj/0100/bugslayer/bugslayer0100.aspx
Tip #30 I have received several hundred e-mails in the last couple of months from folks having trouble accessing their debug symbols with my CrashFinder (MSJ,April 1998) or my CrashHandler (MSJ,August 1998) application. When Windows 2000 ships, get IMAGEHLP.DLL, DBGHELP.DLL, and MSDBI.DLL and place them into the same directory as CrashFinder.EXE or your executables if you are using CrashHandler. That should get you going. I have been using all the Release Candidate versions of these three DLLs on Windows 98, Windows NT 4.0, and Windows 2000 without problems. Please keep in mind that these files are not redistributable, so you cannot ship them with your binaries. For more information about ensuring that your debug symbols are read properly, see the FAQ page at my Web site,http://www.jprobbins.com.

Source: http://www.microsoft.com/msj/0100/bugslayer/bugslayer0100.aspx

 

Tip #31 While debugging, CTRL+F11 (or ALT+8 with Visual C++ 2.0 keyboard mappings) will toggle the current source view to the Disassembly window. Unlike pressing the Disassembly button on the debug toolbar which opens the view at a random location in the code, CTRL+F11 takes you right to the disassembly for the line that you were viewing in the Source window. To change your keyboard mapping to use another key to jump to the disassembly, the ActivateDisassemblyWindow command can be assigned to the new key. (Tip from Sean Echevarria.)

Source: http://msdn.microsoft.com/msdnmag/issues/0400/bugslayer/default.aspx
Tip #32 The Microsoft Knowledge Base (KB) has all sorts of wonderful information, but can be overwhelming. Fortunately, all the KB articles have subcodes associated with them, which help to narrow the search. The codes for each KB article are at the bottom of the article. For example, searching for "ntstop" will yield all KB articles related to STOP messages/blue screens for Windows NT. "How to Query the Microsoft Knowledge Base Using Keywords" Q242450 (Tips About How to Query the Microsoft Knowledge Base), gives you tips for searching the Knowledge Base with keywords.

Source: http://msdn.microsoft.com/msdnmag/issues/0400/bugslayer/default.aspx
Tip #33 Korry Douglas writes: recently, my application was experiencing random deadlocks. Since I couldn't duplicate it at all, I added a new thread to the application that just waits on an event as soon as it starts. I gave a customer who could duplicate the deadlock a separate program called tickle that did nothing more than set the event that my special thread was waiting on. After tickle set the event, the special thread would wake up, suspend the main thread, dump the main thread's stack, and resume the main thread. Whenever the customer thought my application had hung, he would run tickle and I would get the magic call stack. Based on that I was able to figure out the problem.

Source: http://msdn.microsoft.com/msdnmag/issues/0600/bugslayer/
Tip #34 Now that you have Tester to help do your regression testing, make sure you don't forget to check performance. When you build your testing scripts, you should record the start and stop times in order to get a baseline for how long various operations take. After your scripts run, take a look at the subsequent run's time versus your baseline; if you are more than 10 percent off, you need to stop and figure out why it slowed down. Performance problems creep into the applications a little bit at a time. If you start monitoring for them right up front, you can avoid many customer complaints in the end.

Source: http://msdn.microsoft.com/msdnmag/issues/0600/bugslayer/
Tip #35 Joseph Sebestyen from Slorakia writes: In theJune 1998 issue of MSJ you showed how to set the ESP register in the Memory window in order to look up function parameters on the stack. To look up the parameters on the stack on the first instruction of a function, I use ((int*)@ESP),10 in the Watch window (where 10 is the number of parameters I want to see). The undocumented ,# formatting, which I learned from another of your tips, auto- expands to an array view. When I step into standard frame functionsthose that use the PUSH EBP/MOV EBP, ESP prolog sequenceI change the Watch window expression to ((int*)@ESP+1),10.

Source: http://msdn.microsoft.com/msdnmag/issues/0800/Bugslayer/default.aspx
Tip #36 Dr. Jonathan M. Gilligan writes: I do a lot of work with classes that contain pointers to other classes or other objects of the same class (trees and related data structures, for instance). Sometimes when debugging, it can be very hard to keep track of which instance of a class I am looking at, particularly when it's passed around as a function argument or aliased.

I have taken to adding "serial number" members to all classes to help me keep track of such things.
// class declaration
Class Foo
{
private:
    static unsigned s_uLastSerialNo;
    unsigned m_uSerialNo;
...
};

// in the implementation
unsigned Foo::s_uLastSerialNo = 0;

Foo::Foo() : m_uSerialNo(++s_uLastSerialNo)
{
     // initialization
}
Now if I have a bug that shows up in association with a particular object, I can use TRACE output or conditional breakpoints to focus on things that affect that particular object.

Source: http://msdn.microsoft.com/msdnmag/issues/0800/Bugslayer/default.aspx
Tip #37 Spencer Low writes: I am looking for a way to perform compile-time checks on constant-expression assertions, rather than just waiting until runtime to hit them. As I was looking through WINNT.H, I ran across the following code, which is exactly what I needed to solve the problem.

// // C_ASSERT() can be used to perform many compile-time assertions:
// type sizes, field offsets, etc.
//
// An assertion failure results in error C2118: negative subscript.
//

#define C_ASSERT(e) typedef char __C_ASSERT__[(e)?1:-1]


Source: http://msdn.microsoft.com/msdnmag/issues/1000/bugslayer/
//z 2012-09-04 17:56:57 IS2120@CSDN.T1187852306[T12,L120,R4,V119]
Tip #38
Reed Mangino writes: While this might not be a typical Bugslayer tip, it can save you lots of time in the debugger and while editing in the Visual C++ IDE. Use CTRL+SHIFT+G to bring up source files from numerous places. In the Find window, type the name of the file to open (for example, WINNT.H), press CTRL+SHIFT+G and, bingo, WINNT.H will open. In an editor window, if you place the cursor inside the <> or "" of an include statement, pressing CTRL+SHIFT+G will open that include file. If the editor doesn't find the files, you might need to add the appropriate paths in the Include files section of the Options dialog Directories tab.

Source: http://msdn.microsoft.com/msdnmag/issues/1000/Bugslayer/default.aspx
Tip #39 Microsoft has released an interesting utility called PageHeap to help track memory corruption problems. You can read more about PageHeap in Knowledge Base articleQ264471.

Source: http://msdn.microsoft.com/msdnmag/issues/1200/bugslayer/
//z 2012-09-04 17:56:57 IS2120@csdn.T1187852306[T12,L120,R4,V119]
Tip #40
Don't you just hate it when you turn on memory leak detection in the C runtime and all of your leaks allocated by the new operator come out CRTDBG.H and not where you allocated memory? That drives me nuts! The problem is that there is a bug in CRTDBG.H in that the new operator is declared as an inline function. Since debug builds turn all inlining off, the new operator becomes another function and the __FILE__ macro expands to CRTDBG.H. Fortunately, I found a workaround. Make all of your precompiled headers look like the following:

#ifndef _STDAFX_H
#define _STDAFX_H

// This define must occur before any headers are included.
#define _CRTDBG_MAP_ALLOC

// Include all other headers here!

// Include CRTDBG.H after all other headers
#include <crtdbg.h>
#define NEW_INLINE_WORKAROUND new ( _NORMAL_BLOCK ,\
    __FILE__ , __LINE__ )
#define new NEW_INLINE_WORKAROUND
#endif // _STDAFX_H
The one drawback to this approach is that you need to ensure that all STL headers in particular are only included in your precompiled header file. If they are included after the precompiled header, you will get compilation errors. Additionally, if you have custom new operators for a class, you will also get errors. You will need to undefine new before declaring your class and perform the defines I just mentioned after your class. Also, include a placement operator version of new in your class that matches the one in CRTDBG.H so you can get the source and line information.

Source: http://msdn.microsoft.com/msdnmag/issues/1200/bugslayer/

Tip #41 from Ted Yu: Back in your April 2000 column, you complained that STL's bsearch function didn't return a value. Here's a bsearch function that returns the iterator corresponding to the value found. If the value isn't found, it returns end().

template<class _FI, class _Ty>
inline _FI bsearch ( _FI _F , _FI _L , const _Ty& _V )
{
    _FI _I = lower_bound(_F, _L, _V);
    if (_I == _L || _V < *_I)
    {
        return _L ;
    }
    return ( _I ) ;
}


Source: http://msdn.microsoft.com/msdnmag/issues/01/02/Bugslayer/default.aspx
Tip #42 from Patrick Gautschi: Microsoft has released an interesting set of tools to help track memory leaks called UMDH (user-mode dump heap). Download the tools atHow to Use Umdh.exe to Find Memory Leaks. Make sure to read the whole Knowledge Base article on how to use them.

Source: http://msdn.microsoft.com/msdnmag/issues/01/02/Bugslayer/default.aspx
Tip #43 Pavel Lebedinsky found an extremely cool trick for the Visual C++ 6.0 debugger buried deep in the Microsoft Knowledge Base: the debugger can read crash dump files! Setting the CrashDumpEnabled REG_DWORD value to 1 in HKEY_CURRENT_USER\Software\Microsoft\DevStudio\6.0\Debug adds a *.DMP option when opening workspaces. It looks like the feature is partially done, but it does work. To get the best results, copy all the PDB files necessary for the process that crashed into the same directory as the .DMP file.

Source: http://msdn.microsoft.com/msdnmag/issues/01/05/bugslayer/default.aspx
Tip #44 Mike Morearty thought it would be very nice if you could have true hardware read and write breakpoints from the Visual C++ 6.0 debugger. He wrote a very cool class, CBreakpoint, which allows you to specify which address you would like to stop on each time your program truly reads or writes them. Mike's class goes way beyond the data access breakpoints offered in the debugger today. It's a fantastic class and one that I have used to track down some very difficult bugs already! You can download the complete code at http://www.morearty.com/code/breakpoint. Mike also has a nice document set to show you exactly how to use it.

Source: http://msdn.microsoft.com/msdnmag/issues/01/05/bugslayer/default.aspx
Tip #45 One of the advantages of having the Windows 2000 symbols installed is getting perfect call stacks because the supplied symbols include just the public functions, and, most importantly, the Frame Pointer Omission (FPO) data. The FPO data is necessary to completely walk the stack. However, if your code is out in the field, you probably don't want to distribute your existing PDB files, since they have all your secrets in them. A new feature of the Visual C++ .NET linker is the /PDBSTRIPPED switch. It will automatically produce a PDB file that contains nothing but public symbols, object file names, and FPO data. With this new switch, you should never want for a call stack from the field again.

Source: http://msdn.microsoft.com/msdnmag/issues/01/08/bugslayer/
Tip #46 If you want to automate your development builds without starting the new Visual Studio .NET IDE, run "DEVENV /?" from the command line. The resulting dialog will show you all the command-line options for building and running your projects. You can easily automate your complete system build straight from the command line so you can start it late at night without any user intervention.

Source: http://msdn.microsoft.com/msdnmag/issues/01/08/bugslayer/
Tip #47 The Visual Studio .NET editor makes doing your C# doc comments a piece of cake. At the top of your classes, properties, or methods, type "///" and the editor will automatically set up the comments for you, including parameters and return blocks. This feature will save you hours of time.

Source: http://msdn.microsoft.com/msdnmag/issues/01/10/Bugslayer/default.aspx
Tip #48 Once you add your doc comments to your projects, go to the Tool menu and select Build Comment Web Pages. This tool will automatically run through your code and build a complete Web application for your commented code! It's a great way to build up documentation for your libraries and share it with others.

Source: http://msdn.microsoft.com/msdnmag/issues/01/10/Bugslayer/default.aspx
Tip #49 Information about all active add-ins is shown in the Visual Studio .NET About box, as shown in Figure 5. The Add-in Wizard gives you a default icon to display. What's interesting is that the icon is specified as hex data in your add-in's registry key. To change the icon, you'll need to use the GenerateIconData.exe program included with the sample download to get the hex bytes corresponding to your icon.

Figure 5 Installed Add-ins

Source: http://msdn.microsoft.com/msdnmag/issues/02/01/Bugslayer/default.aspx
Tip #50 If you are having trouble with Visual Studio .NET crashing because of a bad add-in, you can start the IDE in safe mode by specifying the /safemode switch on the command line. Only the default environment and services are loaded in safe mode.

Source: http://msdn.microsoft.com/msdnmag/issues/02/01/Bugslayer/default.aspx

Tip #51 One thing that's a little weak in TestRec is that you are stuck looking at a simple edit control to do some of the on-the-fly editing of your scripts. If you're up to the challenge, Neil Hodgson has written an outstanding open source editing control called Scintilla (http://www.scintilla.org), which you could integrate into TestRec. It already supports JavaScript and VBScript syntax highlighting as well as code folding and a myriad of other excellent editing features. Also, if you're looking for a great Windows programming sample to learn from, check it out.

Source: http://msdn.microsoft.com/msdnmag/issues/02/03/Bugslayer/
Tip #52 If you find yourself wanting to know how a particular DLL landed on your system (or more importantly on a customer's system), here's a link that points to a Microsoft database of every DLL they've shipped, along with the version number and link date. The final screen for each item tells what product shipped the DLL. This can be invaluable when you need to track down a "Why doesn't it work on my machine?" bug report. See the database athttp://support.microsoft.com/servicedesks/fileversion/dllinfo.asp?fr=0&sd=msdn.

Source: http://msdn.microsoft.com/msdnmag/issues/02/03/Bugslayer/
Tip #53 If you have any really tough debugging problems, the new WinDBG documentation has a couple of excellent discussions in the Debugging Techniques section.

Source: http://msdn.microsoft.com/msdnmag/issues/02/06/Bugslayer/default.aspx
Tip #54 John Maver reports a cool trick with the Visual Studio .NET debugger. If you have a line like this
HeapFree ( GetProcessHeap ( ) , 0 , lpdwPIDs ) ;
and if you want to step into HeapFree, but not GetProcessHeap, put your cursor on HeapFree, right-click, and choose Step Into HeapFree. The text changes based on where you place your cursor. I like this one so much I assigned the shortcut Ctrl-Alt-F11 to it.

Source: http://msdn.microsoft.com/msdnmag/issues/02/06/Bugslayer/default.aspx
Tip #55 To attach to a process in Visual Studio .NET for quick native debugging, hold down the control key when you click Attach in the Processes dialog. This will bypass the Attach To Process dialog and immediately attach for native debugging only.

Source: http://msdn.microsoft.com/msdnmag/issues/03/06/Bugslayer/default.aspx
Tip #56 The Microsoft Visual Studio team has put together a collection of power toy add-ins for Visual Studio that you might find useful. You can download them atPowerToys for Visual Studio .NET 2003. The Visual Basic Commenter, which lets you put XML comments in Visual Basic .NET, and the Custom Help Builder, which makes it easy to add your own class documentation to the Help System, are both outstanding additions to the IDE.

Source: http://msdn.microsoft.com/msdnmag/issues/03/11/Bugslayer/
Tip #57 To hasten the startup of the Visual Studio .NET IDE, get rid of the Start Page. Because the Start Page requires all Web-browsing components to be loaded, you can chop off a considerable amount of startup time by skipping it. To turn off the Start Page, select Options from the Tools menu to bring up the Options dialog. In the Environment/General property page, select "Show empty environment" in the "at Startup" combobox.

Source: http://msdn.microsoft.com/msdnmag/issues/03/11/Bugslayer/
Tip #58 Another performance tip is to turn off tracking the active item in the Solution Explorer window. This will keep the Solution Explorer selection from bouncing all over the place when working on different files in a project. From the Tools menu, select Options. In the Options dialog, select the Environment/Projects and Solutions property page and uncheck Track Active Item in Solution Explorer.

Source: http://msdn.microsoft.com/msdnmag/issues/03/11/Bugslayer/
Tip #59 In this column, I've covered handling internationalization from the .NET programming perspective. If you're using ASP.NET, you probably have many HTML pages with static text that will need to be internationalized. One great tool you'll want to check out is the Enterprise Localization Toolkit.

Source: http://msdn.microsoft.com/msdnmag/issues/04/03/Bugslayer/default.aspx
Tip #60 If you need to format a selected section of code in a jiffy with Visual Studio .NET, press Ctrl+K, Ctrl+F on the default keyboard, and the Edit.FormatSelection command will do the work.

Source: http://msdn.microsoft.com/msdnmag/issues/04/03/Bugslayer/default.aspx

Tip #61 If you're looking to see how .NET works or want to see how someone implemented a cool program, but you don't have the source, look at Lutz Roeder'sReflector. Not only does it disassemble, it's a complete decompiler that will translate MSIL into C# or Visual Basic .NET.

Source: http://msdn.microsoft.com/msdnmag/issues/04/04/Bugslayer/
Tip #62 While Reflector is a standalone program,Jamie Cansdale has written a cool article in which he takes Reflector and, with some magic, converts it into a Visual Studio .NET AddIn. Not only does he make a phenomenal utility even more useful, Jamie's code is a great example of .NET Framework programming.

Source: http://msdn.microsoft.com/msdnmag/issues/04/04/Bugslayer/
Tip #63 At this point, I've only seen one other person who's posted rules on the Web, Anand M, at a href="http://www.fxcop.tk">http://www.fxcop.tk. His rules are based on the older Reflection engine, but do show you how to write those rules in Visual Basic .NET.

Source: http://msdn.microsoft.com/msdnmag/issues/04/06/Bugslayer/default.aspx
Tip #64 If you're starting to do the very cool Tablet PC development and need another test machine, but can't afford a second Tablet PC, I ran across a great idea on how to mimic one atCan't Afford a Tablet PC? Try This!. Wei-Meng Lee and Brian Jepson point out that you can install Windows Tablet PC Edition on a laptop and hook up a graphics tablet. That gives you an instant test machine for about $100!

Source: http://msdn.microsoft.com/msdnmag/issues/04/06/Bugslayer/default.aspx
Tip #65 Lutz Roeder's Reflector (http://www.aisto.com/roeder/dotnet/) offers a great Add In model. Dennis Bauer has written a very nice Add In, Reflector.FileDisassembler that lets you decompile a whole assembly to source files ready for compiling. Download it with source code at http://www.denisbauer.com/NETTools/

Source: http://msdn.microsoft.com/msdnmag/issues/04/09/Bugslayer/
Tip #66 Virtual PC is a great product that makes it a snap to create a new machine for testing. One thing many people don't realize is that you can create what are called Differencing Virtual Hard Disks. These virtual machines use another virtual machine's disk image as a baseline and only store the differences from the baseline in the new virtual machine. Instead of going through an installation of the whole operating system, you can create a new fully ready to run virtual machine in under a minute. Obviously, you'll want to keep the baseline virtual machine read only and not use it so you don't mess up your differencing virtual machines. See the Virtual PC documentation for more information.

Source: http://msdn.microsoft.com/msdnmag/issues/04/09/Bugslayer/
Tip #67 Since I'm a tools kind of guy, I would be remiss if I also didn't plug Jonathan de Halleux's outstanding MBUnit (http://mbunit.tigris.org). It's fully compatible with NUnit, but offers all sorts of advanced features for creating great tests such as testing against different cultures, data driven testing, and process testing. MBUnit is replacing NUnit for me!

Source: http://msdn.microsoft.com/msdnmag/issues/05/03/Bugslayer/
Tip #68 While MBUnit is excellent, the other testing tool you need is from Jamie Cansdale: TestDriven.NET (http://www.TestDriven.NET). It's a phenomenal Visual Studio .NET Add In that allows you to plug in tools like MBUnit, NUnit, and even the upcoming Microsoft Team System into a single one click testing environment. All I can say is WOW!

Source: http://msdn.microsoft.com/msdnmag/issues/05/03/Bugslayer/
//z 2012-09-04 17:56:57 IS2120@CSDN.T1187852306[T12,L120,R4,V119]
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值