Unhandled exception __vfptr [0] CXX0030: Error: expression cannot be evaluated
-
Tuesday, October 02, 2007 1:05 AM
I've been trying unsuccessfully to fix an issue with a DLL which uses STL <vector> to store pointers to class objects which contain many virtual functions. Unfortunately the classes have pointers to parents as well as vectors of pointers to children for various purposes (and probably part of the problem - but it works in linux and OSX). The data stored in the objects is accessible, but the virtual functions are not. Below is some variable data where you can see that the m_pipes vector works as expected - __vfptr[0] CAN be evaluated. Unfortunately, I am getting Unhandled exception which I assume is its attempt to access a simple virtual function. I have tried changing the virtual functions which cause problems to either inline or normal functions but it actually causes more problems (even though no classes which are derived are affected in any way).
Code Block- m_pipes {first=??? last=???} std::vector<DGLPipe *,std::allocator<DGLPipe *> >
+ std::_Vector_val<DGLPipe *,std::allocator<DGLPipe *> > {_Alval={...} } std::_Vector_val<DGLPipe *,std::allocator<DGLPipe *> >
- _Myfirst 0x01a17018 DGLPipe * *
- 0x01a16fb0 {m_screenNumber=0 m_screenNumberSet=false m_displayNumber=0 ...} DGLPipe *
- dtkBase {magic_number=40894499 type=40894499 } dtkBase
- __vfptr 0x003a3598 const DGLPipe::`vftable' *
[0] 0x00362022 DGLPipe::`vector deleting destructor'(unsigned int) *
magic_number 40894499 unsigned int
type 40894499 unsigned int
m_screenNumber 0 unsigned int
m_screenNumberSet false bool
m_displayNumber 0 unsigned int
m_displayNumberSet false bool
+ m_hostName 0x00000000 <Bad Ptr> char *
m_hostNameSet false bool
+ m_display 0x01a16da8 {m_dgl=0x01a15680 {m_data=0x00000000 m_postconfig=0x00000000 m_preconfig=0x00000000 ...} m_pipes={first=??? last=???} m_name=0x003a32b4 "DGLDisplay" ...} DGLDisplay *
- m_window {first=??? last=???} std::vector<DGLWindow *,std::allocator<DGLWindow *> >
+ std::_Vector_val<DGLWindow *,std::allocator<DGLWindow *> > {_Alval={...} } std::_Vector_val<DGLWindow *,std::allocator<DGLWindow *> >
- _Myfirst 0x01a17b10 DGLWindow * *
- 0x01a17048 {m_parent=false m_child=false m_cursor=true ...} DGLWindow *
- dtkBase {magic_number=40894499 type=40894499 } dtkBase
- __vfptr 0x01a2b224 *
[0] CXX0030: Error: expression cannot be evaluated *
magic_number 40894499 unsigned int
type 40894499 unsigned int
m_parent false bool
m_child false bool
m_cursor true bool
m_border false bool
m_fullscreen false bool
m_resizeable true bool
m_stereo false bool
m_left 200 int
m_bottom 400 int
m_width 200 unsigned int
m_height 200 unsigned int
m_depth 24 unsigned int
+ m_name 0x01a170d0 "Left" char *
+ m_pipe 0x01a16fb0 {m_screenNumber=0 m_screenNumberSet=false m_displayNumber=0 ...} DGLPipe *
+ m_parentWindow 0x00000000 {m_parent=??? m_child=??? m_cursor=??? ...} DGLWindow *
+ m_surface 0x00000000 {UnknownDimension=??? UnknownAmount=??? _numScreens=??? ...} Producer::RenderSurface *
- m_screen {first=??? last=???} std::vector<DGLScreen *,std::allocator<DGLScreen *> >
+ std::_Vector_val<DGLScreen *,std::allocator<DGLScreen *> > {_Alval={...} } std::_Vector_val<DGLScreen *,std::allocator<DGLScreen *> >
- _Myfirst 0x01a171e8 DGLScreen * *
- 0x01a17138 {m_near=0.10000000 m_far=1000.0000 m_left=-1.0000000 ...} DGLScreen *
- dtkBase {magic_number=40894499 type=40894499 } dtkBase
- __vfptr 0x01a2b19c *
[0] CXX0030: Error: expression cannot be evaluated *
magic_number 40894499 unsigned int
type 40894499 unsigned int
m_near 0.10000000 float
m_far 1000.0000 float
m_left -1.0000000 float
m_right 1.0000000 float
m_bottom -1.0000000 float
m_top 1.0000000 float
m_interoccular 0.070000000 float
m_fov 60.000000 float
m_autoAspect VERTICAL DGLScreen::AUTOASPECT
m_width 2.0000000 float
m_height 2.0000000 float
+ m_offset {x=-1.0000000 y=0.00000000 z=0.00000000 ...} dtkCoord
+ m_window 0x01a17048 {m_parent=false m_child=false m_cursor=true ...} DGLWindow *
+ m_viewport {first=??? last=???} std::vector<DGLViewport *,std::allocator<DGLViewport *> >
+ _Mylast 0x01a171ec DGLScreen * *
+ _Myend 0x01a171ec DGLScreen * *
+ m_km 0x00000000 {_implementation={_ptr=??? } _rs={_ptr=??? } _inputArea={_ptr=??? } ...} Producer::KeyboardMouse *
+ m_eventTranslator 0x00000000 Producer::KeyboardMouseCallback *
+ m_chooser 0xcdcdcdcd {_visual_attributes={first=??? last=???} _vinfo=??? _visual_id=??? ...} Producer::VisualChooser *
m_context 0 int
m_cNum -842150451 int
+ _Mylast 0x01a17b28 DGLWindow * *
+ _Myend 0x01a17b28 DGLWindow * *
+ _Mylast 0x01a1701c DGLPipe * *
+ _Myend 0x01a1701c DGLPipe * *
If you want to see the source (requries subversion):
svn co https://diverse.svn.sourceforge.net/svnroot/diverse/trunk diverse
And to build it (requires cmake)
mkdir diverse-build
cmake -i ..\diverse (to build projects files for MSVC)
or
cmake -G "NMake Makefiles" -i ..\diverse (to build NMake makefiles)
nmake
Be sure to set DGL_BUILD_EXAMPLES:BOOL = ON in cmake configuration or CMakeCache.txt file. This will allow it to build the helix.exe example.
It will probably complain about missing dependencies but you should be able to test it as follows:
To test:
set DGL_DSO_FILES=desktopHyperDisplay;desktopGroup
cd dgl\examples\CCallbackHelix
helix.exe
It will have an unhandled exception which if you debug it will stop in DGLDisplay.cpp on line 110. I have tested it to see where it fails - I can print the pointer to the getSharedParent function, but calling it causes the unhandled exception.
Any help or ideas would be greatly appreciated.
Thanks,
Pat
All Replies
-
Tuesday, October 02, 2007 11:21 AM
What version of Visual C++ are you using for compilation?
If you are using Visual C++ 6, you may use STLport as STL implementation.
(If you are using Visual C++ 2003 or 2005, I think that STLport is not required.)
Moreover, in your code in DGLDisplay.cpp on line 110:
Code Blockm_pipes[i]->getWindow(j)->getSharedParent
I would prefer not using operator(), but using instead std::vector::at method, so you can have a bound-check for the vector index.
Giovanni
-
Tuesday, October 02, 2007 2:24 PMThanks for your response - unfortunately it is not what I need. I should have provided more information in my initial post. I am using Visual C++ 2003.
I have provided some additional code and I have updated my code to print the values of the pointers for each. The problem appears to be a missing or corrupt vftable. If I change the functions to non-virtual then an unhandled exception will occur at the next virtual function which is called (for the class objects which seem to be below a certain level. Hence, my thought that the issue is with the vftable.
Code Block/*
Thsi comment block shows the accessor functions and vectors being used:
DGLDisplay::std::vector<DGLPipe*> m_pipes;
DGLPipe::std::vector<DGLWindow*> m_windows;
virtual int DGLPipe::getNumWindows()
{
return m_windows.size();
}
virtual DGLWindow* DGLPipe::getWindow(unsigned int index)
{
if(index < m_windows.size())
return m_windows[index];
return NULL;
}
*/
// The code below is where the unhandled exception occurs
for (unsigned int i=0; i< m_pipes.size(); i++)
{
for (unsigned int j=0; j< m_pipes[i]->getNumWindows(); j++)
{printf( "m_pipes[%d]: %p\n", i, m_pipes[i] );
printf( "m_pipes[%d]->getWindow(%d): %p\n", i, j, m_pipes[i]->getWindow(j) );
printf( "m_pipes[%d]->getWindow(%d)->getSharedParent: %p\n", i, j, m_pipes[i]->getWindow(j)->getSharedParent );
printf( "m_pipes[%d]->getWindow(%d)->getSharedParent(): %d\n", i, j, m_pipes[i]->getWindow(j)->getSharedParent() );// FAILS!!!
if (m_pipes[i]->getWindow(j)->getSharedParent()) // FAILS!!!
{
DGL::getApp()->setMultiThreaded(false);
dtkMsg.add(DTKMSG_DEBUG, "DGLDisplay::config() Warning, cannot multi-thread with shared contexts, switching to single threaded mode.\n");
}
}
}
Output from above:
> helix.exe
m_pipes[0]: 017C6E28
m_pipes[0]->getWindow(0): 017C6EC0
m_pipes[0]->getWindow(0)->getSharedParent: 100019F6
The line which actually calls the getSharedParent causes the unhandled exception. From the output window of vc++2003 after going into Debug mode.
Unhandled exception at 0x100204d8 (dgl.dll) in helix.exe: 0xC0000005: Access violation reading location 0x017db28c.
Variables:
i 0 unsigned int
j 0 unsigned int
- m_pipes {first=??? last=???} std::vector<DGLPipe *,std::allocator<DGLPipe *> >
+ std::_Vector_val<DGLPipe *,std::allocator<DGLPipe *> > {_Alval={...} } std::_Vector_val<DGLPipe *,std::allocator<DGLPipe *> >
- _Myfirst 0x017c6e90 DGLPipe * *
- 0x017c6e28 {m_screenNumber=0 m_screenNumberSet=false m_displayNumber=0 ...} DGLPipe *
- dtkBase {magic_number=40894499 type=40894499 } dtkBase
- __vfptr 0x10043598 const DGLPipe::`vftable' *
[0] 0x10002027 DGLPipe::`vector deleting destructor'(unsigned int) *
magic_number 40894499 unsigned int
type 40894499 unsigned int
m_screenNumber 0 unsigned int
m_screenNumberSet false bool
m_displayNumber 0 unsigned int
m_displayNumberSet false bool
+ m_hostName 0x00000000 <Bad Ptr> char *
m_hostNameSet false bool
+ m_display 0x017c6c58 {m_dgl=0x017c54e0 {m_data=0x00000000 m_postconfig=0x00000000 m_preconfig=0x00000000 ...} m_pipes={first=??? last=???} m_name=0x100432b4 "DGLDisplay" ...} DGLDisplay *
- m_window {first=??? last=???} std::vector<DGLWindow *,std::allocator<DGLWindow *> >
+ std::_Vector_val<DGLWindow *,std::allocator<DGLWindow *> > {_Alval={...} } std::_Vector_val<DGLWindow *,std::allocator<DGLWindow *> >
- _Myfirst 0x017c7988 DGLWindow * *
- 0x017c6ec0 {m_parent=false m_child=false m_cursor=true ...} DGLWindow *
- dtkBase {magic_number=40894499 type=40894499 } dtkBase
- __vfptr 0x017db224 *
[0] CXX0030: Error: expression cannot be evaluated *
magic_number 40894499 unsigned int
type 40894499 unsigned int
m_parent false bool
m_child false bool
m_cursor true bool
m_border false bool
m_fullscreen false bool
m_resizeable true bool
m_stereo false bool
m_left 200 int
m_bottom 400 int
m_width 200 unsigned int
m_height 200 unsigned int
m_depth 24 unsigned int
+ m_name 0x017c6f48 "Left" char *
+ m_pipe 0x017c6e28 {m_screenNumber=0 m_screenNumberSet=false m_displayNumber=0 ...} DGLPipe *
+ m_parentWindow 0x00000000 {m_parent=??? m_child=??? m_cursor=??? ...} DGLWindow *
+ m_surface 0x00000000 {UnknownDimension=??? UnknownAmount=??? _numScreens=??? ...} Producer::RenderSurface *
+ m_screen {first=??? last=???} std::vector<DGLScreen *,std::allocator<DGLScreen *> >
+ m_km 0x00000000 {_implementation={_ptr=??? } _rs={_ptr=??? } _inputArea={_ptr=??? } ...} Producer::KeyboardMouse *
+ m_eventTranslator 0x00000000 Producer::KeyboardMouseCallback *
+ m_chooser 0xcdcdcdcd {_visual_attributes={first=??? last=???} _vinfo=??? _visual_id=??? ...} Producer::VisualChooser *
m_context 0 int
m_cNum -842150451 int
+ _Mylast 0x017c79a0 DGLWindow * *
+ _Myend 0x017c79a0 DGLWindow * *
+ _Mylast 0x017c6e94 DGLPipe * *
+ _Myend 0x017c6e94 DGLPipe * *
+ this 0x017c6c58 {m_dgl=0x017c54e0 {m_data=0x00000000 m_postconfig=0x00000000 m_preconfig=0x00000000 ...} m_pipes={first=??? last=???} m_name=0x100432b4 "DGLDisplay" ...} DGLDisplay * const
The address of the getSharedParent function at least exists within the correct module dgl.dll:
dgl.dll 10000000-1005A000 C:\Program Files\DIVERSE\bin\dgl.dll 13 [3576] helix.exe: Native 10/2/2007 9:48 AM Symbols loaded.
What concerns me most is the lack of __vfptr data. -
Tuesday, October 02, 2007 2:46 PM
In DGLWindow.h you define several virtual member functions, but you also provide the implementation of the virtual function body into the class header, like if it was inlined.
I don't know if it is correct standard C++...
Just for test, could you please try to put the body of the virtual functions into a separate C++ file (not inline in the class header) ?
i.e.:
in the header, put only virtual function declarations:
Code Block// In DGLWindow.h
...
virtual bool getSharedParent(); // No function body here
In DGLWindow.cpp, put the implementation:
Code Blockbool DGLWindow::getSharedParent()
{
return m_parent;
}
Giovanni
-
Tuesday, October 02, 2007 3:14 PMThanks again for the response.
I also saw that and thought it could be an issue but separating the implementation from the declaration had no effect. I also tried many different compiler and linker flags. I have also tried exporting the vectors as discussed in this article. All to no effect.
For some reason I cannot yet fathom, the vftable is not being created properly. Since there is an interdependency between the classes which cause the problem and which requires that a placeholder for the other classes is set in some of the header files, I have tried changing the order in which the headers are #included as well as which headers have placeholders and for which classes. But, again, no effect. It is all very frustrating.
If you have any other ideas, please let me know. -
Tuesday, October 02, 2007 5:31 PMAs a test I added some code to see if adding pointers to a vector and then referencing them would cause similar problems.
Code Block
DGLWindow test_window;
printf( "test_window.getSharedParent(): %d\n", test_window.getSharedParent() );
DGLWindow* test_win_ptr = new DGLWindow;
printf( "test_win_ptr->getSharedParent(): %d\n", test_win_ptr->getSharedParent() );
std::vector<DGLWindow*> win_vector;
for(unsigned int a=0;a<5;a++)
{
DGLWindow* win_ptr = new DGLWindow;
printf( "win_ptr->getSharedParent(): %d\n", win_ptr->getSharedParent() );
win_vector.push_back(win_ptr);
printf( "win_vector[%d]->getSharedParent(): %d\n", a, win_vector[a]->getSharedParent() );
}
for (unsigned int i=0; i< m_pipes.size(); i++)
{
for (unsigned int j=0; j< m_pipes[i]->getNumWindows(); j++)
{
printf( "m_pipes[%d]: %p\n", i, m_pipes[i] );
printf( "m_pipes[%d]->getWindow(%d): %p\n", i, j, m_pipes[i]->getWindow(j) );
printf( "m_pipes[%d]->getWindow(%d)->getSharedParent: %p\n", i, j, m_pipes[i]->getWindow(j)->getSharedParent );
printf( "m_pipes[%d]->getWindow(%d)->getSharedParent(): %d\n", i, j, m_pipes[i]->getWindow(j)->getSharedParent() );
if (m_pipes[i]->getWindow(j)->getSharedParent())
{
DGL::getApp()->setMultiThreaded(false);
dtkMsg.add(DTKMSG_DEBUG, "DGLDisplay::config() Warning, cannot multi-thread with shared contexts, switching to single threaded mode.\n");
}
}
}
for (unsigned int i=0; i< m_pipes.size(); i++)
{
for (unsigned int j=0; j< m_pipes[i]->getNumWindows(); j++)
{
m_pipes[i]->getWindow(j)->create();
}
}
//now create viewports
for (unsigned int i=0; i< m_pipes.size(); i++)
{
for (unsigned int j=0; j< m_pipes[i]->getNumWindows(); j++)
{
//Create the viewports that are inside of each screen that is inside of each window (Holy nested loops (batman))
for (unsigned int k=0; k < m_pipes[i]->getWindow(j)->getNumScreens(); k++)
{
for (unsigned int l=0; l < m_pipes[i]->getWindow(j)->getScreen(k)->getNumViewports(); l++)
{
m_pipes[i]->getWindow(j)->getScreen(k)->getViewport(l)->create();
}
}
}
}
The output:
test_window.getSharedParent(): 0
test_win_ptr->getSharedParent(): 0
win_ptr->getSharedParent(): 0
win_vector[0]->getSharedParent(): 0
win_ptr->getSharedParent(): 0
win_vector[1]->getSharedParent(): 0
win_ptr->getSharedParent(): 0
win_vector[2]->getSharedParent(): 0
win_ptr->getSharedParent(): 0
win_vector[3]->getSharedParent(): 0
win_ptr->getSharedParent(): 0
win_vector[4]->getSharedParent(): 0
m_pipes[0]: 017C6E28
m_pipes[0]->getWindow(0): 017C6EC0
m_pipes[0]->getWindow(0)->getSharedParent: 100019F6
So, it appears to be an issue with the DGLWindow class object being contained by the std::vector of the DGLPipe... so perhaps there is some issue with DGLPipe. Or the issue might be that the pipes, windows, screens, and viewports are all instantiated through DLL plugins so perhaps the plugins are not importing or exporting properly.
Addendum:
Actually, it is the plugins. I had all of the instantiations occuring directly in the plugin loader function (dllexported). But, as a test, I moved everything into constructor of a new class (local to the loader but NOT dllexported) and instantiated the class from the loader function and now it works. So, it probably does have something to do with the DLL export/import but I have no idea what the exact problem is. So, now I just have to edit all files that instatiates stuff directly from the loader function and move it into a local class.
I appreciate your help. -
Tuesday, October 02, 2007 6:16 PM
If the problem is in the DLL plugins, it would be interesting to see how do you export/import...
For example: you should pay attention to calling conventions. There are several calling conventions in Windows programming (e.g. __stdcall, __cdecl,...) they should all match in your code.
Moreover, do you use the "Multi-threaded Debug DLL (/MDd)" option as Runtime library for the debug build?
(If you use the VC2003 IDE, it is in: Project Configuration Properties | C/C++ | Code Generation | Runtime Library. If you use the command line it should be the /MDd switch.)
Giovanni
-
Tuesday, October 02, 2007 6:19 PM
For anyone writing DLL plugins or using dynamically loaded DLLs, it appears that unloading a DLL after instantiating what you hoped would be persistent objects that are defined in another loaded DLL is a bad idea - this will give you the inaccessible vftables. -
Tuesday, October 02, 2007 6:25 PMI believe it is the __stdcall. Also, the /MDd flag is used to build the DLLs. It appears to be that the unloading of the DLL which only instantiates the class objects existing in another DLL corrupted the vftable of those objects.
-
Tuesday, October 02, 2007 7:49 PM
You may consider using some reference counting technique like COM's IUnknown::AddRef/Release...
(BTW: I think that COM offers a very good object system infrastructure; if you are going to develop an object-based DLL plugin system, you may consider using COM.)
Giovanni

