Safely handle block deletion (#13315)

Co-authored-by: Jude Melton-Houghton <jwmhjwmh@gmail.com>
This commit is contained in:
DS 2023-03-24 12:34:44 +01:00 committed by GitHub
parent f3b198e490
commit ed632f3854
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 74 additions and 5 deletions

@ -1309,6 +1309,8 @@ ServerMap::~ServerMap()
*/ */
delete dbase; delete dbase;
delete dbase_ro; delete dbase_ro;
deleteDetachedBlocks();
} }
MapgenParams *ServerMap::getMapgenParams() MapgenParams *ServerMap::getMapgenParams()
@ -1888,12 +1890,31 @@ bool ServerMap::deleteBlock(v3s16 blockpos)
MapSector *sector = getSectorNoGenerate(p2d); MapSector *sector = getSectorNoGenerate(p2d);
if (!sector) if (!sector)
return false; return false;
sector->deleteBlock(block); // It may not be safe to delete the block from memory at the moment
// (pointers to it could still be in use)
sector->detachBlock(block);
m_detached_blocks.push_back(block);
} }
return true; return true;
} }
void ServerMap::deleteDetachedBlocks()
{
for (MapBlock *block : m_detached_blocks) {
assert(block->isOrphan());
delete block;
}
m_detached_blocks.clear();
}
void ServerMap::step()
{
// Delete from memory blocks removed by deleteBlocks() only when pointers
// to them are (probably) no longer in use
deleteDetachedBlocks();
}
void ServerMap::PrintInfo(std::ostream &out) void ServerMap::PrintInfo(std::ostream &out)
{ {
out<<"ServerMap: "; out<<"ServerMap: ";

@ -412,8 +412,15 @@ public:
// Database version // Database version
void loadBlock(std::string *blob, v3s16 p3d, MapSector *sector, bool save_after_load=false); void loadBlock(std::string *blob, v3s16 p3d, MapSector *sector, bool save_after_load=false);
// Blocks are removed from the map but not deleted from memory until
// deleteDetachedBlocks() is called, since pointers to them may still exist
// when deleteBlock() is called.
bool deleteBlock(v3s16 blockpos) override; bool deleteBlock(v3s16 blockpos) override;
void deleteDetachedBlocks();
void step();
void updateVManip(v3s16 pos); void updateVManip(v3s16 pos);
// For debug printing // For debug printing
@ -457,6 +464,9 @@ private:
std::set<v3s16> m_chunks_in_progress; std::set<v3s16> m_chunks_in_progress;
// used by deleteBlock() and deleteDetachedBlocks()
MapBlockVect m_detached_blocks;
// Queued transforming water nodes // Queued transforming water nodes
UniqueQueue<v3s16> m_transforming_liquid; UniqueQueue<v3s16> m_transforming_liquid;
f32 m_transforming_liquid_loop_count_multiplier = 1.0f; f32 m_transforming_liquid_loop_count_multiplier = 1.0f;

@ -81,11 +81,24 @@ public:
return NODECONTAINER_ID_MAPBLOCK; return NODECONTAINER_ID_MAPBLOCK;
}*/ }*/
Map * getParent() Map *getParent()
{ {
return m_parent; return m_parent;
} }
// Any server-modding code can "delete" arbitrary blocks (i.e. with
// core.delete_area), which makes them orphan. Avoid using orphan blocks for
// anything.
bool isOrphan() const
{
return !m_parent;
}
void makeOrphan()
{
m_parent = nullptr;
}
void reallocate() void reallocate()
{ {
for (u32 i = 0; i < nodecount; i++) for (u32 i = 0; i < nodecount; i++)

@ -109,6 +109,12 @@ void MapSector::insertBlock(MapBlock *block)
} }
void MapSector::deleteBlock(MapBlock *block) void MapSector::deleteBlock(MapBlock *block)
{
detachBlock(block);
delete block;
}
void MapSector::detachBlock(MapBlock *block)
{ {
s16 block_y = block->getPos().Y; s16 block_y = block->getPos().Y;
@ -118,8 +124,8 @@ void MapSector::deleteBlock(MapBlock *block)
// Remove from container // Remove from container
m_blocks.erase(block_y); m_blocks.erase(block_y);
// Delete // Mark as removed
delete block; block->makeOrphan();
} }
void MapSector::getBlocks(MapBlockVect &dest) void MapSector::getBlocks(MapBlockVect &dest)

