pure virtual function call when linking statically

For help with anything that CEGUI doesn't offer straight out-of-the-box, e.g.:
- Implementation of new features, such as new Core classes, widgets, WindowRenderers, etc. ...
- Modification of any existing features for specific purposes
- Integration of CEGUI in new engines or frameworks and writing of new plugins (Renderer, Parser, ...) or modules

Moderators: CEGUI MVP, CEGUI Team

anthony
Just popping in
Just popping in
Posts: 8
Joined: Mon Jan 19, 2009 14:20
Location: Russia, Novocherkassk
Contact:

pure virtual function call when linking statically

Postby anthony » Mon Mar 09, 2009 10:57

Hi,
I have a problem when statically linking CEGUI (0.6.1)
I got an error:

R6025
- pure virtual function call

which occur when my app (based on DXUT framework) is perform cleanup at the end:
void CALLBACK OnDestroyDevice(void* pUserContext)
{
SAFE_DELETE(mySystem); <- here i got error (mySystem is CEGUI::System*)
SAFE_DELETE(myRenderer);
}

And how can i get step into source code? I use static liblraries with "_d" but i cant step into destructor and see what happen (I have a source code of CEGUI either, maybe i should target it? how?).

If i change my app for use dynamic libraries of CEGUI everything works fine. (but i badly need static linking)

Jamarr
CEGUI MVP
CEGUI MVP
Posts: 812
Joined: Tue Jun 03, 2008 23:59
Location: USA

Postby Jamarr » Mon Mar 09, 2009 18:07

Are you using the precompiled files? Pretty sure none of the precompiled files have any PDB information in them, because their file sizes are way too low; likely for distribution purposes. And there are obviously no PDB files supplied with the precompiled download.

Since you already have the source, you should only need to compile a debug build yourself. Just make sure you either use option C7 to compile the PDB info into your object files, or if you use Ci make sure the generated PDB file is sitting next to the lib you are linking against.

User avatar
CrazyEddie
CEGUI Project Lead
Posts: 6760
Joined: Wed Jan 12, 2005 12:06
Location: England
Contact:

Postby CrazyEddie » Mon Mar 09, 2009 20:15

With regards tot he original issue, when you built your app did you remember to define the CEGUI_STATIC preprocessor symbol?

If you are still looking to step into, or otherwise debug CEGUI, then as Jamarr says, compiling CEGUI yourself is definitely the way to go here.

I think the only precompiled version that's got the debug database is the VC++ 7.1 version, and this is likely why it's so huge (and why we wish to discontinue it!).

CE.

anthony
Just popping in
Just popping in
Posts: 8
Joined: Mon Jan 19, 2009 14:20
Location: Russia, Novocherkassk
Contact:

Postby anthony » Mon Mar 09, 2009 22:56

Yes i use CEGUI_STATIC symbol.
But there is already precompiled debug versions of dll's (for vc8).
Its not 'right' debug versions?

User avatar
CrazyEddie
CEGUI Project Lead
Posts: 6760
Joined: Wed Jan 12, 2005 12:06
Location: England
Contact:

Postby CrazyEddie » Tue Mar 10, 2009 10:59

anthony wrote:But there is already precompiled debug versions of dll's (for vc8).
Its not 'right' debug versions?

Yes, these are the "right" ones - it's just that the packages do not contain all the information to debug into CEGUI itself (which is not the purpose of them; it's to enable correct linking of your client code to the CEGUI libs, because having matching C/C++ runtime and other options for all components is very important).

It's highly unlikely there is an issue within CEGUI itself relating to pure virtual calls, because if there were we would have heard about it (a thousand times over) by now ;)

Looking at other threads here on the forum, apparently deleting things twice can sometimes cause this. Because it's only happening on a static build, I might guess that it's related to cleaning up of modules (like the XML parser and so on), which is handled differently in static link situations (though I can not be sure).

I do not currently have a great deal of (any?) experience of CEGUI in statically linked situations, so I'm limited in what I can suggest, without resorting to talking about things I know nothing about ;)

CE.

anthony
Just popping in
Just popping in
Posts: 8
Joined: Mon Jan 19, 2009 14:20
Location: Russia, Novocherkassk
Contact:

Postby anthony » Tue Mar 10, 2009 13:38

I found problem in the compatibility with the DXUT.
Here is my minimal app:

Code: Select all

#include "stdafx.h"
#include "ceguitest.h"
#include "DXUT.h"

#include "CEGUIsystem.h"
#include "CEGUIWindow.h"
#include "CEGUIScheme.h"
#include "CEGUIImageset.h"
#include "CEGUIWindowManager.h"
#include "CEGUISchemeManager.h"
#include "CEGUIFontManager.h"
#include "falagard/CEGUIFalWidgetLookManager.h"
#include "CEGUIDefaultResourceProvider.h"
#include "d3d9renderer.h"

#pragma comment(lib, "d3d9.lib")
#pragma comment(lib, "d3dx9.lib")
#pragma comment(lib, "dxguid.lib")
#pragma comment(lib, "dxerr9.lib")
#pragma comment(lib, "comctl32.lib")
#pragma comment(lib, "winmm.lib")

