Memory Corruption in LLVM

In my upgrade process I get a memory-corruption in LLVM in a test-case (sadly I can’t provide this test-case)

I upgraded from 18.1.8 to 19.1.0 with only minor changes caused by my target - could be not enough changes.

The symptoms differ and are:

  1. a straight core dump without any error message:
     | ^
     | static
PLEASE submit a bug report to https://github.com/llvm/llvm-project/issues/ and include the crash backtrace, preprocessed source, and associated run script.
Stack dump:
  1. or an assertion
      | ^
      | static
Assertion failed: (Sequence.size() - Noops == ScheduledNodes && "The number of nodes scheduled doesn't match the expected number!"), function VerifyScheduledSequence, file ScheduleDAGSDNodes.cpp, line 732.
  1. or another assertion
      | ^
      | static
Assertion failed: (Op.getValueType() != MVT::Other && Op.getValueType() != MVT::Glue && "Chain and glue operands should occur at end of operand list!"), function AddRegisterOperand, file InstrEmitter.cpp, line 325.

And maybe others.

When I run it in the debugger lldb I get:
1.

* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=1, address=0x1)
    frame #0: 0x00000001008d7310 clang`llvm::detail::PunnedPointer<llvm::SUnit*>::asInt(this=0x0000000000000001) const at PointerIntPair.h:41:5
   38
   39  	  constexpr intptr_t asInt() const {
   40  	    intptr_t R = 0;
-> 41  	    std::memcpy(&R, Data, sizeof(R));
   42  	    return R;
   43  	  }
  1. or
