Skip to content

Commit

Permalink
Fix seg fault if popping from empty stack (L-system trees)
Browse files Browse the repository at this point in the history
See: #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: #1469

Fix l-system crash when treedef random_level not set by Lua
  • Loading branch information
Zeno- authored and RealBadAngel committed Aug 23, 2014
1 parent 996ea60 commit f33d316
Show file tree
Hide file tree
Showing 4 changed files with 45 additions and 10 deletions.
2 changes: 1 addition & 1 deletion doc/lua_api.txt
Expand Up @@ -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
Expand Down
16 changes: 13 additions & 3 deletions src/script/lua_api/l_env.cpp
Expand Up @@ -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;
Expand All @@ -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;
}

Expand Down
27 changes: 23 additions & 4 deletions src/treegen.cpp
Expand Up @@ -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<v3s16, MapBlock*> 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
Expand All @@ -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;
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -393,6 +410,8 @@ void make_ltree(ManualMapVoxelManipulator &vmanip, v3s16 p0, INodeDefManager *nd
break;
}
}

return SUCCESS;
}

void tree_node_placement(ManualMapVoxelManipulator &vmanip, v3f p0,
Expand Down
10 changes: 8 additions & 2 deletions src/treegen.h
Expand Up @@ -30,6 +30,11 @@ class ServerEnvironment;

namespace treegen {

enum error {
SUCCESS,
UNBALANCED_BRACKETS
};

struct TreeDef {
std::string initial_axiom;
std::string rules_a;
Expand All @@ -50,6 +55,7 @@ namespace treegen {
MapNode fruitnode;
int fruit_chance;
int seed;
bool explicit_seed;
};

// Add default tree
Expand All @@ -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
Expand Down

0 comments on commit f33d316

Please sign in to comment.