]> git.lizzy.rs Git - dragonfireclient.git/commitdiff
Fix find_nodes_in_area misbehaving with out-of-map coordinates (#11770)
authorsfan5 <sfan5@live.de>
Fri, 26 Nov 2021 18:32:41 +0000 (19:32 +0100)
committerGitHub <noreply@github.com>
Fri, 26 Nov 2021 18:32:41 +0000 (19:32 +0100)
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.

src/script/lua_api/l_env.cpp
src/unittest/test_voxelarea.cpp

index 2c709d31b265215f5b474ef0cf31c387806859d6..18ee3a521a4d0455f9ec933320c252762d04970e 100644 (file)
@@ -880,6 +880,21 @@ int ModApiEnvMod::l_find_node_near(lua_State *L)
        return 0;
 }
 
+static void checkArea(v3s16 &minp, v3s16 &maxp)
+{
+       auto volume = VoxelArea(minp, maxp).getVolume();
+       // Volume limit equal to 8 default mapchunks, (80 * 2) ^ 3 = 4,096,000
+       if (volume > 4096000) {
+               throw LuaError("Area volume exceeds allowed value of 4096000");
+       }
+
+       // Clamp to map range to avoid problems
+#define CLAMP(arg) core::clamp(arg, (s16)-MAX_MAP_GENERATION_LIMIT, (s16)MAX_MAP_GENERATION_LIMIT)
+       minp = v3s16(CLAMP(minp.X), CLAMP(minp.Y), CLAMP(minp.Z));
+       maxp = v3s16(CLAMP(maxp.X), CLAMP(maxp.Y), CLAMP(maxp.Z));
+#undef CLAMP
+}
+
 // find_nodes_in_area(minp, maxp, nodenames, [grouped])
 int ModApiEnvMod::l_find_nodes_in_area(lua_State *L)
 {
@@ -899,13 +914,7 @@ int ModApiEnvMod::l_find_nodes_in_area(lua_State *L)
        }
 #endif
 
-       v3s16 cube = maxp - minp + 1;
-       // Volume limit equal to 8 default mapchunks, (80 * 2) ^ 3 = 4,096,000
-       if ((u64)cube.X * (u64)cube.Y * (u64)cube.Z > 4096000) {
-               luaL_error(L, "find_nodes_in_area(): area volume"
-                               " exceeds allowed value of 4096000");
-               return 0;
-       }
+       checkArea(minp, maxp);
 
        std::vector<content_t> filter;
        collectNodeIds(L, 3, ndef, filter);
@@ -1010,13 +1019,7 @@ int ModApiEnvMod::l_find_nodes_in_area_under_air(lua_State *L)
        }
 #endif
 
-       v3s16 cube = maxp - minp + 1;
-       // Volume limit equal to 8 default mapchunks, (80 * 2) ^ 3 = 4,096,000
-       if ((u64)cube.X * (u64)cube.Y * (u64)cube.Z > 4096000) {
-               luaL_error(L, "find_nodes_in_area_under_air(): area volume"
-                               " exceeds allowed value of 4096000");
-               return 0;
-       }
+       checkArea(minp, maxp);
 
        std::vector<content_t> filter;
        collectNodeIds(L, 3, ndef, filter);
index 6ec0412d57c6419c30db5cee33c605633c3c1c06..9826d2ee780eb880c4bd01898628ea6752bb9942 100644 (file)
@@ -30,6 +30,7 @@ class TestVoxelArea : public TestBase
 
        void test_addarea();
        void test_pad();
+       void test_extent();
        void test_volume();
        void test_contains_voxelarea();
        void test_contains_point();
@@ -65,6 +66,7 @@ void TestVoxelArea::runTests(IGameDef *gamedef)
 {
        TEST(test_addarea);
        TEST(test_pad);
+       TEST(test_extent);
        TEST(test_volume);
        TEST(test_contains_voxelarea);
        TEST(test_contains_point);
@@ -113,10 +115,22 @@ void TestVoxelArea::test_pad()
        UASSERT(v1.MaxEdge == v3s16(-47, -9347, 969));
 }
 
+void TestVoxelArea::test_extent()
+{
+       VoxelArea v1(v3s16(-1337, -547, -789), v3s16(-147, 447, 669));
+       UASSERT(v1.getExtent() == v3s16(1191, 995, 1459));
+
+       VoxelArea v2(v3s16(32493, -32507, 32753), v3s16(32508, -32492, 32768));
+       UASSERT(v2.getExtent() == v3s16(16, 16, 16));
+}
+
 void TestVoxelArea::test_volume()
 {
-       VoxelArea v1(v3s16(-1337, 447, -789), v3s16(-147, -9547, 669));
-       UASSERTEQ(s32, v1.getVolume(), -184657133);
+       VoxelArea v1(v3s16(-1337, -547, -789), v3s16(-147, 447, 669));
+       UASSERTEQ(s32, v1.getVolume(), 1728980655);
+
+       VoxelArea v2(v3s16(32493, -32507, 32753), v3s16(32508, -32492, 32768));
+       UASSERTEQ(s32, v2.getVolume(), 4096);
 }
 
 void TestVoxelArea::test_contains_voxelarea()