Thunderclap, the newsletter of Rolling Thunder Computing

Volume 1, Number 1 Fall 1998

In this issue:
About Thunderclap
Subscription Information
Feature Article: COM Robustness, Part 1: Count Your Objects
Blatant Self Promotion
Contest with Prizes: The Answer Game


About Thunderclap

This is the first of  a series of quarterly newsletters. Each will bring you a technical article on COM development. I hope will find it useful. The first one (to be published around September 15) will be on tracking reference count bugs in COM. Each issue will also bring you a contest, allowing you to show off your intelligence and creativity to win prizes. I hope you will find it funny. In between you will find my own blatant self promotional material, telling you about the latest ways I've come up with to separate you from your money. (I could have said "carefully selected products and services that we feel might interest you", or other mealy-mouthed horsepuckey. You want the truth or you want me to waste my time and yours dressing it up?)

I'd like to hear what you think about this newsletter and what types of articles you'd like to see in the future. Would you prefer technical programming articles, such as the one in this current issue? Future topics on this track might be, "What the Heck Is the Free-Threaded Marshaler, Anyway?" or "Our Friend, the Causality ID". Or would you prefer higher-level conceptual articles, like "With All the Fuss About COM+, What's In It For Me Today?" Send your e-mail comments to newsletter@rollthunder.com.

This newsletter may be freely redistributed, provided that it is sent in its entirety. If you enjoyed it, can I ask you to please forward it to a friend who might also enjoy it?


Subscription Information

Thunderclap is free, and is distributed via e-mail only. We never rent, sell or give away our mailing list. Subscription and unsubscription are handled by a human operator reading e-mail messages. To subscribe, jump to the Rolling Thunder Web site and fill in the subscription form.


Feature Article: COM Robustness, Part 1

Count your objects

(In the next issue, "Part2: Watch Out for the Other Guy")

In the COM class I taught at Harvard last spring (see the Blatant Self-Promotion section of this newsletter for information on this year’s class), I invited Joel Gould, chief software architect at Dragon Systems and the husband of my best student, to give a guest lecture on Dragon Systems' use of COM inside their excellent speech recognition product called Naturally Speaking. He kept hammering at the need to go beyond simple textbook examples to make a product robust enough to make money in the real world. When your product lists for $150, it retails for $100, and you’re lucky to get $50 of that. If it costs you $15 every time your tech support answers the phone, it doesn’t take long before a rickety product sends you into bankruptcy. You MUST be able to identify, reproduce, and squash nasty subtle bugs to get far enough up the reliability curve to make money on a mass-market product.

I’ve always admired the sound of a twelve-string guitar, but I never could play one. My instructor said that I spent half my time trying to tune it and the other half playing out of tune. Reference counting in COM is like that. You spend half your time trying to get it right and the other half of your time writing code to protect yourself against the bad stuff that happens when you get it wrong. Programming discipline helps avoid them, and so does using smart pointers, but I guarantee that you’ll be banging your head against reference count bugs the night before you ship. And I guarantee that you won’t find them then. Reference count bugs produce the subtle and hard-to-reproduce malfunctions that make you wish you'd gone to law school instead of becoming a geek. Tracking them down isn't cool, it isn't sexy, it isn't fun, but squashing them determines whether your stock options go through the ceiling or through the floor.

Reference count bugs occur when you miss or do an extra AddRef( ) or Release( ). An extra Release( ) or a missing AddRef( ) cause an object to destruct prematurely. These usually aren’t too hard to find because they lead to crashes, which you generally notice and can then debug. It’s much harder to detect a missing Release( ) or an extra AddRef( ), which lead to objects being leaked away. Most real-world apps have too many objects coming and going under the covers for the macroscopic behavior of the program to indicate whether all the object references are being properly handled. You need to track every object and make sure that they come and go when they’re supposed to.

Like seat belts or birth control, object reference tracking schemes only work if you use them. Therefore the right technique for you is not necessarily the one with the highest effectiveness in the laboratory, but the one that is least obtrusive in actual use, so that you actually will use it.  You need a "fire-and-forget" approach, or you’ll never do it.

Joel told me that Dragon Systems uses macros in each object’s constructor and destructor to log its creation and destruction to a file.  At the end of a test run, a utility program opens the log file, matches construction with destruction, and lists any that have come but not gone. He invariably finds about 20 leaked objects, caused by one leaked object holding open references to three or four others, each of which in turn holds open references to three or four more. A conditional compilation switch removes the logging code from the production version. Dragon Systems' original implementation was written by Mike Elkins.