@ -58,6 +58,9 @@ public:
void deleteBlock(MapBlock *block); void deleteBlock(MapBlock *block);
// Remove a block from the map and the sector without deleting it
void detachBlock(MapBlock *block);
void getBlocks(MapBlockVect &dest); void getBlocks(MapBlockVect &dest);
bool empty() const { return m_blocks.empty(); } bool empty() const { return m_blocks.empty(); }

@ -666,6 +666,11 @@ void Server::AsyncRunStep(bool initial_step)
-1); -1);
} }
/*
Note: Orphan MapBlock ptrs become dangling after this call.
*/
m_env->getServerMap().step();
/* /*
Listen to the admin chat, if available Listen to the admin chat, if available
*/ */

@ -282,6 +282,8 @@ void LBMManager::applyLBMs(ServerEnvironment *env, MapBlock *block,
continue; continue;
for (auto lbmdef : *lbm_list) { for (auto lbmdef : *lbm_list) {
lbmdef->trigger(env, pos + pos_of_block, n, dtime_s); lbmdef->trigger(env, pos + pos_of_block, n, dtime_s);
if (block->isOrphan())
return;
n = block->getNodeNoCheck(pos); n = block->getNodeNoCheck(pos);
if (n.getContent() != c) if (n.getContent() != c)
break; // The node was changed and the LBMs no longer apply break; // The node was changed and the LBMs no longer apply
@ -966,6 +968,9 @@ public:
aabm.abm->trigger(m_env, p, n, aabm.abm->trigger(m_env, p, n,
active_object_count, active_object_count_wider); active_object_count, active_object_count_wider);
if (block->isOrphan())
return;
// Count surrounding objects again if the abms added any // Count surrounding objects again if the abms added any
if(m_env->m_added_objects > 0) { if(m_env->m_added_objects > 0) {
active_object_count = countObjects(block, map, active_object_count_wider); active_object_count = countObjects(block, map, active_object_count_wider);
@ -1016,13 +1021,17 @@ void ServerEnvironment::activateBlock(MapBlock *block, u32 additional_dtime)
// Activate stored objects // Activate stored objects
activateObjects(block, dtime_s); activateObjects(block, dtime_s);
if (block->isOrphan())
return;
/* Handle LoadingBlockModifiers */ /* Handle LoadingBlockModifiers */
m_lbm_mgr.applyLBMs(this, block, stamp, (float)dtime_s); m_lbm_mgr.applyLBMs(this, block, stamp, (float)dtime_s);
if (block->isOrphan())
return;
// Run node timers // Run node timers
block->step((float)dtime_s, [&](v3s16 p, MapNode n, f32 d) -> bool { block->step((float)dtime_s, [&](v3s16 p, MapNode n, f32 d) -> bool {
return m_script->node_on_timer(p, n, d); return !block->isOrphan() && m_script->node_on_timer(p, n, d);
}); });
} }
@ -1996,6 +2005,8 @@ void ServerEnvironment::activateObjects(MapBlock *block, u32 dtime_s)
<< " type=" << (int)s_obj.type << std::endl; << " type=" << (int)s_obj.type << std::endl;
// This will also add the object to the active static list // This will also add the object to the active static list
addActiveObjectRaw(obj, false, dtime_s); addActiveObjectRaw(obj, false, dtime_s);
if (block->isOrphan())
return;
} }
// Clear stored list // Clear stored list