PMDataManager segfault when using `addRequired` in custom compiler pass

I have two RISCV custom compiler passes, pass A and pass B. Pass A adds some custom instructions that I want to detect in pass B. As such, pass B should depend on pass A. In B::getAnalysisUsage I am doing AU.addRequired<A>() so pass A should run before pass B (is that right?).

However, the compiler crashes at PMDataManager::~PMDataManager when I do this. I presume an invalid pointer is freed, but how is this possible? Maybe I need to add something to pass A so that it can be required by pass B?

I can use addRequired for built-in passes just fine, it’s just the custom pass A that doesn’t work. Pass A does not depend on anything, so I don’t think there is a dependency cycle going on. If you need any more information please let me know.

Crash below (using llvm 16.0.2):

1.  <eof> parser at end of file
    #0 0x0000000001dfcae7 llvm::sys::PrintStackTrace(llvm::raw_ostream&, int) (/workspaces/intermittent-risc-v/llvm/llvm-16.0.2/install/bin/clang+0x1dfcae7)
    #1 0x0000000001dfaa8e llvm::sys::RunSignalHandlers() (/workspaces/intermittent-risc-v/llvm/llvm-16.0.2/install/bin/clang+0x1dfaa8e)
    #2 0x0000000001d7fd4f CrashRecoverySignalHandler(int) CrashRecoveryContext.cpp:0:0
    #3 0x00007ff9cd4a6520 (/lib/x86_64-linux-gnu/libc.so.6+0x42520)
    #4 0x00000000017ff172 llvm::PMDataManager::~PMDataManager() (/workspaces/intermittent-risc-v/llvm/llvm-16.0.2/install/bin/clang+0x17ff172)
    clang-16: error: clang frontend command failed with exit code 139 (use -v to see invocation)

Source code for A:

char A::ID = 0;

A::A() : MachineFunctionPass(ID) {}

void A::getAnalysisUsage(AnalysisUsage &AU) const
{
    AU.setPreservesCFG();
    AU.setPreservesAll();

    MachineFunctionPass::getAnalysisUsage(AU);
}

bool A::runOnMachineFunction(MachineFunction &MF) {
    // Pass A inserts instructions.
}

FunctionPass *llvm::createAPass() {
  return new A();
}

INITIALIZE_PASS(A, DEBUG_TYPE, PASS_NAME, false, false)

Source code for B:

char B::ID = 0;


INITIALIZE_PASS_BEGIN(B, DEBUG_TYPE, PASS_NAME,
                      false, false)
INITIALIZE_PASS_DEPENDENCY(LiveIntervals)
INITIALIZE_PASS_DEPENDENCY(A)
INITIALIZE_PASS_END(B, DEBUG_TYPE,
                PASS_NAME, false, false)

B::B() : MachineFunctionPass(ID) {}

void B::getAnalysisUsage(AnalysisUsage &AU) const
{
    AU.setPreservesCFG();
    AU.addRequired<A>();
    AU.addPreserved<A>();
    AU.addRequired<LiveIntervals>();

    MachineFunctionPass::getAnalysisUsage(AU);
}

bool B::runOnMachineFunction(MachineFunction &MF) {
    // Pass B detects instructions inserted by pass A.
}

FunctionPass *llvm::createBPass() {
  return new B();
}

RISCVTargetMachine.cpp

extern "C" LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVTarget() {
  auto *PR = PassRegistry::getPassRegistry();
  ...
  initializeAPass(*PR);
  initializeBPass(*PR);
}

void RISCVPassConfig::addPreEmitPass() {
  addPass(createAPass());
  ...
}

void RISCVPassConfig::addPreRegAlloc() {
  ...
  addPass(createBPass());
}

OK, I found out something. The segfault only happens when I use addRequired<LiveIntervals>(); in pass B, after requiring A. But I want to extend some live intervals in pass B, so I need this LiveIntervals pass to be able to use getAnalysis on it. What could be the issue here???