Browse Source

Fixed shutdown crash in ~Math.

The 'registry' global in Module.cpp appears to be destroyed before the last
module is destroyed, specifically the math module. This is bad, because ~Module
tries to look for itself in 'registry' after it's gone. This causes a nasty
debug assert in VS2012, and a shutdown crash in release builds.

Fixed by dynamically allocating/releasing the registry.
rude 12 years ago
parent
commit
fc5d5e3f26
1 changed files with 39 additions and 10 deletions
  1. 39 10
      src/common/Module.cpp

+ 39 - 10
src/common/Module.cpp

@@ -29,7 +29,30 @@
 
 namespace
 {
-	std::map<std::string, love::Module*> registry;
+	typedef std::map<std::string, love::Module*> ModuleRegistry;
+
+	// The registry must be dynamically managed, because some modules
+	// (the math module) are static globals that are not guaranteed to
+	// be destroyed before other static globals.
+	ModuleRegistry *registry = nullptr;
+
+	ModuleRegistry &registryInstance()
+	{
+		if (!registry)
+			registry = new ModuleRegistry;
+
+		return *registry;
+	}
+
+	void freeEmptyRegistry()
+	{
+		if (registry && registry->empty())
+		{
+			delete registry;
+			registry = nullptr;
+		}
+	}
+
 } // anonymous namespace
 
 namespace love
@@ -37,10 +60,10 @@ namespace love
 
 Module::~Module()
 {
-	std::map<std::string, Module*>::iterator it;
+	ModuleRegistry &registry = registryInstance();
 
 	// We can't use the overridden Module::getName() in this destructor.
-	for (it = registry.begin(); it != registry.end(); ++it)
+	for (auto it = registry.begin(); it != registry.end(); ++it)
 	{
 		if (it->second == this)
 		{
@@ -48,16 +71,20 @@ Module::~Module()
 			break;
 		}
 	}
+
+	freeEmptyRegistry();
 }
 
 void Module::registerInstance(Module *instance)
 {
-	if (instance == NULL)
+	if (instance == nullptr)
 		throw Exception("Module instance is NULL");
 
 	std::string name(instance->getName());
 
-	std::map<std::string, Module*>::iterator it = registry.find(name);
+	ModuleRegistry &registry = registryInstance();
+
+	auto it = registry.find(name);
 
 	if (it != registry.end())
 	{
@@ -71,25 +98,27 @@ void Module::registerInstance(Module *instance)
 
 Module *Module::getInstance(const std::string &name)
 {
-	std::map<std::string, Module*>::const_iterator it = registry.find(name);
+	ModuleRegistry &registry = registryInstance();
+
+	auto it = registry.find(name);
 
 	if (registry.end() == it)
-		return NULL;
+		return nullptr;
 
 	return it->second;
 }
 
 Module *Module::findInstance(const std::string &name)
 {
-	std::map<std::string, Module*>::const_iterator it;
+	ModuleRegistry &registry = registryInstance();
 
-	for (it = registry.begin(); it != registry.end(); ++it)
+	for (auto it = registry.begin(); it != registry.end(); ++it)
 	{
 		if (it->first.find(name) == 0)
 			return it->second;
 	}
 
-	return NULL;
+	return nullptr;
 }
 
 } // love