This sounded like a good idea, so I sat down to implement such a scheme. You can download the code that I’ll show you here from Rolling Thunder’s Web site. This code was written by me, and has not been supplied or endorsed by Dragon Systems.

I wrote an extremely simple ATL in-proc object, which you will find in the subdirectory \RTmacrotest. It does essentially nothing, containing only a single method for saying "Hello, World" so you know it’s there. Register the DLL "RTmacrotest.dll" via regsvr32. Then run the sample client app "project1.exe" in the directory \VBTestClient. You can create an object, make it say "Hello, World", and release it. Try to hold the applause down.

What you probably haven’t noticed is that the COM objects have been logging their creation and destruction to the file "objlog.txt", which should be in the \VBTestClient directory. If you open it with notepad, you’ll see something like the following:

C 850b80 D:\newsletter\code\v1n1\RTmacrotest\Test.h
D 850b80 D:\newsletter\code\v1n1\RTmacrotest\Test.h
C 850b80 D:\newsletter\code\v1n1\RTmacrotest\Test.h
D 850b80 D:\newsletter\code\v1n1\RTmacrotest\Test.h

Each line represents the construction (‘C’) or destruction (‘D’) of an object. The number following it is a pointer to the object, thereby uniquely identifying it for its lifetime. The last entry is the file in which the object lives, which ought to tell you which class is belongs to so you can start debugging it. You’ll note that VB properly matches its creation and destruction of the objects it uses.

How did I get the objects to log their creation and destruction to this file? I wrote two macros, one for the object’s constructor and one for its destructor. All the programmer needs to do is to put them into the constructor and destructor of EVERY object that he ever writes, without exception. The macros live in the header file "countmacros.h". I put them in thus:

#include "countmacros.h"

class ATL_NO_VTABLE CTest :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CTest, &CLSID_Test>,
public IDispatchImpl<ITest, &IID_ITest, &LIBID_RTMACROTESTLib>
{
    CTest()
    {
       CTOR_COUNT_MACRO
    }

    ~CTest()
    {
       DTOR_COUNT_MACRO
    }

    <rest of class declaration omitted>
}

The macros themselves are shown below. Each opens the file "objlog.txt" for appending data. Each then writes a ‘C’ or ‘D’ to identify the operation and the value of its ‘this’ pointer to uniquely identify the object during its lifetime. I also used the VC++ macro definition __FILE__ to identify the file in which the macro was compiled. Many development projects use one header file per class, so this will identify the class of object created or destroyed. You could certainly pass the class name as an argument to the macro, but the approach shown is  impossible to mess up.

#include <stdio.h>

/*
For a debug version, compile the macros to log construction
and destruction to a file called "objlog.txt".
*/

#ifdef _DEBUG

    #define CTOR_COUNT_MACRO { \
        FILE *fp = fopen ("objlog.txt", "a+") ;\
        fprintf (fp, "C %x %s\n", this, __FILE__) ;\
        fclose (fp) ;}

    #define DTOR_COUNT_MACRO {\
        FILE *fp = fopen ("objlog.txt", "a+") ;\
        fprintf (fp, "D %x %s\n", this, __FILE__) ;\
        fclose (fp) ;}

/*
For a release version, compile the macros away
to nothing.
*/

#else

    #define CTOR_COUNT_MACRO
    #define DTOR_COUNT_MACRO

#endif

So that’s how the log gets there. To read the log file, I wrote a utility app that you will find in the directory \scanner. The code isn't interesting, just a simple file parser, so I won't show it here. It reads the file, matches object construction and destruction, and displays any undestroyed objects. To demonstrate it, run the client app, create an object, then use the Task Manager’s "Process" tab to terminate the process named "Project1.exe". If you look at the log file, you will find a ‘C’ line with no matching ‘D’ line, indicating that the process died before it could release the object. If you then run the scanner program and open the log file, the scanner will detect the leaked object and produce output something like this:

Obviously there are many adjustments you could make to this scheme. The file is always opened for appending, so one test run's data will be tacked onto the end of the previous one. Maybe you'd want one macro in the beginning of the file that clears it. The formatted output functions that I’m using are very inefficient, so you might want a different logging mechanism. You might need finer identification of the object that’s been leaked, perhaps using the __LINE__ macro. You might want to add the time of construction or destruction as an aid to debugging.

