update(userspace/engine): broader err catching support in macro resolver

Signed-off-by: Jason Dellaluce <jasondellaluce@gmail.com>
This commit is contained in:
Jason Dellaluce
2022-12-06 13:56:01 +00:00
committed by poiana
parent 35dd0fc153
commit 25ddc3c6a2
3 changed files with 57 additions and 29 deletions

View File

@@ -24,8 +24,9 @@ bool filter_macro_resolver::run(libsinsp::filter::ast::expr*& filter)
{ {
m_unknown_macros.clear(); m_unknown_macros.clear();
m_resolved_macros.clear(); m_resolved_macros.clear();
m_errors.clear();
visitor v(m_unknown_macros, m_resolved_macros, m_macros); visitor v(m_errors, m_unknown_macros, m_resolved_macros, m_macros);
v.m_node_substitute = nullptr; v.m_node_substitute = nullptr;
filter->accept(&v); filter->accept(&v);
if (v.m_node_substitute) if (v.m_node_substitute)
@@ -40,8 +41,9 @@ bool filter_macro_resolver::run(std::shared_ptr<libsinsp::filter::ast::expr>& fi
{ {
m_unknown_macros.clear(); m_unknown_macros.clear();
m_resolved_macros.clear(); m_resolved_macros.clear();
m_errors.clear();
visitor v(m_unknown_macros, m_resolved_macros, m_macros); visitor v(m_errors, m_unknown_macros, m_resolved_macros, m_macros);
v.m_node_substitute = nullptr; v.m_node_substitute = nullptr;
filter->accept(&v); filter->accept(&v);
if (v.m_node_substitute) if (v.m_node_substitute)
@@ -58,12 +60,17 @@ void filter_macro_resolver::set_macro(
m_macros[name] = macro; m_macros[name] = macro;
} }
const filter_macro_resolver::macro_info_map& filter_macro_resolver::get_unknown_macros() const const std::vector<filter_macro_resolver::value_info>& filter_macro_resolver::get_unknown_macros() const
{ {
return m_unknown_macros; return m_unknown_macros;
} }
const filter_macro_resolver::macro_info_map& filter_macro_resolver::get_resolved_macros() const const std::vector<filter_macro_resolver::value_info>& filter_macro_resolver::get_errors() const
{
return m_errors;
}
const std::vector<filter_macro_resolver::value_info>& filter_macro_resolver::get_resolved_macros() const
{ {
return m_resolved_macros; return m_resolved_macros;
} }
@@ -133,8 +140,13 @@ void filter_macro_resolver::visitor::visit(ast::value_expr* e)
const auto& prevref = std::find(m_macros_path.begin(), m_macros_path.end(), macro->first); const auto& prevref = std::find(m_macros_path.begin(), m_macros_path.end(), macro->first);
if (prevref != m_macros_path.end()) if (prevref != m_macros_path.end())
{ {
throw falco_exception("detected reference loop in macro '" + macro->first + "'"); auto msg = "reference loop in macro '" + macro->first + "'";
m_errors.push_back({msg, e->get_pos()});
m_node_substitute = nullptr;
m_unknown_macros.push_back({e->value, e->get_pos()});
return;
} }
m_macros_path.push_back(macro->first); m_macros_path.push_back(macro->first);
m_node_substitute = nullptr; m_node_substitute = nullptr;
auto new_node = ast::clone(macro->second.get()); auto new_node = ast::clone(macro->second.get());
@@ -145,12 +157,12 @@ void filter_macro_resolver::visitor::visit(ast::value_expr* e)
{ {
m_node_substitute = std::move(new_node); m_node_substitute = std::move(new_node);
} }
m_resolved_macros[e->value] = e->get_pos(); m_resolved_macros.push_back({e->value, e->get_pos()});
m_macros_path.pop_back(); m_macros_path.pop_back();
} }
else else
{ {
m_node_substitute = nullptr; m_node_substitute = nullptr;
m_unknown_macros[e->value] = e->get_pos(); m_unknown_macros.push_back({e->value, e->get_pos()});
} }
} }

View File

