verilog: rebuild user_type_stack from globals before parsing file

This was actually a ticking UB bomb: after running the parser, the type
maps contain pointers to children of the current AST, which is
recursively deleted after the pass has executed. This leaves the
pointers in user_type_stack dangling, which just happened to never be a
problem due to another bug that causes typedefs from higher-level type
maps to never be considered.

Rebuilding the type stack from the design's globals ensures the AstNode
pointers are valid.
This commit is contained in:
Xiretza 2021-03-16 16:42:14 +01:00 committed by Zachary Snow
parent 3a12617ec0
commit 0c66141ed2
1 changed files with 21 additions and 5 deletions

View File

@ -61,11 +61,6 @@ static void add_package_types(dict<std::string, AST::AstNode *> &user_types, std
}
}
}
// carry over typedefs from previous files, but allow them to be overridden
// note that these type maps are currently never reclaimed
if (user_type_stack.empty() || !user_type_stack.back()->empty())
user_type_stack.push_back(new UserTypeMap());
}
struct VerilogFrontend : public Frontend {
@ -487,6 +482,19 @@ struct VerilogFrontend : public Frontend {
// make package typedefs available to parser
add_package_types(pkg_user_types, design->verilog_packages);
UserTypeMap *global_types_map = new UserTypeMap();
for (auto def : design->verilog_globals) {
if (def->type == AST::AST_TYPEDEF) {
(*global_types_map)[def->str] = def;
}
}
log_assert(user_type_stack.empty());
// use previous global typedefs as bottom level of user type stack
user_type_stack.push_back(global_types_map);
// add a new empty type map to allow overriding existing global definitions
user_type_stack.push_back(new UserTypeMap());
frontend_verilog_yyset_lineno(1);
frontend_verilog_yyrestart(NULL);
frontend_verilog_yyparse();
@ -509,6 +517,14 @@ struct VerilogFrontend : public Frontend {
if (!flag_nopp)
delete lexin;
// only the previous and new global type maps remain
log_assert(user_type_stack.size() == 2);
for (auto it : user_type_stack) {
// the global typedefs have to remain valid for future invocations, so just drop the map without deleting values
delete it;
}
user_type_stack.clear();
delete current_ast;
current_ast = NULL;