Skip to content

Commit 87ab97d

Browse files
authoredNov 26, 2021
Fix find_nodes_in_area misbehaving with out-of-map coordinates (#11770)
This ensures that no overflows (side-effects) happen within the find_nodes_in_area function by limiting coordinates like done in the map generation code.
1 parent b905138 commit 87ab97d

File tree

2 files changed

+33
-16
lines changed

2 files changed

+33
-16
lines changed
 

‎src/script/lua_api/l_env.cpp

+17-14
Original file line numberDiff line numberDiff line change
@@ -880,6 +880,21 @@ int ModApiEnvMod::l_find_node_near(lua_State *L)
880880
return 0;
881881
}
882882

883+
static void checkArea(v3s16 &minp, v3s16 &maxp)
884+
{
885+
auto volume = VoxelArea(minp, maxp).getVolume();
886+
// Volume limit equal to 8 default mapchunks, (80 * 2) ^ 3 = 4,096,000
887+
if (volume > 4096000) {
888+
throw LuaError("Area volume exceeds allowed value of 4096000");
889+
}
890+
891+
// Clamp to map range to avoid problems
892+
#define CLAMP(arg) core::clamp(arg, (s16)-MAX_MAP_GENERATION_LIMIT, (s16)MAX_MAP_GENERATION_LIMIT)
893+
minp = v3s16(CLAMP(minp.X), CLAMP(minp.Y), CLAMP(minp.Z));
894+
maxp = v3s16(CLAMP(maxp.X), CLAMP(maxp.Y), CLAMP(maxp.Z));
895+
#undef CLAMP
896+
}
897+
883898
// find_nodes_in_area(minp, maxp, nodenames, [grouped])
884899
int ModApiEnvMod::l_find_nodes_in_area(lua_State *L)
885900
{
@@ -899,13 +914,7 @@ int ModApiEnvMod::l_find_nodes_in_area(lua_State *L)
899914
}
900915
#endif
901916

902-
v3s16 cube = maxp - minp + 1;
903-
// Volume limit equal to 8 default mapchunks, (80 * 2) ^ 3 = 4,096,000
904-
if ((u64)cube.X * (u64)cube.Y * (u64)cube.Z > 4096000) {
905-
luaL_error(L, "find_nodes_in_area(): area volume"
906-
" exceeds allowed value of 4096000");
907-
return 0;
908-
}
917+
checkArea(minp, maxp);
909918

910919
std::vector<content_t> filter;
911920
collectNodeIds(L, 3, ndef, filter);
@@ -1010,13 +1019,7 @@ int ModApiEnvMod::l_find_nodes_in_area_under_air(lua_State *L)
10101019
}
10111020
#endif
10121021

1013-
v3s16 cube = maxp - minp + 1;
1014-
// Volume limit equal to 8 default mapchunks, (80 * 2) ^ 3 = 4,096,000
1015-
if ((u64)cube.X * (u64)cube.Y * (u64)cube.Z > 4096000) {
1016-
luaL_error(L, "find_nodes_in_area_under_air(): area volume"
1017-
" exceeds allowed value of 4096000");
1018-
return 0;
1019-
}
1022+
checkArea(minp, maxp);
10201023

10211024
std::vector<content_t> filter;
10221025
collectNodeIds(L, 3, ndef, filter);

‎src/unittest/test_voxelarea.cpp

+16-2
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ class TestVoxelArea : public TestBase
3030

3131
void test_addarea();
3232
void test_pad();
33+
void test_extent();
3334
void test_volume();
3435
void test_contains_voxelarea();
3536
void test_contains_point();
@@ -65,6 +66,7 @@ void TestVoxelArea::runTests(IGameDef *gamedef)
6566
{
6667
TEST(test_addarea);
6768
TEST(test_pad);
69+
TEST(test_extent);
6870
TEST(test_volume);
6971
TEST(test_contains_voxelarea);
7072
TEST(test_contains_point);
@@ -113,10 +115,22 @@ void TestVoxelArea::test_pad()
113115
UASSERT(v1.MaxEdge == v3s16(-47, -9347, 969));
114116
}
115117

118+
void TestVoxelArea::test_extent()
119+
{
120+
VoxelArea v1(v3s16(-1337, -547, -789), v3s16(-147, 447, 669));
121+
UASSERT(v1.getExtent() == v3s16(1191, 995, 1459));
122+
123+
VoxelArea v2(v3s16(32493, -32507, 32753), v3s16(32508, -32492, 32768));
124+
UASSERT(v2.getExtent() == v3s16(16, 16, 16));
125+
}
126+
116127
void TestVoxelArea::test_volume()
117128
{
118-
VoxelArea v1(v3s16(-1337, 447, -789), v3s16(-147, -9547, 669));
119-
UASSERTEQ(s32, v1.getVolume(), -184657133);
129+
VoxelArea v1(v3s16(-1337, -547, -789), v3s16(-147, 447, 669));
130+
UASSERTEQ(s32, v1.getVolume(), 1728980655);
131+
132+
VoxelArea v2(v3s16(32493, -32507, 32753), v3s16(32508, -32492, 32768));
133+
UASSERTEQ(s32, v2.getVolume(), 4096);
120134
}
121135

122136
void TestVoxelArea::test_contains_voxelarea()

0 commit comments

Comments
 (0)