@@ -59,16 +59,17 @@ class filter_macro_resolver
std::shared_ptr<libsinsp::filter::ast::expr> macro); std::shared_ptr<libsinsp::filter::ast::expr> macro);
/*! /*!
\brief used in get_{resolved,unknown}_macros \brief used in get_{resolved,unknown}_macros and get_errors
to represent an identifer/string value along with an AST position.
*/ */
typedef std::unordered_map<std::string,libsinsp::filter::ast::pos_info> macro_info_map; typedef std::pair<std::string,libsinsp::filter::ast::pos_info> value_info;
/*! /*!
\brief Returns a set containing the names of all the macros \brief Returns a set containing the names of all the macros
substituted during the last invocation of run(). Should be substituted during the last invocation of run(). Should be
non-empty if the last invocation of run() returned true. non-empty if the last invocation of run() returned true.
*/ */
const macro_info_map& get_resolved_macros() const; const std::vector<value_info>& get_resolved_macros() const;
/*! /*!
\brief Returns a set containing the names of all the macros \brief Returns a set containing the names of all the macros
@@ -76,7 +77,13 @@ class filter_macro_resolver
A macro remains unresolved if it is found inside the processed A macro remains unresolved if it is found inside the processed
filter but it was not defined with set_macro(); filter but it was not defined with set_macro();
*/ */
const macro_info_map& get_unknown_macros() const; const std::vector<value_info>& get_unknown_macros() const;
/*!
\brief Returns a list of errors occurred during
the latest invocation of run().
*/
const std::vector<value_info>& get_errors() const;
private: private:
typedef std::unordered_map< typedef std::unordered_map<
@@ -86,8 +93,15 @@ class filter_macro_resolver
struct visitor : public libsinsp::filter::ast::expr_visitor struct visitor : public libsinsp::filter::ast::expr_visitor
{ {
visitor(macro_info_map& unknown_macros, macro_info_map& resolved_macros, macro_defs& macros) visitor(
: m_unknown_macros(unknown_macros), m_resolved_macros(resolved_macros), m_macros(macros) {} std::vector<value_info>& errors,
std::vector<value_info>& unknown_macros,
std::vector<value_info>& resolved_macros,
macro_defs& macros):
m_errors(errors),
m_unknown_macros(unknown_macros),
m_resolved_macros(resolved_macros),
m_macros(macros) {}
visitor(visitor&&) = default; visitor(visitor&&) = default;
visitor& operator = (visitor&&) = default; visitor& operator = (visitor&&) = default;
visitor(const visitor&) = delete; visitor(const visitor&) = delete;
@@ -95,9 +109,9 @@ class filter_macro_resolver
std::vector<std::string> m_macros_path; std::vector<std::string> m_macros_path;
std::unique_ptr<libsinsp::filter::ast::expr> m_node_substitute; std::unique_ptr<libsinsp::filter::ast::expr> m_node_substitute;
macro_info_map& m_unknown_macros; std::vector<value_info>& m_errors;
macro_info_map& m_resolved_macros; std::vector<value_info>& m_unknown_macros;
std::vector<value_info>& m_resolved_macros;
macro_defs& m_macros; macro_defs& m_macros;
void visit(libsinsp::filter::ast::and_expr* e) override; void visit(libsinsp::filter::ast::and_expr* e) override;
@@ -109,7 +123,8 @@ class filter_macro_resolver
void visit(libsinsp::filter::ast::binary_check_expr* e) override; void visit(libsinsp::filter::ast::binary_check_expr* e) override;
}; };
macro_info_map m_unknown_macros; std::vector<value_info> m_errors;
macro_info_map m_resolved_macros; std::vector<value_info> m_unknown_macros;
std::vector<value_info> m_resolved_macros;
macro_defs m_macros; macro_defs m_macros;
}; };

View File

@@ -248,18 +248,19 @@ static void resolve_macros(
} }
macro_resolver.run(ast); macro_resolver.run(ast);
// Note: only complaining about the first unknown macro // Note: only complaining about the first error or unknown macro
const filter_macro_resolver::macro_info_map& unresolved_macros = macro_resolver.get_unknown_macros(); const auto& errors_macros = macro_resolver.get_errors();
if(!unresolved_macros.empty()) const auto& unresolved_macros = macro_resolver.get_unknown_macros();
if(!errors_macros.empty() || !unresolved_macros.empty())
{ {
auto it = unresolved_macros.begin(); auto errpos = !errors_macros.empty()
const rule_loader::context cond_ctx(it->second, condition, ctx); ? errors_macros.begin()->second
: unresolved_macros.begin()->second;
THROW(true, std::string errmsg = !errors_macros.empty()
std::string("Undefined macro '") ? errors_macros.begin()->first
+ it->first : ("Undefined macro '" + unresolved_macros.begin()->first + "' used in filter.");
+ "' used in filter.", const rule_loader::context cond_ctx(errpos, condition, ctx);
cond_ctx); THROW(true, errmsg, cond_ctx);
} }
for (auto &it : macro_resolver.get_resolved_macros()) for (auto &it : macro_resolver.get_resolved_macros())