Skip to content

Iteration over std::unordered_map while modifying it causes missing exported functions #768

@Dreamapple

Description

@Dreamapple

version 0.19.6
When compiling Python code with codon, I've observed that many functions I intend to export are missing from the output. After investigation, I've minimized the problem to a C++ code snippet within codon's codebase where an std::unordered_map is being modified while iterating over it. This leads to undefined behavior, likely causing iterator invalidation and resulting in functions being omitted or corrupted during the compilation process.
This bug consistently manifests on Linux systems, but I have been unable to reproduce it on macOS.

    # codon/parser/visitors/typecheck/infer.cpp
    if (ctx->getBase()->iteration == 1 && isToplevel) {
      // Realize all @force_realize functions
      for (auto &f : ctx->cache->functions) {
        auto ast = f.second.ast;
        if (f.second.type && f.second.realizations.empty() &&
            (ast->hasAttribute(Attr::ForceRealize) || ast->hasAttribute(Attr::Export) ||
             (ast->hasAttribute(Attr::C) && !ast->hasAttribute(Attr::CVarArg)))) {
          seqassert(f.second.type->canRealize(), "cannot realize {}", f.first);
          LOG_REALIZE("[force_realize] {}", f.second.getType()->debugString(2));
          realize(instantiateType(f.second.getType()));  // ERROR this might operate on ctx->cache->functions
          seqassert(!f.second.realizations.empty(), "cannot realize {}", f.first);
        }
      }
    }

stacktrace