#ifdef _DEBUG
#pragma comment(lib, "freetype_d.lib")
#pragma comment(lib, "pcre_d.lib")
#pragma comment(lib, "expat_d.lib")
#pragma comment(lib, "CEGUIBase_Static_d.lib")
#pragma comment(lib, "CEGUIExpatParser_Static_d.lib")
#pragma comment(lib, "DirectX9GUIRenderer_Static_d.lib")
#pragma comment(lib, "CEGUIFalagardWRBase_Static_d.lib")
#else
#pragma comment(lib, "freetype.lib")
#pragma comment(lib, "pcre.lib")
#pragma comment(lib, "expat.lib")
#pragma comment(lib, "CEGUIBase_Static.lib")
#pragma comment(lib, "CEGUIExpatParser_Static.lib")
#pragma comment(lib, "DirectX9GUIRenderer_Static.lib")
#pragma comment(lib, "CEGUIFalagardWRBase_Static.lib")
#endif

CEGUI::DirectX9Renderer *myRenderer;
CEGUI::System *mySystem;

HRESULT CALLBACK OnCreateDevice(IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc, void* pUserContext)
{
   using namespace CEGUI;
   myRenderer = new DirectX9Renderer(pd3dDevice, 0);
   myRenderer->preD3DReset();
   mySystem = new System(myRenderer);

   DefaultResourceProvider* rp = static_cast<DefaultResourceProvider*>(System::getSingleton().getResourceProvider());
   rp->setResourceGroupDirectory("schemes", "./datafiles/schemes/");
   rp->setResourceGroupDirectory("imagesets", "./datafiles/imagesets/");
   rp->setResourceGroupDirectory("fonts", "./datafiles/fonts/");   
   rp->setResourceGroupDirectory("looknfeels", "./datafiles/looknfeel/");
   rp->setResourceGroupDirectory("layouts", "./datafiles/layouts/");

   // set the default resource groups to be used
   Imageset::setDefaultResourceGroup("imagesets");
   Font::setDefaultResourceGroup("fonts");
   Scheme::setDefaultResourceGroup("schemes");
   WidgetLookManager::setDefaultResourceGroup("looknfeels");
   WindowManager::setDefaultResourceGroup("layouts");

   SchemeManager::getSingleton().loadScheme("TaharezLook.scheme");
   WindowManager& wmgr = WindowManager::getSingleton();
   Window* myRoot = wmgr.createWindow("DefaultWindow", "root");
   System::getSingleton().setGUISheet(myRoot);
   Window* fWnd = wmgr.createWindow("TaharezLook/FrameWindow", "Window");
   myRoot->addChildWindow(fWnd);

   return S_OK;
}

HRESULT CALLBACK OnResetDevice(IDirect3DDevice9* pd3dDevice, const D3DSURFACE_DESC* pBackBufferSurfaceDesc, void* pUserContext)
{   
   myRenderer->postD3DReset();   
   return S_OK;
}


void CALLBACK OnLostDevice(void* pUserContext)
{
   myRenderer->preD3DReset();
}


void CALLBACK OnDestroyDevice(void* pUserContext)
{
   //SAFE_DELETE(mySystem); // i got crash here
   //SAFE_DELETE(myRenderer);
}

void CALLBACK OnFrameRender(IDirect3DDevice9* pd3dDevice, double fTime, float fElapsedTime, void* pUserContext)
{
   pd3dDevice->Clear(0, 0, D3DCLEAR_TARGET, 0xff707070, 1.0f, 0);
   pd3dDevice->BeginScene();
   mySystem->renderGUI();
   pd3dDevice->EndScene();   

   return;
}

int APIENTRY _tWinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,
                     int       nCmdShow)
{
    DXUTInit( TRUE, TRUE );
    DXUTCreateWindow( L"DXUTTest" );

   DXUTSetCallbackD3D9DeviceCreated(OnCreateDevice);
    DXUTSetCallbackD3D9DeviceReset(OnResetDevice);
    DXUTSetCallbackD3D9DeviceLost(OnLostDevice);
   DXUTSetCallbackD3D9DeviceDestroyed(OnDestroyDevice);
   DXUTSetCallbackD3D9FrameRender(OnFrameRender);

   DXUTCreateDevice(true, 800, 600);
   DXUTMainLoop();

   SAFE_DELETE(mySystem); // here its all ok!
   SAFE_DELETE(myRenderer);


   return DXUTGetExitCode();
// after that static DXUT framework objects starts to destroy and OnLostDevice and OnDestroyDevice pair will be called but something required already destroyed(?) and we get virtual pure call. any ideas how to avoid it?
}

anthony
Just popping in
Just popping in
Posts: 8
Joined: Mon Jan 19, 2009 14:20
Location: Russia, Novocherkassk
Contact:

Postby anthony » Tue Mar 10, 2009 14:02

here is this small solution for VS 2005
http://rapidshare.com/files/207545673/c ... t.zip.html

