none
Unhandled exception __vfptr [0] CXX0030: Error: expression cannot be evaluated

    Question


  • 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




    Tuesday, October 02, 2007 1:05 AM

Answers

  • 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:19 PM

All replies

  • 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 Block

    m_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 11:21 AM
  • Thanks 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:24 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 Block

    bool DGLWindow::getSharedParent()

    {

        return m_parent;

     

     

     

     

    Giovanni

     

    Tuesday, October 02, 2007 2:46 PM
  • Thanks 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 3:14 PM
  • As 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 5:31 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:16 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:19 PM
  • I 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 6:25 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

     

    Tuesday, October 02, 2007 7:49 PM