We have had a number of customers send us dump files where we have determined that for some reason, it appears CJ is accessing bad memory in docking pane code. We could not tell if it is due to some memory overwrite on our part or some other issue.
Today, I happened to figure out what is going on. When we have a floating docking pane, and the layout gets reloaded, this sequence of events occurs:
CXTPDockingPaneLayout::SetLayout is called. CXTPDockingPaneLayout::Copy is called. CXTPDockingPaneLayout::Free is called.
CXTPDockingPane::DeletePane is called. This pane is in a floating docking pane. The pane is in a CXTPDockingPaneTabbedContainer, which is in turn in a CXTPDockingPaneMiniWnd.
As the Free method continues to execute ...
CXTPDockingPaneTabbedContainer::DeletePane is called. This PANE CONTAINS THE BACK POINTER TO THE PREVIOUSLY DELETED PANE.
OnFinalRelase calls DestroyWindow. That in turn causes the docking pane miniwnd to get a call to paint itself, including an OnEraseBkgnd call.
Unfortunately for us, we handle that call and we call GetSelectedPane.
CXTPDockingPaneMiniWnd::GetSelectedPane calls FindPane(xtpPaneTypeTabbedContainer). You can see where this is going :(
CXTPDockingPaneMiniWnd::FindPane still has the m_pTopContainer pointer set. This tabbed container has yet to be deleted.
The tabbed container in turn calls FindPane. This is in the CXTPDockingPaneBaseContainer code. There it calls GetType and its type matches the request for a tabbed container type. So, it calls:
CXTPDockingPaneBaseContainer::IsEmpty(). That object has its own m_lstPanes list. And that list has the pointer to the deleted pane. The result is that the c++ vtable is accessed. KABOOM.
This is "random" in that there is no telling where that memory points to.
Right now, I don't see an easy fix for this. On first glance, it would seem that the way to go about deleting panes should be a top down approach. Delete the mini windows. Delete the tabbed containers. Delete the panes. But, I'm betting this bevy of non add reffed pointers CJ stores means the back pointers to containers will just trigger more of the same.
The pointer checks in CJ code are in place, but the timing is wrong.
Codejock should be able to easily duplicate this issue. Just modify CXTPDockingPaneMiniWnd to implement OnEraseBkgnd. Then, in that method, call GetSelectedPane.
|