diff options
author | MetaDucky <metaducky AT gmail DOT com> | 2013-11-20 22:11:57 +0100 |
---|---|---|
committer | kwolekr <kwolekr@minetest.net> | 2013-11-29 23:35:16 -0500 |
commit | 5be786c804d36e9950598a01cf39f05574af2acc (patch) | |
tree | 488f9fd610b5785389c15d0faa02f840ba9e7110 | |
parent | 747bc40840ff13bcf9c7a60b790a6de24f94f946 (diff) | |
download | minetest-5be786c804d36e9950598a01cf39f05574af2acc.tar.gz minetest-5be786c804d36e9950598a01cf39f05574af2acc.tar.bz2 minetest-5be786c804d36e9950598a01cf39f05574af2acc.zip |
Fixed potential NULL pointer and leak when setting node metadata
-rw-r--r-- | src/map.cpp | 19 | ||||
-rw-r--r-- | src/map.h | 17 | ||||
-rw-r--r-- | src/rollback_interface.cpp | 8 | ||||
-rw-r--r-- | src/script/lua_api/l_nodemeta.cpp | 18 | ||||
-rw-r--r-- | src/script/lua_api/l_nodemeta.h | 13 |
5 files changed, 56 insertions, 19 deletions
diff --git a/src/map.cpp b/src/map.cpp index 0dbfd42f4..0f9c82c3c 100644 --- a/src/map.cpp +++ b/src/map.cpp @@ -2279,7 +2279,7 @@ void Map::transformLiquids(std::map<v3s16, MapBlock*> & modified_blocks) updateLighting(lighting_modified_blocks, modified_blocks); } -NodeMetadata* Map::getNodeMetadata(v3s16 p) +NodeMetadata *Map::getNodeMetadata(v3s16 p) { v3s16 blockpos = getNodeBlockPos(p); v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE; @@ -2289,8 +2289,7 @@ NodeMetadata* Map::getNodeMetadata(v3s16 p) <<PP(blockpos)<<std::endl; block = emergeBlock(blockpos, false); } - if(!block) - { + if(!block){ infostream<<"WARNING: Map::getNodeMetadata(): Block not found" <<std::endl; return NULL; @@ -2299,7 +2298,7 @@ NodeMetadata* Map::getNodeMetadata(v3s16 p) return meta; } -void Map::setNodeMetadata(v3s16 p, NodeMetadata *meta) +bool Map::setNodeMetadata(v3s16 p, NodeMetadata *meta) { v3s16 blockpos = getNodeBlockPos(p); v3s16 p_rel = p - blockpos*MAP_BLOCKSIZE; @@ -2309,13 +2308,13 @@ void Map::setNodeMetadata(v3s16 p, NodeMetadata *meta) <<PP(blockpos)<<std::endl; block = emergeBlock(blockpos, false); } - if(!block) - { + if(!block){ infostream<<"WARNING: Map::setNodeMetadata(): Block not found" <<std::endl; - return; + return false; } block->m_node_metadata.set(p_rel, meta); + return true; } void Map::removeNodeMetadata(v3s16 p) @@ -2342,8 +2341,7 @@ NodeTimer Map::getNodeTimer(v3s16 p) <<PP(blockpos)<<std::endl; block = emergeBlock(blockpos, false); } - if(!block) - { + if(!block){ infostream<<"WARNING: Map::getNodeTimer(): Block not found" <<std::endl; return NodeTimer(); @@ -2362,8 +2360,7 @@ void Map::setNodeTimer(v3s16 p, NodeTimer t) <<PP(blockpos)<<std::endl; block = emergeBlock(blockpos, false); } - if(!block) - { + if(!block){ infostream<<"WARNING: Map::setNodeTimer(): Block not found" <<std::endl; return; @@ -307,7 +307,22 @@ public: */ NodeMetadata* getNodeMetadata(v3s16 p); - void setNodeMetadata(v3s16 p, NodeMetadata *meta); + + /** + * Sets metadata for a node. + * This method sets the metadata for a given node. + * On success, it returns @c true and the object pointed to + * by @p meta is then managed by the system and should + * not be deleted by the caller. + * + * In case of failure, the method returns @c false and the + * caller is still responsible for deleting the object! + * + * @param p node coordinates + * @param meta pointer to @c NodeMetadata object + * @return @c true on success, false on failure + */ + bool setNodeMetadata(v3s16 p, NodeMetadata *meta); void removeNodeMetadata(v3s16 p); /* diff --git a/src/rollback_interface.cpp b/src/rollback_interface.cpp index 70a9e9457..808b07fed 100644 --- a/src/rollback_interface.cpp +++ b/src/rollback_interface.cpp @@ -340,7 +340,13 @@ bool RollbackAction::applyRevert(Map *map, InventoryManager *imgr, IGameDef *gam if(n_old.meta != ""){ if(!meta){ meta = new NodeMetadata(gamedef); - map->setNodeMetadata(p, meta); + if(!map->setNodeMetadata(p, meta)){ + delete meta; + infostream<<"RollbackAction::applyRevert(): " + <<"setNodeMetadata failed at " + <<PP(p)<<" for "<<n_old.name<<std::endl; + return false; + } } std::istringstream is(n_old.meta, std::ios::binary); meta->deSerialize(is); diff --git a/src/script/lua_api/l_nodemeta.cpp b/src/script/lua_api/l_nodemeta.cpp index f9c8794d5..4f20e56f9 100644 --- a/src/script/lua_api/l_nodemeta.cpp +++ b/src/script/lua_api/l_nodemeta.cpp @@ -42,10 +42,12 @@ NodeMetaRef* NodeMetaRef::checkobject(lua_State *L, int narg) NodeMetadata* NodeMetaRef::getmeta(NodeMetaRef *ref, bool auto_create) { NodeMetadata *meta = ref->m_env->getMap().getNodeMetadata(ref->m_p); - if(meta == NULL && auto_create) - { + if(meta == NULL && auto_create) { meta = new NodeMetadata(ref->m_env->getGameDef()); - ref->m_env->getMap().setNodeMetadata(ref->m_p, meta); + if(!ref->m_env->getMap().setNodeMetadata(ref->m_p, meta)) { + delete meta; + return NULL; + } } return meta; } @@ -227,17 +229,21 @@ int NodeMetaRef::l_from_table(lua_State *L) NodeMetaRef *ref = checkobject(L, 1); int base = 2; + // clear old metadata first + ref->m_env->getMap().removeNodeMetadata(ref->m_p); + if(lua_isnil(L, base)){ // No metadata - ref->m_env->getMap().removeNodeMetadata(ref->m_p); lua_pushboolean(L, true); return 1; } - // Has metadata; clear old one first - ref->m_env->getMap().removeNodeMetadata(ref->m_p); // Create new metadata NodeMetadata *meta = getmeta(ref, true); + if(meta == NULL){ + lua_pushboolean(L, false); + return 1; + } // Set fields lua_getfield(L, base, "fields"); int fieldstable = lua_gettop(L); diff --git a/src/script/lua_api/l_nodemeta.h b/src/script/lua_api/l_nodemeta.h index ed06ff0fa..e39ac3931 100644 --- a/src/script/lua_api/l_nodemeta.h +++ b/src/script/lua_api/l_nodemeta.h @@ -39,6 +39,19 @@ private: static NodeMetaRef *checkobject(lua_State *L, int narg); + /** + * Retrieve metadata for a node. + * If @p auto_create is set and the specified node has no metadata information + * associated with it yet, the method attempts to attach a new metadata object + * to the node and returns a pointer to the metadata when successful. + * + * However, it is NOT guaranteed that the method will return a pointer, + * and @c NULL may be returned in case of an error regardless of @p auto_create. + * + * @param ref specifies the node for which the associated metadata is retrieved. + * @param auto_create when true, try to create metadata information for the node if it has none. + * @return pointer to a @c NodeMetadata object or @c NULL in case of error. + */ static NodeMetadata* getmeta(NodeMetaRef *ref, bool auto_create); static void reportMetadataChange(NodeMetaRef *ref); |