Prevent VoxelManipulator size overflow

This commit is contained in:
sfan5 2025-01-08 19:30:48 +01:00
parent 2cdf3af1b8
commit 9dd09d1056
4 changed files with 33 additions and 31 deletions

View file

@ -5044,7 +5044,7 @@ inside the VoxelManip.
can use `core.emerge_area` to make sure that the area you want to
read/write is already generated.
* Other mods, or the core itself, could possibly modify the area of the map
* Other mods, or the engine itself, could possibly modify the area of the map
currently loaded into a VoxelManip object. With the exception of Mapgen
VoxelManips (see above section), the internal buffers are not updated. For
this reason, it is strongly encouraged to complete the usage of a particular
@ -5059,9 +5059,11 @@ inside the VoxelManip.
Methods
-------
* `read_from_map(p1, p2)`: Loads a chunk of map into the VoxelManip object
* `read_from_map(p1, p2)`: Loads a chunk of map into the VoxelManip object
containing the region formed by `p1` and `p2`.
* returns actual emerged `pmin`, actual emerged `pmax`
* Note that calling this multiple times will *add* to the area loaded in the
VoxelManip, and not reset it.
* `write_to_map([light])`: Writes the data loaded from the `VoxelManip` back to
the map.
* **important**: data must be set using `VoxelManip:set_data()` before
@ -5120,8 +5122,8 @@ Methods
generated mapchunk above are propagated down into the mapchunk, defaults
to `true` if left out.
* `update_liquids()`: Update liquid flow
* `was_modified()`: Returns `true` if the data in the voxel manipulator has been modified
since it was last read from the map. This means you have to call `get_data` again.
* `was_modified()`: Returns `true` if the data in the VoxelManip has been modified
since it was last read from the map. This means you have to call `get_data()` again.
This only applies to a `VoxelManip` object from `core.get_mapgen_object`,
where the engine will keep the map and the VM in sync automatically.
* Note: this doesn't do what you think it does and is subject to removal. Don't use it!

View file

@ -752,17 +752,12 @@ MMVManip::MMVManip(Map *map):
assert(map);
}
void MMVManip::initialEmerge(v3s16 blockpos_min, v3s16 blockpos_max,
bool load_if_inexistent)
void MMVManip::initialEmerge(v3s16 p_min, v3s16 p_max, bool load_if_inexistent)
{
TimeTaker timer1("initialEmerge", &emerge_time);
assert(m_map);
// Units of these are MapBlocks
v3s16 p_min = blockpos_min;
v3s16 p_max = blockpos_max;
VoxelArea block_area_nodes
(p_min*MAP_BLOCKSIZE, (p_max+1)*MAP_BLOCKSIZE-v3s16(1,1,1));
@ -775,6 +770,7 @@ void MMVManip::initialEmerge(v3s16 blockpos_min, v3s16 blockpos_max,
infostream<<std::endl;
}
const bool all_new = m_area.hasEmptyExtent() || block_area_nodes.contains(m_area);
addArea(block_area_nodes);
for(s32 z=p_min.Z; z<=p_max.Z; z++)
@ -812,16 +808,12 @@ void MMVManip::initialEmerge(v3s16 blockpos_min, v3s16 blockpos_max,
setFlags(a, VOXELFLAG_NO_DATA);
}
}
/*else if (block->getNode(0, 0, 0).getContent() == CONTENT_IGNORE)
{
// Mark that block was loaded as blank
flags |= VMANIP_BLOCK_CONTAINS_CIGNORE;
}*/
m_loaded_blocks[p] = flags;
}
m_is_dirty = false;
if (all_new)
m_is_dirty = false;
}
void MMVManip::blitBackAll(std::map<v3s16, MapBlock*> *modified_blocks,
@ -834,6 +826,7 @@ void MMVManip::blitBackAll(std::map<v3s16, MapBlock*> *modified_blocks,
/*
Copy data of all blocks
*/
assert(!m_loaded_blocks.empty());
for (auto &loaded_block : m_loaded_blocks) {
v3s16 p = loaded_block.first;
MapBlock *block = m_map->getBlockNoCreateNoEx(p);

View file

@ -298,9 +298,6 @@ protected:
u32 needed_count);
};
#define VMANIP_BLOCK_DATA_INEXIST 1
#define VMANIP_BLOCK_CONTAINS_CIGNORE 2
class MMVManip : public VoxelManipulator
{
public:
@ -344,4 +341,8 @@ protected:
value = flags describing the block
*/
std::map<v3s16, u8> m_loaded_blocks;
enum : u8 {
VMANIP_BLOCK_DATA_INEXIST = 1 << 0,
};
};

View file

@ -113,6 +113,20 @@ void VoxelManipulator::print(std::ostream &o, const NodeDefManager *ndef,
}
}
static inline void checkArea(const VoxelArea &a)
{
// won't overflow since cbrt(2^64) > 2^16
u64 real_volume = static_cast<u64>(a.getExtent().X) * a.getExtent().Y * a.getExtent().Z;
// Volume limit equal to 8 default mapchunks, (80 * 2) ^ 3 = 4,096,000
// Note: the hard limit is somewhere around 2^31 due to s32 type
constexpr u64 MAX_ALLOWED = 4096000;
if (real_volume > MAX_ALLOWED) {
throw BaseException("VoxelManipulator: "
"Area volume exceeds allowed value of " + std::to_string(MAX_ALLOWED));
}
}
void VoxelManipulator::addArea(const VoxelArea &area)
{
// Cancel if requested area has zero volume
@ -124,18 +138,10 @@ void VoxelManipulator::addArea(const VoxelArea &area)
return;
// Calculate new area
VoxelArea new_area;
// New area is the requested area if m_area has zero volume
if(m_area.hasEmptyExtent())
{
new_area = area;
}
// Else add requested area to m_area
else
{
new_area = m_area;
new_area.addArea(area);
}
VoxelArea new_area = m_area;
new_area.addArea(area);
checkArea(new_area);
u32 new_size = new_area.getVolume();