Fix use of previously deallocated EmergeManager
authorkwolekr <kwolekr@minetest.net>
Sun, 26 Jan 2014 06:12:18 +0000 (01:12 -0500)
committerkwolekr <kwolekr@minetest.net>
Sun, 26 Jan 2014 06:12:18 +0000 (01:12 -0500)
src/emerge.cpp
src/emerge.h
src/server.cpp

index ff00a0b62bf862aa8c616cf4d6c0f4b3e0e4d6b7..bd9b7c7bda9ba6363a3ab0dfa26c69949df1670d 100644 (file)
@@ -92,6 +92,11 @@ EmergeManager::EmergeManager(IGameDef *gamedef) {
        this->biomedef = new BiomeDefManager();
        this->params   = NULL;
 
+       // Note that accesses to this variable are not synchronized.
+       // This is because the *only* thread ever starting or stopping
+       // EmergeThreads should be the ServerThread.
+       this->threads_active = false;
+
        this->luaoverride_params          = NULL;
        this->luaoverride_params_modified = 0;
        this->luaoverride_flagmask        = 0;
@@ -128,9 +133,11 @@ EmergeManager::EmergeManager(IGameDef *gamedef) {
 
 EmergeManager::~EmergeManager() {
        for (unsigned int i = 0; i != emergethread.size(); i++) {
-               emergethread[i]->Stop();
-               emergethread[i]->qevent.signal();
-               emergethread[i]->Wait();
+               if (threads_active) {
+                       emergethread[i]->Stop();
+                       emergethread[i]->qevent.signal();
+                       emergethread[i]->Wait();
+               }
                delete emergethread[i];
                delete mapgen[i];
        }
@@ -252,9 +259,32 @@ Mapgen *EmergeManager::getCurrentMapgen() {
 }
 
 
-void EmergeManager::startAllThreads() {
+void EmergeManager::startThreads() {
+       if (threads_active)
+               return;
+
        for (unsigned int i = 0; i != emergethread.size(); i++)
                emergethread[i]->Start();
+
+       threads_active = true;
+}
+
+
+void EmergeManager::stopThreads() {
+       if (!threads_active)
+               return;
+
+       // Request thread stop in parallel
+       for (unsigned int i = 0; i != emergethread.size(); i++) {
+               emergethread[i]->Stop();
+               emergethread[i]->qevent.signal();
+       }
+
+       // Then do the waiting for each
+       for (unsigned int i = 0; i != emergethread.size(); i++)
+               emergethread[i]->Wait();
+
+       threads_active = false;
 }
 
 
index b2b00adc9a531625632011056aa56e48d4a163ce..17097327b3daf0d23858ecb848f11f861cf638a4 100644 (file)
@@ -87,6 +87,8 @@ public:
        std::vector<Mapgen *> mapgen;
        std::vector<EmergeThread *> emergethread;
 
+       bool threads_active;
+
        //settings
        MapgenParams *params;
        bool mapgen_debug_info;
@@ -119,7 +121,8 @@ public:
        Mapgen *createMapgen(std::string mgname, int mgid,
                                                MapgenParams *mgparams);
        MapgenParams *createMapgenParams(std::string mgname);
-       void startAllThreads();
+       void startThreads();
+       void stopThreads();
        bool enqueueBlockEmerge(u16 peer_id, v3s16 p, bool allow_generate);
 
        void registerMapgen(std::string name, MapgenFactory *mgfactory);
index 47b11d3da3f6a43f1eddfd082c4b89b020f51728..0ada4d8181b5234e099e866d9036227c370bb9ac 100644 (file)
@@ -917,8 +917,9 @@ Server::~Server()
        stop();
        delete m_thread;
 
-       //shutdown all emerge threads first!
-       delete m_emerge;
+       // stop all emerge threads before deleting players that may have
+       // requested blocks to be emerged
+       m_emerge->stopThreads();
 
        /*
                Delete clients
@@ -938,6 +939,10 @@ Server::~Server()
 
        // Delete things in the reverse order of creation
        delete m_env;
+
+       // N.B. the EmergeManager should be deleted after the Environment since Map
+       // depends on EmergeManager to write its current params to the map meta
+       delete m_emerge;
        delete m_rollback;
        delete m_banmanager;
        delete m_event;
@@ -1684,7 +1689,7 @@ void Server::AsyncRunStep(bool initial_step)
                {
                        counter = 0.0;
 
-                       m_emerge->startAllThreads();
+                       m_emerge->startThreads();
 
                        // Update m_enable_rollback_recording here too
                        m_enable_rollback_recording =