ddmd

D/DMD: Exiting program causes errors (segfault, sigabort, ...)


I have freetime game projects, written with D, SDL2 and OpenGL (derelict), shared parts forming sort-of-engine. Key points:

The entire source can be accessed here: https://github.com/mkoskim/games

Symptom: exiting - both quit'ing with exit() and returning from main() - causes almost always glibc to throw various signals or segfault, like:

*** Error ...: munmap_chunk(): invalid pointer: ... *** ... Aborted
*** Error ...: double free or corruption (out): ... *** ... Aborted
*** Error ...: free(): invalid pointer: ... *** ... Aborted
*** Error ...: corrupted double-linked list: ... *** ... Aborted
*** core.exception.InvalidMemoryOperationError@src/core/exception.d(679): ...
**** Segmentation fault

Making small changes - like adding destructor to Framebuffer class or anything - can change the behavior, and even then, this does not happen in every game sketches I have. At the moment it happens in 'projects/cylinderium', but don't happen in projects like 'demo/objectview' or 'testbench/wolfish'.

I have long time suspected it to be caused by SDL2 library objects (like SDL_Surface), as those are allocated outside D runtime, but I haven't yet managed to track down this. Another suspect I have is that there happens calls from object destructor to e.g. derelict, and that has already been destructed.

Basically getting errors at shutdown is not dangerous, as exit will anyways clear everything. But before knowing the reason I am worried that this is a symptom of a more severe error, which would then explode when I have more complex game (e.g. during loading a new game level, or running a game for a long time).

Questions:

1) In what order DMD runtime calls destructors? Could it cause e.g. derelict OpenGL interface to be destructed before destructors of all the created objects using OpenGL functions (e.g. glDeleteTextures) are called?

2) I have already hooked most destructors in my own classes, but can I hook every single destructor to track down what and in what order DMD is deleting at runtime shutdown?

3) If you happen to be able to successfully fetch, compile and run the projects, I would be pleased to hear if you can reproduce the error.

I'm bit out of ideas at the moment, any ideas where to look would be appreciated.


Solution

  • I think I have found the reason.

    For sake of completeness, the module which had initialized SDL (SDL_Init, TTF_Init, ...) in static constructor has had static destructor to shut them down (SDL_Quit, ...). On the other hand, I have individually deleted resources allocated by SDL in destructors who have allocated them. These are needed to deallocate resources at runtime.

    I have already earlier struggled with destructors freeing SDL_Font* and SDL_Surface*, and for that reason I added global SDL_up flag to prevent calls after SDL shutdown.

    What I had forgotten was that I also had Joystick managing SDL resource... More debugging revealed that module destructor was indeed called before joystick destructor, and calling SDL to free the resource caused the error.

    FIX: I removed SDL/TTF/IMG Quit calls from module destructor, and SDL_up flag. This is already second time I was spending hours and hours for the same reason, and I decided that it is better not to make resource deallocation more complex, but give up orthodoxis complete Init-Quit call pairs (and let system exit to get rid of SDL).