User avatar
CrazyEddie
CEGUI Project Lead
Posts: 6760
Joined: Wed Jan 12, 2005 12:06
Location: England
Contact:

Postby CrazyEddie » Wed Mar 11, 2009 14:14

What you could do is test to see if the system object is already destroyed before deleting it:

Code: Select all

if (CEGUI::System::getSingletonPtr())
    // destroy system here


If you want me to look at / test the solution posted, it will have to wait until the weekend at the earliest, and even then I can't guarantee anything ;)

CE.

anthony
Just popping in
Just popping in
Posts: 8
Joined: Mon Jan 19, 2009 14:20
Location: Russia, Novocherkassk
Contact:

Postby anthony » Wed Mar 11, 2009 15:53

CrazyEddie wrote:What you could do is test to see if the system object is already destroyed before deleting it:

Code: Select all

if (CEGUI::System::getSingletonPtr())
    // destroy system here


If you want me to look at / test the solution posted, it will have to wait until the weekend at the earliest, and even then I can't guarantee anything ;)

CE.

Yes, I understand that. Anyway thanks for help!

User avatar
CrazyEddie
CEGUI Project Lead
Posts: 6760
Joined: Wed Jan 12, 2005 12:06
Location: England
Contact:

Postby CrazyEddie » Mon Mar 16, 2009 17:42

I did some testing with the posted VC++ project and get the same result (this was with vc9 and CEGUI 0.6.2 SDK, mainly because that's what I have on the VM I'm using).

The callstack indicates that the issue actually happens when destroying Window objects:

Code: Select all

>   ceguitest.exe!CEGUI::WindowManager::cleanDeadPool()  + 0x1b3 bytes   
    ceguitest.exe!CEGUI::System::~System()  + 0x15e bytes   
    ceguitest.exe!CEGUI::System::`vector deleting destructor'()  + 0x2b bytes   
    ceguitest.exe!OnDestroyDevice(void * pUserContext=0x00000000)  Line 95 + 0x3f bytes   C++
    ceguitest.exe!DXUTCleanup3DEnvironment9(bool bReleaseSettings=true)  Line 3340 + 0x12 bytes   C++
    ceguitest.exe!DXUTCleanup3DEnvironment(bool bReleaseSettings=true)  Line 5605 + 0xa bytes   C++
    ceguitest.exe!DXUTShutdown(int nExitCode=0)  Line 6273 + 0x7 bytes   C++
    ceguitest.exe!DXUTState::Destroy()  Line 356   C++
    ceguitest.exe!DXUTState::~DXUTState()  Line 308 + 0x2b bytes   C++
    ceguitest.exe!DXUTState::`scalar deleting destructor'()  + 0x2b bytes   C++
    ceguitest.exe!DXUTDestroyState()  Line 575 + 0x36 bytes   C++
    ceguitest.exe!DXUTMemoryHelper::~DXUTMemoryHelper()  Line 588   C++
    ceguitest.exe!`GetDXUTState'::`2'::`dynamic atexit destructor for 'memory''()  + 0x28 bytes   C++

So I wonder if some statically created object is getting destroyed out of turn somewhere? Even if that is the case, I don't know how to fix that at the moment.

I'll rebuild and retest with a CEGUI built from source in order to drill a bit deeper.

CE

User avatar
CrazyEddie
CEGUI Project Lead
Posts: 6760
Joined: Wed Jan 12, 2005 12:06
Location: England
Contact:

Postby CrazyEddie » Mon Mar 16, 2009 19:53

I can confirm this is/was caused by the static objects CEGUI uses getting destroyed by the c/c++ runtime up before the call was made to perform application cleanup.

The solution is to explicitly call the DXUTShutdown() function in your application main function as opposed to just falling through at the end.

CE.

anthony
Just popping in
Just popping in
Posts: 8
Joined: Mon Jan 19, 2009 14:20
Location: Russia, Novocherkassk
Contact:

Postby anthony » Tue Mar 17, 2009 06:16

CrazyEddie wrote:I can confirm this is/was caused by the static objects CEGUI uses getting destroyed by the c/c++ runtime up before the call was made to perform application cleanup.

The solution is to explicitly call the DXUTShutdown() function in your application main function as opposed to just falling through at the end.

CE.

Yes, this is a solution.
Im wonder, but if link CEGUI dynamically, this error doesn't appear.
Thank you.

User avatar
CrazyEddie
CEGUI Project Lead
Posts: 6760
Joined: Wed Jan 12, 2005 12:06
Location: England
Contact:

Postby CrazyEddie » Tue Mar 17, 2009 11:47

There are inevitably some differences in how things are handled between statically and dynamically linked apps, much of which will be implementation defined.

There can never be any guarantees as regards to what happens when you fall-through main, and subsequently calling back into 'user' code when this happens is fraught with danger.

For my money, the fact it 'works' in a dynamically linked app is just pure luck and is a behaviour that should not be relied upon.

CE.


Return to “Modifications / Integrations / Customisations”

Who is online

Users browsing this forum: No registered users and 1 guest