From f33d31693ed2ab7d2a29320181b6aba2c12f76d3 Mon Sep 17 00:00:00 2001 From: Craig Robbins Date: Thu, 7 Aug 2014 15:39:12 +1000 Subject: [PATCH] Fix seg fault if popping from empty stack (L-system trees) See: https://github.com/minetest/minetest/issues/1525 Background Wuzzy2: If you attempt to spawn a L-system tree with minetest.spawn_tree, you can make Minetest crash if it is attempted to pop an empty stack. ShadowNinja: This shouldn't cause a segmentation fault, but it should throw a Lua error Commit Description This commit throws a Lua error instead of causing a segmentation fault. The server will still "crash" but will include a Lua backtrace. L-Systems fix randomness Unless a random seed is provided (via Lua treedef) seed the PRNG with a different seed for each tree Resolves: https://github.com/minetest/minetest/issues/1469 Fix l-system crash when treedef random_level not set by Lua --- doc/lua_api.txt | 2 +- src/script/lua_api/l_env.cpp | 16 +++++++++++++--- src/treegen.cpp | 27 +++++++++++++++++++++++---- src/treegen.h | 10 ++++++++-- 4 files changed, 45 insertions(+), 10 deletions(-) diff --git a/doc/lua_api.txt b/doc/lua_api.txt index 74487edee..5412c4ccb 100644 --- a/doc/lua_api.txt +++ b/doc/lua_api.txt @@ -2208,7 +2208,7 @@ treedef={ thin_branches, - boolean true -> use thin (1 node) branches fruit, - string fruit node name fruit_chance, - num chance (0-100) to replace leaves with fruit node - seed, - num random seed + seed, - num random seed; if no seed is provided, the engine will create one } Key for Special L-System Symbols used in Axioms diff --git a/src/script/lua_api/l_env.cpp b/src/script/lua_api/l_env.cpp index e6ca846d8..deeb5966f 100644 --- a/src/script/lua_api/l_env.cpp +++ b/src/script/lua_api/l_env.cpp @@ -747,7 +747,8 @@ int ModApiEnvMod::l_spawn_tree(lua_State *L) } getintfield(L, 2, "angle", tree_def.angle); getintfield(L, 2, "iterations", tree_def.iterations); - getintfield(L, 2, "random_level", tree_def.iterations_random_level); + if (!getintfield(L, 2, "random_level", tree_def.iterations_random_level)) + tree_def.iterations_random_level = 0; getstringfield(L, 2, "trunk_type", tree_def.trunk_type); getboolfield(L, 2, "thin_branches", tree_def.thin_branches); tree_def.fruit_chance=0; @@ -757,11 +758,20 @@ int ModApiEnvMod::l_spawn_tree(lua_State *L) tree_def.fruitnode=ndef->getId(fruit); getintfield(L, 2, "fruit_chance",tree_def.fruit_chance); } - getintfield(L, 2, "seed", tree_def.seed); + tree_def.explicit_seed = getintfield(L, 2, "seed", tree_def.seed); } else return 0; - treegen::spawn_ltree (env, p0, ndef, tree_def); + + treegen::error e; + if ((e = treegen::spawn_ltree (env, p0, ndef, tree_def)) != treegen::SUCCESS) { + if (e == treegen::UNBALANCED_BRACKETS) { + luaL_error(L, "spawn_tree(): closing ']' has no matching opening bracket"); + } else { + luaL_error(L, "spawn_tree(): unknown error"); + } + } + return 1; } diff --git a/src/treegen.cpp b/src/treegen.cpp index 542bdf21c..bd4a2f2c9 100644 --- a/src/treegen.cpp +++ b/src/treegen.cpp @@ -118,14 +118,19 @@ void make_tree(ManualMapVoxelManipulator &vmanip, v3s16 p0, } // L-System tree LUA spawner -void spawn_ltree(ServerEnvironment *env, v3s16 p0, INodeDefManager *ndef, TreeDef tree_definition) +treegen::error spawn_ltree(ServerEnvironment *env, v3s16 p0, INodeDefManager *ndef, TreeDef tree_definition) { ServerMap *map = &env->getServerMap(); std::map modified_blocks; ManualMapVoxelManipulator vmanip(map); v3s16 tree_blockp = getNodeBlockPos(p0); + treegen::error e; + vmanip.initialEmerge(tree_blockp - v3s16(1,1,1), tree_blockp + v3s16(1,3,1)); - make_ltree (vmanip, p0, ndef, tree_definition); + e = make_ltree (vmanip, p0, ndef, tree_definition); + if (e != SUCCESS) + return e; + vmanip.blitBackAll(&modified_blocks); // update lighting @@ -142,15 +147,25 @@ void spawn_ltree(ServerEnvironment *env, v3s16 p0, INodeDefManager *ndef, TreeDe event.modified_blocks.insert(i->first); } map->dispatchEvent(&event); + return SUCCESS; } //L-System tree generator -void make_ltree(ManualMapVoxelManipulator &vmanip, v3s16 p0, INodeDefManager *ndef, +treegen::error make_ltree(ManualMapVoxelManipulator &vmanip, v3s16 p0, INodeDefManager *ndef, TreeDef tree_definition) { MapNode dirtnode(ndef->getId("mapgen_dirt")); + int seed; + if (tree_definition.explicit_seed) + { + seed = tree_definition.seed+14002; + } + else + { + seed = p0.X*2 + p0.Y*4 + p0.Z; // use the tree position to seed PRNG + } + PseudoRandom ps(seed); - PseudoRandom ps(tree_definition.seed+14002); // chance of inserting abcd rules double prop_a = 9; double prop_b = 8; @@ -354,6 +369,8 @@ void make_ltree(ManualMapVoxelManipulator &vmanip, v3s16 p0, INodeDefManager *nd stack_position.push(position); break; case ']': + if (stack_orientation.empty()) + return UNBALANCED_BRACKETS; rotation=stack_orientation.top(); stack_orientation.pop(); position=stack_position.top(); @@ -393,6 +410,8 @@ void make_ltree(ManualMapVoxelManipulator &vmanip, v3s16 p0, INodeDefManager *nd break; } } + + return SUCCESS; } void tree_node_placement(ManualMapVoxelManipulator &vmanip, v3f p0, diff --git a/src/treegen.h b/src/treegen.h index 55da6f9e5..a557ad975 100644 --- a/src/treegen.h +++ b/src/treegen.h @@ -30,6 +30,11 @@ class ServerEnvironment; namespace treegen { + enum error { + SUCCESS, + UNBALANCED_BRACKETS + }; + struct TreeDef { std::string initial_axiom; std::string rules_a; @@ -50,6 +55,7 @@ namespace treegen { MapNode fruitnode; int fruit_chance; int seed; + bool explicit_seed; }; // Add default tree @@ -60,10 +66,10 @@ namespace treegen { INodeDefManager *ndef, int seed); // Add L-Systems tree (used by engine) - void make_ltree(ManualMapVoxelManipulator &vmanip, v3s16 p0, INodeDefManager *ndef, + treegen::error make_ltree(ManualMapVoxelManipulator &vmanip, v3s16 p0, INodeDefManager *ndef, TreeDef tree_definition); // Spawn L-systems tree from LUA - void spawn_ltree (ServerEnvironment *env, v3s16 p0, INodeDefManager *ndef, + treegen::error spawn_ltree (ServerEnvironment *env, v3s16 p0, INodeDefManager *ndef, TreeDef tree_definition); // L-System tree gen helper functions -- 2.25.1