* thread #1, queue = 'com.apple.main-thread', stop reason = hit program assert
    frame #4: 0x00000001043b7df0 clang`llvm::InstrEmitter::AddRegisterOperand(this=0x000000016fdf6010, MIB=0x000000016fdf5a60, Op=SDValue @ 0x000000016fdf5430, IIOpNum=1, II=0x000000010a1156d8, VRBaseMap=0x000000016fdf5fe8, IsDebug=false, IsClone=false, IsCloned=false) at InstrEmitter.cpp:323:3
   320 	                                 const MCInstrDesc *II,
   321 	                                 DenseMap<SDValue, Register> &VRBaseMap,
   322 	                                 bool IsDebug, bool IsClone, bool IsCloned) {
-> 323 	  assert(Op.getValueType() != MVT::Other &&
   324 	         Op.getValueType() != MVT::Glue &&
   325 	         "Chain and glue operands should occur at end of operand list!");
   326 	  // Get/emit the operand.
  1. or
* thread #1, queue = 'com.apple.main-thread', stop reason = EXC_BAD_ACCESS (code=2, address=0xfffff0000)
    frame #0: 0x0000000100d552f8 clang`llvm::SmallVectorTemplateBase<llvm::SDep, true>::push_back(this=0x0000000a3b4ccc78, Elt=llvm::SmallVectorTemplateBase<llvm::SDep, true>::ValueParamT @ 0x000000016fdf5f58) at SmallVector.h:577:5
   574 	public:
   575 	  void push_back(ValueParamT Elt) {
   576 	    const T *EltPtr = reserveForParamAndGetAddress(Elt);
-> 577 	    memcpy(reinterpret_cast<void *>(this->end()), EltPtr, sizeof(T));
   578 	    this->set_size(this->size() + 1);
   579 	  }

And maybe others.

I assume that quite some source code did go through the compiler and that is not a LLVM problem, but a missing initialisation from my side. Well, the different error messages point to missing initialisations.

I do use the option -verify-machineinstrs and I guess that the IR is correct.

Are there good guesses how I can track this down to the initial problem?

You are mentioning suspicion of memory corruption, but I don’t see any mention of ASAN (or Valgrind)? Have you tried this?

1 Like

Thanks for mentioning that. I used ASAN. Without special options I get:

=================================================================
==28685==ERROR: AddressSanitizer: use-after-poison on address 0x6210005e2ac8 at pc 0x00010a2f454c bp 0x00016afb0350 sp 0x00016afb0348
READ of size 8 at 0x6210005e2ac8 thread T0
    #0 0x00010a2f4548 in llvm::ScheduleDAGSDNodes::BuildSchedUnits() ScheduleDAGSDNodes.cpp:357
    #1 0x00010a2f6080 in llvm::ScheduleDAGSDNodes::BuildSchedGraph(llvm::AAResults*) ScheduleDAGSDNodes.cpp:543
    #2 0x00010a2cf770 in (anonymous namespace)::ScheduleDAGRRList::Schedule() ScheduleDAGRRList.cpp:373
    #3 0x00010a493ec0 in llvm::SelectionDAGISel::CodeGenAndEmitDAG() SelectionDAGISel.cpp:1111

But I know that I can screw up things in DAG2DAG easily. Well, I did that in the past. So, I wanted to view the ISel and Sched DAGs (-view-isel-dags -view-sched-dags [editted] and -debug-only=isel). And now I get:

=================================================================
==29210==ERROR: AddressSanitizer: use-after-poison on address 0x6210005e2ae0 at pc 0x000109b4ec44 bp 0x00016b8e4910 sp 0x00016b8e4908
READ of size 2 at 0x6210005e2ae0 thread T0
    #0 0x000109b4ec40 in DumpNodes(llvm::SDNode const*, unsigned int, llvm::SelectionDAG const*) SelectionDAGDumper.cpp:1008
    #1 0x000109b4eba4 in DumpNodes(llvm::SDNode const*, unsigned int, llvm::SelectionDAG const*) SelectionDAGDumper.cpp:1011
    #2 0x000109b4eba4 in DumpNodes(llvm::SDNode const*, unsigned int, llvm::SelectionDAG const*) SelectionDAGDumper.cpp:1011
    #3 0x000109b4e430 in llvm::SelectionDAG::dump() const SelectionDAGDumper.cpp:1027
    #4 0x000109b5fd60 in llvm::SelectionDAGISel::CodeGenAndEmitDAG() SelectionDAGISel.cpp:1098
...
0x6210005e2ae0 is located 1504 bytes inside of 4096-byte region [0x6210005e2500,0x6210005e3500)
allocated by thread T0 here:
    #0 0x00011ad91ff4 in __sanitizer_mz_memalign+0x80 (libclang_rt.asan_osx_dynamic.dylib:arm64e+0x41ff4)
    #1 0x000184aa78f4 in _malloc_zone_memalign+0x128 (libsystem_malloc.dylib:arm64e+0x3a8f4)
    #2 0x000184a8b808 in _malloc_type_aligned_alloc_outlined+0x68 (libsystem_malloc.dylib:arm64e+0x1e808)
    #3 0x000184c328b4 in operator new(unsigned long, std::align_val_t)+0x4c (libc++abi.dylib:arm64e+0x168b4)
    #4 0x0001046182d4 in llvm::BumpPtrAllocatorImpl<llvm::MallocAllocator, 4096ul, 4096ul, 128ul>::StartNewSlab() Allocator.h:344
    #5 0x00010461805c in llvm::BumpPtrAllocatorImpl<llvm::MallocAllocator, 4096ul, 4096ul, 128ul>::AllocateSlow(unsigned long, unsigned long, llvm::Align) Allocator.h:200
    #6 0x000109aa1e5c in llvm::SelectionDAG::getRegister(unsigned int, llvm::EVT) SelectionDAG.cpp:2275
    #7 0x00010458840c in llvm::MYTargetLowering::LowerFormalArguments(llvm::SDValue, unsigned int, bool, llvm::SmallVectorImpl<llvm::ISD::InputArg> const&, llvm::SDLoc const&, llvm::SelectionDAG&, llvm::SmallVectorImpl<llvm::SDValue>&) const MYISelLowering.cpp:3503
    #8 0x000109a61ca8 in llvm::SelectionDAGISel::LowerArguments(llvm::Function const&) SelectionDAGBuilder.cpp:11618

It seems to me that straight during ISel something goes wrong.
MYISelLowering.cpp:3503 is:

      SDValue Arg = DAG.getCopyFromReg(Chain, DL, VReg, VA.getLocVT());

Chain and DL are the parameters passed to LowerFormalArguments(), VReg is of type unsigned and contains a virtual register.
And now I’m stuck.

Edit: I forgot to mention the use of option -debug-only=isel.

Finally, I have found my bug. Indeed, I screw it up in ISel: I delete a node that is not dead. Currently problem solved.