Detecting over-Releasing on COM objects

I am in Refcount Hell right now, trying to fix a new chunk of our codebase for COM refcounting issues. Debugging missing AddRefs consumes most of my time, and I might write about that one day, but yesterday I managed to over-Release an object and of course I crashed. Finding over-Releases is trivial by comparison:

Assuming you can determine the instance of your object that will be over-released, just set a 4-byte data breakpoint on that pointer value. When the object gets over-released, and its destructor called (by "delete this") the debugger will stop right at that point. This happens because a destructor will overwrite the vtable address with its base class, firing the data breakpoint.

(This assumes you are using some inheritance to get COM refcounting, such as ATL)

Comments (2)

  1. Phaeron says:

    Unfortunately, while usually effective, this trick doesn’t actually stop on the bad over release — it just stops on the penultimate call. If the object has several refcounts on it and the bad call occurs early, the crash may not happen until several Release() calls later, with no clue as to who actually blew it. If the last reference is held long term in something like a cache, the crash can be delayed by minutes or even hours.

    When I get a really nasty case, one trick I like to do is to set up a huge static ring buffer and rig AddRef/Release() to plop this, thread ID, refcount, and return address into the buffer. This minimizes the runtime cost, but allows you to see a fairly long history of who did AddRef/Release calls on that object, which you can then process with an offline tool.

  2. Andy-Pennell says:

    This worked for me because the penultimate call WAS the bad one. Agreed, this is not always the case.

    There is a much easier way Phaeron: Debugger Tracepoints. Set a tracepoint on the offending AddRef/Release funcs, and dump the callstack, this ptr, and refcount. You still have to manually tie them into matching pairs to find the errant call of course, and that takes the time. (Right now I have my object leaks down from over 22k to 19).

Skip to main content