The one downfall of this scheme is that it's pointless if even one object doesn't have the tracking macros in it. It's sometimes difficult to get programmers (a notoriously individualistic and stiff-necked bunch; managing them has been likened to herding cats) to put  the macros in when they're supposed to. You need to make it as easy as possible, as this scheme does, to remove any excuses for not doing so. After that, its a matter of public humiliation when the omission causes a nasty bug, and the occasional flogging.

I hope this article has been useful to you. Feel free to forward this newsletter (in its entirety, please) to anyone you'd like. I'd like to hear your ideas for future articles, similar in length and complexity to this one. Tune in next quarter for "COM Robustness, Part2: Watch Out For The Other Guy."

Send us your COM robustness tips and ideas. If we use any in the next issue, we'll credit you as we did for Dragon systems in this issue.


Blatant Self Promotion

Publicly available classes from Rolling Thunder Computing

All are available in-house as well

OLE for Life Insurance in Texas in October

The next public class in OLE for Life Insurance will be held in Dallas TX on October 19-21 and 26-28, sponsored by Cybertek. For more information on this class or OLifE in general, see http://www.acord.com.

Intro to COM on Halloween.

What could be more appropriate for the technology that has loosed demons upon the world? I'll be presenting a one-day Professional Development Seminar for the Greater Boston Chapter of the ACM on Halloween, Saturday October 31, at Northeastern University in Boston. The topic is "Using COM to Develop Distributed Components for Windows NT". For information and registration, see http://www.acm.org/chapters/gbc/

Rolling Thunder goes Down Under in November

I'm heading to Australia come November to deliver several talks. I'll be doing my one-day Intro to COM at the Tools Pacific 98 conference in Melbourne on November 23-26. For more information, see http://www.sd.monash.edu.au/tools98/index.html. I'll also be teaching OLE for Life Insurance on November 11-13 and 16-18, sponsored by Acord. For more information on this class or OLifE in general, see http://www.acord.com.

ActiveX for Health Care in Salem in December

Too bad we couldn't get this one on Halloween. The next public class in ActiveX for Health Care will be held at the Hawthorne Hotel on December 7-11, 1998. For more information, see http://www.rollthunder.com/ahc.htm.

Advance notice – Harvard in the spring.

I'll be teaching my class CSCI-E218, Programming COM+, COM, ActiveX, and OLE, at Harvard Extension in the Spring 1999 term. The class is designed for practicing programmers and is open to the public. It meets Thursday nights at 7:35 PM, beginning on February 4 in Lecture Hall E (downstairs) at the Harvard Science Center. The class grants 4 units of graduate credit and costs $1200. The class description and syllabus can be found at http://www.rollthunder.com/harvard.htm

 


Contest with Prizes

Every issue of Thunderclap will feature a contest allowing you  to show off your intelligence and creativity. First prize is $100, second prize $50. Winners will be announced in the next issue of Thunderclap, and the judge's decision (mine) is final. In the event of duplicate or similar entries, the earliest wins. All entries become property of Rolling Thunder Computing and must be original.  Submit your entries via e-mail to contest@rollthunder.com. I got   some of the contest ideas and examples from New York Magazine's Competition section.

This contest is called "The Answer Game". Similar to Jeopardy, I want you to write an answer and then give the question. For example:

A. Sansui
Q. Who is the patron saint of pigs?

A. Eisenhower, Kennedy, and Johnson
Q. Name two dead presidents and a floor wax.

If they are computer related and somewhat raunchy, so much the better. For example:

A. Microsoft
Q. What were the last two words Melissa Gates wanted to hear on her wedding night?

The last time I ran this contest, the winning entry came from Greg Manto. His entry was:

A. Thunderclap
Q. What do you get from having sex with Zeus ?


Legal Notices

Thunderclap does not accept advertising; nor do we sell, rent, or give away our subscriber list. We will make every effort to keep the names of subscribers private; however, if served with a court order, we will sing like a whole flock of canaries. If this bothers you, don't subscribe.

Source code and binaries supplied via this newsletter are provided "as-is", with no warranty of functionality, reliability or suitability for any purpose.

This newsletter is Copyright © 1998 by Rolling Thunder Computing, Inc., Ipswich MA. It may be freely redistributed provided that it is redistributed in its entirety, and that absolutely no changes are made in any way, including the removal of these legal notices.

Thunderclap is a registered trademark ® of Rolling Thunder Computing, Inc., Ipswich MA. All other trademarks are owned by their respective companies.