Skip to content

Segfault caused by circular construction dependency between LowerModule and LowerTypes #2042

@mahmood82

Description

@mahmood82

I'm encountering a segmentation fault when calling a method on
LowerModule::getTargetLoweringInfo(). After debugging, it appears to be caused by a circular dependency between LowerModule and LowerTypes during construction.

The construction chain begins in cir::createLowerModule:

return std::make_unique<LowerModule>(std::move(langOpts),
                                     std::move(codeGenOpts), module,
                                     std::move(targetInfo), rewriter);

Inside LowerModule's constructor, the types member is constructed before the
target lowering info exists:

LowerModule::LowerModule(clang::LangOptions langOpts,
                         clang::CodeGenOptions codeGenOpts,
                         mlir::ModuleOp &module,
                         std::unique_ptr<clang::TargetInfo> target,
                         mlir::PatternRewriter &rewriter)
    : context(module, std::move(langOpts), std::move(codeGenOpts)),
      module(module), Target(std::move(target)), ABI(createCXXABI(*this)),
      types(*this), rewriter(rewriter) {
  context.initBuiltinTypes(*Target);
}

LowerTypes immediately queries LowerModule::getTargetLoweringInfo():

LowerTypes::LowerTypes(LowerModule &LM)
    : LM(LM), context(LM.getContext()), Target(LM.getTarget()),
      CXXABI(LM.getCXXABI()),
      TheABIInfo(LM.getTargetLoweringInfo().getABIInfo()),
      mlirContext(LM.getMLIRContext()), DL(LM.getModule()) {}

This triggers:

const TargetLoweringInfo &LowerModule::getTargetLoweringInfo() {
  if (!TheTargetCodeGenInfo)
    TheTargetCodeGenInfo = createTargetLoweringInfo(*this);
  return *TheTargetCodeGenInfo;
}

And in my configuration, createTargetLoweringInfo resolves to:

std::unique_ptr<TargetLoweringInfo>
createSPIRVTargetLoweringInfo(LowerModule &lowerModule) {
  return std::make_unique<SPIRVTargetLoweringInfo>(lowerModule.getTypes());
}

At this point, lowerModule.getTypes() returns the LowerTypes instance that is still under construction, and dereferencing fields inside it triggers a segmentation fault.

So effectively:

  • LowerModule constructor ==> constructs types
  • LowerTypes constructor ==> queries getTargetLoweringInfo
  • createTargetLoweringInfo ==> asks again for LowerTypes
  • ==> circular dependency ==> crash

This looks like a design-time initialization order violation.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions