When running and compiling a simple equation more than once using ExprTK, I encounter a segmentation fault or address boundary error. Surprisingly, the issue disappears when I exclude the exprtk::collect_variables() function, which doesn't make any sense since the function is just supposed to provide me a list with every variable in the equation.
#include "exprtk.h"
#include <iostream>
typedef exprtk::symbol_table<float> symbol_table_t;
typedef exprtk::expression<float> expression_t;
typedef exprtk::parser<float> parser_t;
parser_t parser;
expression_t expression;
symbol_table_t symbol_table;
float a = 5.0f;
std::string equation;
void f()
{
symbol_table.clear();
std::vector<std::string> varList;
exprtk::collect_variables(equation, varList); // DELETE THIS LINE FOR THE SEGFAULT TO GO AWAY
symbol_table.add_variable("a", a);
parser.compile(equation, expression);
std::cout << "value is " << expression.value() << std::endl;
}
int main()
{
equation.reserve(16);
equation = "a";
expression.register_symbol_table(symbol_table);
std::cout << "First call" << std::endl;
f();
std::cout << "Second call" << std::endl;
f();
return 0;
}
I really need the "collect_variables" function and I would appreciate if someone could tell me what is happening and how to I fix it.
Thanks in advance.
I tried to exclude the "symbol_table.clear()" call and the code works too, but it brings other issues.
Initially, from the ExprTk readme, in multiple places, we have the following statement:
On the second call to
f(), on the first line thesymbol_tableis cleared, which means the references to the variables etc that have been embedded in the expression are now pointing to invalid memory, any accesses to those node will cause UB.When the compile method is called in the second call to
f()the expression instance's destructor is called, at which point it attempts to see if any nodes it is holding on to need to be destroyed, whilst doing this it accesses the nodes it got from the symbol table during the previous compilation call and that's why you are seeing the crash.Including or excluding the call to
collect_variableshas got nothing to do with the issue.Running your code using UBSAN and ASAN, the resulting diagnostics will correctly point to the issue you are observing.
In order to resolve the crash, all you need to do is call release on the expression instance before calling clear on the
symbol_table. As follows: