Fixed crash when exiting because Graphics and GraphicHash are freed before CPatchManager

The earlier fix in bos SVN trunk r9918 on 2010-07-02 does not work
reliably with GCC 4.4.5; it seems std::map::~map does not bother
marking the map as empty.  Instead, rely on C++ constructing objects
in the order of definition and destructing them in the opposite order.

In DEBUG builds, also add assertions to catch any attempt to access
Graphics or GraphicsHash before they are constructed or after they are
destructed.
This commit is contained in:
kon 2011-03-05 14:02:21 +00:00
parent da3b369551
commit c84ac83904

View file

@ -52,12 +52,47 @@
-- Variables
----------------------------------------------------------------------------*/
static enum {
ModuleNotInitialized,
ModuleOK,
ModuleDeinitialized
} GraphicsState;
static int HashCount;
static std::map<std::string, CGraphic *> GraphicHash;
static std::list<CGraphic *> Graphics;
struct CGraphicsModule {
CGraphicsModule() {
GraphicsState = ModuleOK;
}
~CGraphicsModule() {
GraphicsState = ModuleDeinitialized;
}
static void AssertOK() {
#ifdef DEBUG
switch (GraphicsState) {
case ModuleNotInitialized:
fprintf(stderr, "The graphics module hasn't yet been initialized\n");
// Do not call ExitFatal, because that calls exit,
// which might attempt to call destructors again.
abort();
case ModuleOK:
break;
case ModuleDeinitialized:
fprintf(stderr, "The graphics module has already been deinitialized\n");
abort();
default:
abort();
}
#endif // DEBUG
}
};
static CGraphicsModule GraphicsModule;
/*----------------------------------------------------------------------------
-- Functions
----------------------------------------------------------------------------*/
@ -490,6 +525,8 @@ CGraphic *CGraphic::New(const std::string &file, int w, int h)
return new CGraphic;
}
CGraphicsModule::AssertOK();
CGraphic *g = GraphicHash[file];
if (!g) {
g = new CGraphic;
@ -526,6 +563,8 @@ CPlayerColorGraphic *CPlayerColorGraphic::New(const std::string &file, int w, in
return new CPlayerColorGraphic;
}
CGraphicsModule::AssertOK();
CPlayerColorGraphic *g = dynamic_cast<CPlayerColorGraphic *>(GraphicHash[file]);
if (!g) {
g = new CPlayerColorGraphic;
@ -558,6 +597,7 @@ CPlayerColorGraphic *CPlayerColorGraphic::New(const std::string &file, int w, in
*/
CGraphic *CGraphic::ForceNew(const std::string &file, int w, int h)
{
CGraphicsModule::AssertOK();
CGraphic *g = new CGraphic;
if (!g) {
fprintf(stderr, "Out of memory\n");
@ -602,6 +642,7 @@ CGraphic *CGraphic::Clone() const
*/
CPlayerColorGraphic *CPlayerColorGraphic::ForceNew(const std::string &file, int w, int h)
{
CGraphicsModule::AssertOK();
CPlayerColorGraphic *g = new CPlayerColorGraphic;
if (!g) {
fprintf(stderr, "Out of memory\n");
@ -654,6 +695,8 @@ void CGraphic::Load()
return;
}
CGraphicsModule::AssertOK();
// TODO: More formats?
if (LoadGraphicPNG(this, false) == -1) {
fprintf(stderr, "Can't load the graphic `%s'\n", File.c_str());
@ -738,7 +781,7 @@ void CGraphic::Free(CGraphic *g)
}
}
if (!Graphics.empty()) {
if (GraphicsState == ModuleOK) {
Graphics.remove(g);
}
}
@ -747,7 +790,7 @@ void CGraphic::Free(CGraphic *g)
FreeSurface(&g->SurfaceFlip);
if (!g->HashFile.empty()) {
if (!GraphicHash.empty()) {
if (GraphicsState == ModuleOK) {
GraphicHash.erase(g->HashFile);
}
}
@ -760,6 +803,8 @@ void CGraphic::Free(CGraphic *g)
*/
void FreeOpenGLGraphics()
{
CGraphicsModule::AssertOK();
std::list<CGraphic *>::iterator i;
for (i = Graphics.begin(); i != Graphics.end(); ++i) {
if ((*i)->Textures) {
@ -781,6 +826,7 @@ void FreeOpenGLGraphics()
*/
void ReloadGraphics()
{
CGraphicsModule::AssertOK();
std::list<CGraphic *>::iterator i;
for (i = Graphics.begin(); i != Graphics.end(); ++i) {
if ((*i)->Textures) {
@ -1326,6 +1372,7 @@ void CGraphic::MakeShadow()
void FreeGraphics()
{
CGraphicsModule::AssertOK();
std::map<std::string, CGraphic *>::iterator i;
while (!GraphicHash.empty()) {
i = GraphicHash.begin();