libcodonc.so!codon::ast::TypecheckVisitor::visit(codon::ast::TypecheckVisitor * this, codon::ast::FunctionStmt * stmt) (/root/projects/codon_compile/codon-0.19.6/codon/parser/visitors/typecheck/function.cpp:596)
libcodonc.so!codon::ast::FunctionStmt::accept(codon::ast::FunctionStmt * this, codon::ast::ASTVisitor & visitor) (/root/projects/codon_compile/codon-0.19.6/codon/parser/ast/stmt.cpp:621)
libcodonc.so!codon::ast::TypecheckVisitor::transform(codon::ast::TypecheckVisitor * this, codon::ast::Stmt * stmt) (/root/projects/codon_compile/codon-0.19.6/codon/parser/visitors/typecheck/typecheck.cpp:302)
libcodonc.so!codon::ast::TypecheckVisitor::transformNewImport(codon::ast::TypecheckVisitor * this, const codon::ast::ImportFile & file) (/root/projects/codon_compile/codon-0.19.6/codon/parser/visitors/typecheck/import.cpp:415)
libcodonc.so!codon::ast::TypecheckVisitor::visit(codon::ast::TypecheckVisitor * this, codon::ast::ImportStmt * stmt) (/root/projects/codon_compile/codon-0.19.6/codon/parser/visitors/typecheck/import.cpp:79)
libcodonc.so!codon::ast::ImportStmt::accept(codon::ast::ImportStmt * this, codon::ast::ASTVisitor & visitor) (/root/projects/codon_compile/codon-0.19.6/codon/parser/ast/stmt.cpp:616)
libcodonc.so!codon::ast::TypecheckVisitor::transform(codon::ast::TypecheckVisitor * this, codon::ast::Stmt * stmt) (/root/projects/codon_compile/codon-0.19.6/codon/parser/visitors/typecheck/typecheck.cpp:302)
libcodonc.so!codon::ast::TypecheckVisitor::visit(codon::ast::TypecheckVisitor * this, codon::ast::SuiteStmt * stmt) (/root/projects/codon_compile/codon-0.19.6/codon/parser/visitors/typecheck/typecheck.cpp:367)
libcodonc.so!codon::ast::SuiteStmt::accept(codon::ast::SuiteStmt * this, codon::ast::ASTVisitor & visitor) (/root/projects/codon_compile/codon-0.19.6/codon/parser/ast/stmt.cpp:602)
libcodonc.so!codon::ast::TypecheckVisitor::transform(codon::ast::TypecheckVisitor * this, codon::ast::Stmt * stmt) (/root/projects/codon_compile/codon-0.19.6/codon/parser/visitors/typecheck/typecheck.cpp:302)
libcodonc.so!codon::ast::TypecheckVisitor::inferTypes(codon::ast::TypecheckVisitor * this, codon::ast::Stmt * result, bool isToplevel) (/root/projects/codon_compile/codon-0.19.6/codon/parser/visitors/typecheck/infer.cpp:81)
libcodonc.so!codon::ast::TypecheckVisitor::realizeFunc(codon::ast::TypecheckVisitor * this, codon::ast::types::FuncType * type, bool force) (/root/projects/codon_compile/codon-0.19.6/codon/parser/visitors/typecheck/infer.cpp:496)
libcodonc.so!codon::ast::TypecheckVisitor::realize(codon::ast::TypecheckVisitor * this, codon::ast::types::Type * typ) (/root/projects/codon_compile/codon-0.19.6/codon/parser/visitors/typecheck/infer.cpp:210)
libcodonc.so!codon::ast::TypecheckVisitor::visit(codon::ast::TypecheckVisitor * this, codon::ast::IdExpr * expr) (/root/projects/codon_compile/codon-0.19.6/codon/parser/visitors/typecheck/access.cpp:57)
libcodonc.so!codon::ast::IdExpr::accept(codon::ast::IdExpr * this, codon::ast::ASTVisitor & visitor) (/root/projects/codon_compile/codon-0.19.6/codon/parser/ast/expr.cpp:575)
libcodonc.so!codon::ast::TypecheckVisitor::transform(codon::ast::TypecheckVisitor * this, codon::ast::Expr * expr, bool allowTypes) (/root/projects/codon_compile/codon-0.19.6/codon/parser/visitors/typecheck/typecheck.cpp:221)
libcodonc.so!codon::ast::TypecheckVisitor::transform(codon::ast::TypecheckVisitor * this, codon::ast::Expr * expr) (/root/projects/codon_compile/codon-0.19.6/codon/parser/visitors/typecheck/typecheck.cpp:207)
libcodonc.so!codon::ast::TypecheckVisitor::visit(codon::ast::TypecheckVisitor * this, codon::ast::DotExpr * expr) (/root/projects/codon_compile/codon-0.19.6/codon/parser/visitors/typecheck/access.cpp:265)
libcodonc.so!codon::ast::DotExpr::accept(codon::ast::DotExpr * this, codon::ast::ASTVisitor & visitor) (/root/projects/codon_compile/codon-0.19.6/codon/parser/ast/expr.cpp:590)
libcodonc.so!codon::ast::TypecheckVisitor::transform(codon::ast::TypecheckVisitor * this, codon::ast::Expr * expr, bool allowTypes) (/root/projects/codon_compile/codon-0.19.6/codon/parser/visitors/typecheck/typecheck.cpp:221)
libcodonc.so!codon::ast::TypecheckVisitor::transform(codon::ast::TypecheckVisitor * this, codon::ast::Expr * expr) (/root/projects/codon_compile/codon-0.19.6/codon/parser/visitors/typecheck/typecheck.cpp:207)
libcodonc.so!codon::ast::TypecheckVisitor::visit(codon::ast::TypecheckVisitor * this, codon::ast::CallExpr * expr) (/root/projects/codon_compile/codon-0.19.6/codon/parser/visitors/typecheck/call.cpp:81)
libcodonc.so!codon::ast::CallExpr::accept(codon::ast::CallExpr * this, codon::ast::ASTVisitor & visitor) (/root/projects/codon_compile/codon-0.19.6/codon/parser/ast/expr.cpp:589)
libcodonc.so!codon::ast::TypecheckVisitor::transform(codon::ast::TypecheckVisitor * this, codon::ast::Expr * expr, bool allowTypes) (/root/projects/codon_compile/codon-0.19.6/codon/parser/visitors/typecheck/typecheck.cpp:221)
libcodonc.so!codon::ast::TypecheckVisitor::transform(codon::ast::TypecheckVisitor * this, codon::ast::Expr * expr) (/root/projects/codon_compile/codon-0.19.6/codon/parser/visitors/typecheck/typecheck.cpp:207)
libcodonc.so!codon::ast::TypecheckVisitor::getCalleeFn(codon::ast::TypecheckVisitor * this, codon::ast::CallExpr * expr, codon::ast::TypecheckVisitor::PartialCallData & part) (/root/projects/codon_compile/codon-0.19.6/codon/parser/visitors/typecheck/call.cpp:430)
libcodonc.so!codon::ast::TypecheckVisitor::visit(codon::ast::TypecheckVisitor * this, codon::ast::CallExpr * expr) (/root/projects/codon_compile/codon-0.19.6/codon/parser/visitors/typecheck/call.cpp:86)
libcodonc.so!codon::ast::CallExpr::accept(codon::ast::CallExpr * this, codon::ast::ASTVisitor & visitor) (/root/projects/codon_compile/codon-0.19.6/codon/parser/ast/expr.cpp:589)
libcodonc.so!codon::ast::TypecheckVisitor::transform(codon::ast::TypecheckVisitor * this, codon::ast::Expr * expr, bool allowTypes) (/root/projects/codon_compile/codon-0.19.6/codon/parser/visitors/typecheck/typecheck.cpp:221)
libcodonc.so!codon::ast::TypecheckVisitor::transform(codon::ast::TypecheckVisitor * this, codon::ast::Expr * expr) (/root/projects/codon_compile/codon-0.19.6/codon/parser/visitors/typecheck/typecheck.cpp:207)
libcodonc.so!codon::ast::TypecheckVisitor::visit(codon::ast::TypecheckVisitor * this, codon::ast::ReturnStmt * stmt) (/root/projects/codon_compile/codon-0.19.6/codon/parser/visitors/typecheck/function.cpp:120)
libcodonc.so!codon::ast::ReturnStmt::accept(codon::ast::ReturnStmt * this, codon::ast::ASTVisitor & visitor) (/root/projects/codon_compile/codon-0.19.6/codon/parser/ast/stmt.cpp:609)
libcodonc.so!codon::ast::TypecheckVisitor::transform(codon::ast::TypecheckVisitor * this, codon::ast::Stmt * stmt) (/root/projects/codon_compile/codon-0.19.6/codon/parser/visitors/typecheck/typecheck.cpp:302)
libcodonc.so!codon::ast::TypecheckVisitor::visit(codon::ast::TypecheckVisitor * this, codon::ast::SuiteStmt * stmt) (/root/projects/codon_compile/codon-0.19.6/codon/parser/visitors/typecheck/typecheck.cpp:367)
libcodonc.so!codon::ast::SuiteStmt::accept(codon::ast::SuiteStmt * this, codon::ast::ASTVisitor & visitor) (/root/projects/codon_compile/codon-0.19.6/codon/parser/ast/stmt.cpp:602)
libcodonc.so!codon::ast::TypecheckVisitor::transform(codon::ast::TypecheckVisitor * this, codon::ast::Stmt * stmt) (/root/projects/codon_compile/codon-0.19.6/codon/parser/visitors/typecheck/typecheck.cpp:302)
libcodonc.so!codon::ast::TypecheckVisitor::inferTypes(codon::ast::TypecheckVisitor * this, codon::ast::Stmt * result, bool isToplevel) (/root/projects/codon_compile/codon-0.19.6/codon/parser/visitors/typecheck/infer.cpp:81)
libcodonc.so!codon::ast::TypecheckVisitor::realizeFunc(codon::ast::TypecheckVisitor * this, codon::ast::types::FuncType * type, bool force) (/root/projects/codon_compile/codon-0.19.6/codon/parser/visitors/typecheck/infer.cpp:496)
libcodonc.so!codon::ast::TypecheckVisitor::realize(codon::ast::TypecheckVisitor * this, codon::ast::types::Type * typ) (/root/projects/codon_compile/codon-0.19.6/codon/parser/visitors/typecheck/infer.cpp:210)
libcodonc.so!codon::ast::TypecheckVisitor::visit(codon::ast::TypecheckVisitor * this, codon::ast::IdExpr * expr) (/root/projects/codon_compile/codon-0.19.6/codon/parser/visitors/typecheck/access.cpp:57)
libcodonc.so!codon::ast::IdExpr::accept(codon::ast::IdExpr * this, codon::ast::ASTVisitor & visitor) (/root/projects/codon_compile/codon-0.19.6/codon/parser/ast/expr.cpp:575)
libcodonc.so!codon::ast::TypecheckVisitor::transform(codon::ast::TypecheckVisitor * this, codon::ast::Expr * expr, bool allowTypes) (/root/projects/codon_compile/codon-0.19.6/codon/parser/visitors/typecheck/typecheck.cpp:221)
libcodonc.so!codon::ast::TypecheckVisitor::transform(codon::ast::TypecheckVisitor * this, codon::ast::Expr * expr) (/root/projects/codon_compile/codon-0.19.6/codon/parser/visitors/typecheck/typecheck.cpp:207)
libcodonc.so!codon::ast::TypecheckVisitor::visit(codon::ast::TypecheckVisitor * this, codon::ast::CallExpr * expr) (/root/projects/codon_compile/codon-0.19.6/codon/parser/visitors/typecheck/call.cpp:81)
libcodonc.so!codon::ast::CallExpr::accept(codon::ast::CallExpr * this, codon::ast::ASTVisitor & visitor) (/root/projects/codon_compile/codon-0.19.6/codon/parser/ast/expr.cpp:589)
libcodonc.so!codon::ast::TypecheckVisitor::transform(codon::ast::TypecheckVisitor * this, codon::ast::Expr * expr, bool allowTypes) (/root/projects/codon_compile/codon-0.19.6/codon/parser/visitors/typecheck/typecheck.cpp:221)
libcodonc.so!codon::ast::TypecheckVisitor::transform(codon::ast::TypecheckVisitor * this, codon::ast::Expr * expr) (/root/projects/codon_compile/codon-0.19.6/codon/parser/visitors/typecheck/typecheck.cpp:207)
libcodonc.so!codon::ast::TypecheckVisitor::transformUpdate(codon::ast::TypecheckVisitor * this, codon::ast::AssignStmt * stmt) (/root/projects/codon_compile/codon-0.19.6/codon/parser/visitors/typecheck/assign.cpp:347)
libcodonc.so!codon::ast::TypecheckVisitor::transformAssignment(codon::ast::TypecheckVisitor * this, codon::ast::AssignStmt * stmt, bool mustExist) (/root/projects/codon_compile/codon-0.19.6/codon/parser/visitors/typecheck/assign.cpp:249)
libcodonc.so!codon::ast::TypecheckVisitor::visit(codon::ast::TypecheckVisitor * this, codon::ast::AssignStmt * stmt) (/root/projects/codon_compile/codon-0.19.6/codon/parser/visitors/typecheck/assign.cpp:50)
libcodonc.so!codon::ast::AssignStmt::accept(codon::ast::AssignStmt * this, codon::ast::ASTVisitor & visitor) (/root/projects/codon_compile/codon-0.19.6/codon/parser/ast/stmt.cpp:606)
libcodonc.so!codon::ast::TypecheckVisitor::transform(codon::ast::TypecheckVisitor * this, codon::ast::Stmt * stmt) (/root/projects/codon_compile/codon-0.19.6/codon/parser/visitors/typecheck/typecheck.cpp:302)
libcodonc.so!codon::ast::TypecheckVisitor::visit(codon::ast::TypecheckVisitor * this, codon::ast::SuiteStmt * stmt) (/root/projects/codon_compile/codon-0.19.6/codon/parser/visitors/typecheck/typecheck.cpp:367)
libcodonc.so!codon::ast::SuiteStmt::accept(codon::ast::SuiteStmt * this, codon::ast::ASTVisitor & visitor) (/root/projects/codon_compile/codon-0.19.6/codon/parser/ast/stmt.cpp:602)
libcodonc.so!codon::ast::TypecheckVisitor::transform(codon::ast::TypecheckVisitor * this, codon::ast::Stmt * stmt) (/root/projects/codon_compile/codon-0.19.6/codon/parser/visitors/typecheck/typecheck.cpp:302)
libcodonc.so!codon::ast::TypecheckVisitor::visit(codon::ast::TypecheckVisitor * this, codon::ast::TryStmt * stmt) (/root/projects/codon_compile/codon-0.19.6/codon/parser/visitors/typecheck/error.cpp:55)
libcodonc.so!codon::ast::TryStmt::accept(codon::ast::TryStmt * this, codon::ast::ASTVisitor & visitor) (/root/projects/codon_compile/codon-0.19.6/codon/parser/ast/stmt.cpp:618)
libcodonc.so!codon::ast::TypecheckVisitor::transform(codon::ast::TypecheckVisitor * this, codon::ast::Stmt * stmt) (/root/projects/codon_compile/codon-0.19.6/codon/parser/visitors/typecheck/typecheck.cpp:302)
libcodonc.so!codon::ast::TypecheckVisitor::visit(codon::ast::TypecheckVisitor * this, codon::ast::SuiteStmt * stmt) (/root/projects/codon_compile/codon-0.19.6/codon/parser/visitors/typecheck/typecheck.cpp:367)
libcodonc.so!codon::ast::SuiteStmt::accept(codon::ast::SuiteStmt * this, codon::ast::ASTVisitor & visitor) (/root/projects/codon_compile/codon-0.19.6/codon/parser/ast/stmt.cpp:602)
libcodonc.so!codon::ast::TypecheckVisitor::transform(codon::ast::TypecheckVisitor * this, codon::ast::Stmt * stmt) (/root/projects/codon_compile/codon-0.19.6/codon/parser/visitors/typecheck/typecheck.cpp:302)
libcodonc.so!codon::ast::TypecheckVisitor::inferTypes(codon::ast::TypecheckVisitor * this, codon::ast::Stmt * result, bool isToplevel) (/root/projects/codon_compile/codon-0.19.6/codon/parser/visitors/typecheck/infer.cpp:81)
libcodonc.so!codon::ast::TypecheckVisitor::realizeFunc(codon::ast::TypecheckVisitor * this, codon::ast::types::FuncType * type, bool force) (/root/projects/codon_compile/codon-0.19.6/codon/parser/visitors/typecheck/infer.cpp:496)
libcodonc.so!codon::ast::TypecheckVisitor::realize(codon::ast::TypecheckVisitor * this, codon::ast::types::Type * typ) (/root/projects/codon_compile/codon-0.19.6/codon/parser/visitors/typecheck/infer.cpp:210)
libcodonc.so!codon::ast::TypecheckVisitor::realize(codon::ast::TypecheckVisitor * this, codon::ast::types::TypePtr && t) (/root/projects/codon_compile/codon-0.19.6/codon/parser/visitors/typecheck/typecheck.h:230)
libcodonc.so!codon::ast::TypecheckVisitor::inferTypes(codon::ast::TypecheckVisitor * this, codon::ast::Stmt * result, bool isToplevel) (/root/projects/codon_compile/codon-0.19.6/codon/parser/visitors/typecheck/infer.cpp:113)
libcodonc.so!codon::ast::TypecheckVisitor::apply(codon::ast::Cache * cache, codon::ast::Stmt * node, const std::string & file, const std::unordered_map<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::hash<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::equal_to<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > & defines, const std::unordered_map<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::hash<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::equal_to<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > & earlyDefines, bool barebones) (/root/projects/codon_compile/codon-0.19.6/codon/parser/visitors/typecheck/typecheck.cpp:79)
libcodonc.so!codon::Compiler::parse(codon::Compiler * this, bool isCode, const std::string & file, const std::string & code, int startLine, int testFlags, const std::unordered_map<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::hash<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::equal_to<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > & defines) (/root/projects/codon_compile/codon-0.19.6/codon/compiler/compiler.cpp:111)
libcodonc.so!codon::Compiler::parseFile(codon::Compiler * this, const std::string & file, int testFlags, const std::unordered_map<std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::basic_string<char, std::char_traits<char>, std::allocator<char> >, std::hash<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::equal_to<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >, std::allocator<std::pair<std::basic_string<char, std::char_traits<char>, std::allocator<char> > const, std::basic_string<char, std::char_traits<char>, std::allocator<char> > > > > & defines) (/root/projects/codon_compile/codon-0.19.6/codon/compiler/compiler.cpp:151)
processSource(std::vector<char const*, std::allocator<char const*> > const&, bool, std::function<bool ()>)(const std::vector<char const*, std::allocator<char const*> > & args, bool standalone, std::function<bool ()> pyExtension) (/root/projects/codon_compile/codon-0.19.6/codon/app/main.cpp:239)
buildMode(const std::vector<char const*, std::allocator<char const*> > & args, const std::string & argv0) (/root/projects/codon_compile/codon-0.19.6/codon/app/main.cpp:370)
main(int argc, const char ** argv) (/root/projects/codon_compile/codon-0.19.6/codon/app/main.cpp:497)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions