WFL: Fix stack overflow when attempting to call a non-existent function

This commit is contained in:
Celtic Minstrel 2017-06-20 00:20:56 -04:00
parent 1bb750f649
commit 3f3a176f57
4 changed files with 18 additions and 19 deletions

View file

@ -35,6 +35,7 @@ Version 1.13.8+dev:
* WFL Engine
* Add owner key to terrain space callable, for villages
* Location formulas in [tunnel] now have a teleport_unit variable
* Fix a crash when attempting to call a non-existent function
* WML Engine
* If ai_algorithm is used in [modify_side][ai], it now replaces the whole AI
with the contents of [modify_side][ai], instead of appending these parameters.

View file

@ -1596,7 +1596,7 @@ public:
#define FUNCTION(name) add_function(#name, formula_function_ptr( \
new builtin_formula_function<name##_function>(#name)))
ai_function_symbol_table::ai_function_symbol_table(ai::formula_ai& ai) : function_symbol_table(new action_function_symbol_table) {
ai_function_symbol_table::ai_function_symbol_table(ai::formula_ai& ai) : function_symbol_table(std::make_shared<action_function_symbol_table>()) {
FUNCTION(outcomes);
//AI_FUNCTION(evaluate_for_position);
FUNCTION(move);

View file

@ -1570,11 +1570,7 @@ function_expression_ptr user_formula_function::generate_function_expression(cons
return function_expression_ptr(new formula_function_expression(name_, args, formula_, precondition_, args_));
}
function_symbol_table::function_symbol_table(function_symbol_table* parent) : parent(parent) {}
function_symbol_table::~function_symbol_table() {
if(parent) delete parent;
}
function_symbol_table::function_symbol_table(std::shared_ptr<function_symbol_table> parent) : parent(parent ? parent : get_builtins()) {}
void function_symbol_table::add_function(const std::string& name, formula_function_ptr fcn)
{
@ -1588,9 +1584,11 @@ expression_ptr function_symbol_table::create_function(const std::string& fn, con
return i->second->generate_function_expression(args);
}
expression_ptr res((parent ? parent : get_builtins())->create_function(fn, args));
if(res) {
return res;
if(parent) {
expression_ptr res(parent->create_function(fn, args));
if(res) {
return res;
}
}
throw formula_error("Unknown function: " + fn, "", "", 0);
@ -1601,8 +1599,6 @@ std::set<std::string> function_symbol_table::get_function_names() const
std::set<std::string> res;
if(parent) {
res = parent->get_function_names();
} else if(this != get_builtins()) {
res = get_builtins()->get_function_names();
}
for(functions_map::const_iterator iter = custom_formulas_.begin(); iter != custom_formulas_.end(); ++iter ) {
res.insert((*iter).first);
@ -1613,10 +1609,11 @@ std::set<std::string> function_symbol_table::get_function_names() const
#define FUNCTION(name) functions_table.add_function(#name, \
formula_function_ptr(new builtin_formula_function<name##_function>(#name)))
function_symbol_table* function_symbol_table::get_builtins() {
static function_symbol_table functions_table;
std::shared_ptr<function_symbol_table> function_symbol_table::get_builtins() {
static function_symbol_table functions_table(builtins_tag);
if(functions_table.empty()) {
functions_table.parent = nullptr;
using namespace builtins;
FUNCTION(debug);
FUNCTION(dir);
@ -1680,7 +1677,7 @@ function_symbol_table* function_symbol_table::get_builtins() {
FUNCTION(type);
}
return &functions_table;
return std::shared_ptr<function_symbol_table>(&functions_table, [](function_symbol_table*){});
}
action_function_symbol_table::action_function_symbol_table() {

View file

@ -139,16 +139,17 @@ typedef std::shared_ptr<formula_function> formula_function_ptr;
typedef std::map<std::string, formula_function_ptr> functions_map;
class function_symbol_table {
function_symbol_table* parent = nullptr;
std::shared_ptr<function_symbol_table> parent;
functions_map custom_formulas_;
enum builtins_tag_t {builtins_tag};
function_symbol_table(builtins_tag_t) {}
public:
explicit function_symbol_table(function_symbol_table* parent = nullptr);
~function_symbol_table();
explicit function_symbol_table(std::shared_ptr<function_symbol_table> parent = nullptr);
void add_function(const std::string& name, formula_function_ptr fcn);
expression_ptr create_function(const std::string& fn, const std::vector<expression_ptr>& args) const;
std::set<std::string> get_function_names() const;
bool empty() {return custom_formulas_.empty();}
static function_symbol_table* get_builtins();
bool empty() {return custom_formulas_.empty() && (parent == nullptr || parent->empty());}
static std::shared_ptr<function_symbol_table> get_builtins();
};
class action_function_symbol_table : public function_symbol_table {