What's wrong with this code, part lucky 13
Today's example is a smidge long, I've stripped out everything I can possibly imagine stripping out to reduce size.
This is a very real world example that we recently hit - only the names have been changed to protect the innocent.
I've used the built-in C++ decorations for interfaces, but that was just to get this stuff to compile in a single source file, it's not related to the bug.
extern CLSID CLSID_FooDerived;[ object, uuid("0A0DDEDC-C422-4BB3-9869-4FED020B66C5"), ] __interface IFooBase : IUnknown{ HRESULT FooBase();};class CFooBase: public IFooBase{ LONG _refCount; virtual ~CFooBase() { ASSERT(_refCount == 0); };public: CFooBase() : _refCount(1) {}; virtual HRESULT STDMETHODCALLTYPE QueryInterface(const IID& iid, void** ppUnk) { HRESULT hr=S_OK; *ppUnk = NULL; if (iid == IID_FooBase) { AddRef(); *ppUnk = reinterpret_cast<void *>(this); } else if (iid == IID_IUnknown) { AddRef(); *ppUnk = reinterpret_cast<void *>(this); } else { hr = E_NOINTERFACE; } return hr; } virtual ULONG STDMETHODCALLTYPE AddRef(void) { return InterlockedIncrement(&_refCount); } virtual ULONG STDMETHODCALLTYPE Release(void) { LONG refCount; refCount = InterlockedDecrement(&_refCount); if (refCount == 0) { delete this; } return refCount;`` } STDMETHOD(FooBase)(void);};class ATL_NO_VTABLE CFooDerived : public CComObjectRootEx<CComMultiThreadModel>, public CComCoClass<CFooDerived, &CLSID_FooDerived>, public CFooBase{ virtual ~CFooDerived(); public: CFooDerived(); DECLARE_NO_REGISTRY() BEGIN_COM_MAP(CFooDerived) COM_INTERFACE_ENTRY(IFooBase) END_COM_MAP() DECLARE_PROTECT_FINAL_CONSTRUCT()};OBJECT_ENTRY_AUTO(CLSID_FooDerived, CFooDerived)
As always, tomorrow I'll post the answers along with kudos and mea culpas.
Edit: Fixed missing return value in Release() - without it it doesn't compile. Also added the addrefs - my stupid mistake. mirobin gets major props for those ones.