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.