Re-entering Release() - strange crash
Hello,
This question arose from an attempt to implement the life-time
management scheme described here:
http://groups.google.com/group/microsoft.public.vc.atl/msg/ad32f7588607c739?dmode=source
The following class definition is a minimal repro of the issue. It's a
modified wizard-generated simple ATL class (appt-threading, no
aggregation). The whole project ("ATLRefcount") is wizard-generated
MSVC2008SP1 ATL inproc server (DLL, merged proxy/stub). Its host is a
simple wizard-generated WinForms .NET project with 1 additional member
in the form:
ATLRefcountLib.Root root = new ATLRefcountLib.Root();
On the apllication shutdown, the DLL always causes the following
diagnostic info (unmanaged code debugging should be switched on):
"HEAP[Host.exe]: HEAP: Free Heap block 12c3350 modified at 12c3380
after it was freed
Windows has triggered a breakpoint in Host.exe.
This may be due to a corruption of the heap, which indicates a bug in
Host.exe or any of the DLLs it has loaded.
This may also be due to the user pressing F12 while Host.exe has
focus."
Note that the last Release() call from the "real" client returns 1,
and this happens *after* the object is alredy destroyed -- by re-
entering Release(). Probably, the client thinks the object is still
alive and tries to access it somehow, and this causes the crash?
#pragma once
#include "resource.h" // main symbols
#include "ATLRefcount_i.h"
#define BOOST_MEM_FN_ENABLE_STDCALL
#include <boost/shared_ptr.hpp>
#include <boost/mem_fn.hpp>
// CRoot
class ATL_NO_VTABLE CRoot :
public CComObjectRootEx<CComSingleThreadModel>,
public CComCoClass<CRoot, &CLSID_Root>,
public IDispatchImpl<IRoot, &IID_IRoot, &LIBID_ATLRefcountLib, 1, 0>
{
public:
CRoot() : creatingInstance_(false)
{
}
DECLARE_REGISTRY_RESOURCEID(IDR_ROOT)
DECLARE_NOT_AGGREGATABLE(CRoot)
BEGIN_COM_MAP(CRoot)
COM_INTERFACE_ENTRY(IRoot)
COM_INTERFACE_ENTRY(IDispatch)
END_COM_MAP()
DECLARE_PROTECT_FINAL_CONSTRUCT()
HRESULT FinalConstruct()
{
init();
return S_OK;
}
ULONG InternalAddRef()
{
if (m_dwRef == 0)
creatingInstance_ = true;
return CComObjectRootEx::InternalAddRef();
}
ULONG InternalRelease()
{
ULONG ref = CComObjectRootEx::InternalRelease();
if (ref == 1 && holder_)
{
if (creatingInstance_)
creatingInstance_ = false;
else
release();
}
return ref;
}
private:
void init()
{
AddRef();
holder_.reset(this, std::tr1::mem_fn(&CRoot::Release));
}
void release()
{
holder_.reset();
}
private:
std::tr1::shared_ptr<CRoot> holder_;
bool creatingInstance_;
};
OBJECT_ENTRY_AUTO(__uuidof(Root), CRoot)