#206 Segfault on shutdown if glutMainLoop not called (fglrx)

open
nobody
None
5
2014-01-21
2013-12-29
Bruce Merry
No

The following code segfaults when using freeglut 2.8.1 and AMD Catalyst drivers 13.12.

include <GL glut.h="">

int main(int argc, char **argv)
{
glutInit(&argc, argv);
glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH);
glutInitWindowSize(300, 300);
glutCreateWindow("Window");
glutDestroyWindow(glutGetWindow());
return 0;
}

From some investigation, the problem appears to be that glutInit uses atexit to register shutdown code, and at a later point (I think the first time a glX function is called), the fglrx driver also registers some shutdown code with __cxa_atexit. Because it is registered later, it runs first, and presumably puts things into a state where fgDeinitialize ends up corrupting data. The actual segfault doesn't seem to have fgDeinitialize in the stack, but presumably it is corrupting something that then breaks later shutdown code.

If glutMainLoop is called, then it explicitly calls fgDeinitialize before main() returns, and all is well (fgDeinitialize still runs at shutdown, but it doesn't do anything since freeglut has already shut down). Similarly, if I manually call fgDeinitialize, then there is no segfault.

I've filed this as a bug in AMD's unofficial bugzilla (http://ati.cchtml.com/show_bug.cgi?id=979), but who knows if it will be fixed. As a workaround, the atexit registration should presumably be delayed until after the first GLX call (or possibly use a second atexit call, if there is no guarantee that there will be such a call). Another possibility might be to make a dummy GLX call earlier on, to force the driver to do its own atexit registration.

Discussion

  • Hi Bruce,

    Since you are talking about glX function calls, I assume this happens on Linux?

    Thanks,
    Dee

     
  • Bruce Merry
    Bruce Merry
    2014-01-17

    Yes, I should have mentioned that. Ubuntu 13.10.

     
  • There is a glx call before atexit. fg_init_x11.c in fgPlatformInitialize: glXQueryExtension is called on line 182, while the atexit call is done on line 254.

    If you can figure out exactly which part of fgDeinitialize causes the crash (if any), then feel free to post more info and I'll look into it. But as it stands, without being able to reporduce the bug, and without concrete information on what's going wrong, I can't do anything.

    Plus this all is very pointless; a glut program without a call to glutMainLoop is useless anyway.

     
  • Bruce Merry
    Bruce Merry
    2014-01-17

    I'm guessing that glXQueryExtension doesn't trigger the driver registration because it just checks that GLX is present without doing anything.

    When I have a chance I'll experiment with sticking in some other GLX calls to see if I can make a workaround.

    Plus this all is very pointless; a glut program without a call to glutMainLoop is useless anyway.

    I haven't actually tested it, but I suspect that the same problem will occur if the user directly calls exit() once glutMainLoop is running.

    The context is that I have a unit test which creates a context, pokes it a bit, and then returns an exit code to the shell to indicate success or failure, all without user interaction. GLUT without glutMainLoop is pretty handy in that case. If I call glutMainLoop, the only ways I can see to influence the exit code are to call exit() myself (which I think will crash again), or to set GLUT_ACTION_ON_WINDOW_CLOSE (which is not portable to the original GLUT).

     
  • Bruce Merry
    Bruce Merry
    2014-01-19

    The following patch fixes the crash on my machine, and I think should be reasonably harmless. I've also confirmed that the segfault occurs if glutMainLoop is called but the application calls exit().

    Index: src/x11/fg_init_x11.c
    ===================================================================
    --- src/x11/fg_init_x11.c   (revision 1638)
    +++ src/x11/fg_init_x11.c   (working copy)
    @@ -182,6 +182,14 @@
         if( !glXQueryExtension( fgDisplay.pDisplay.Display, NULL, NULL ) )
             fgError( "OpenGL GLX extension not supported by display '%s'",
                 XDisplayName( displayName ) );
    +
    +    /* This forces AMD Catalyst drivers to initialize and register a shutdown
    +     * function, which must be done before our own call to atexit to prevent
    +     * a crash if glutMainLoop is not called or is not exited cleanly.
    +     * (http://sourceforge.net/p/freeglut/bugs/206/)
    +     */
    +    glXQueryExtensionsString( fgDisplay.pDisplay.Display,
    +        DefaultScreen( fgDisplay.pDisplay.Display ));
     #endif
    
         fgDisplay.pDisplay.Screen = DefaultScreen( fgDisplay.pDisplay.Display );
    
     
  • This looks fine. Commited, svn revision 1640.
    Cheers.