Assertion: replaceAllUses of value with new value of different type! being thrown all of a sudden

Hello,

I wonder if someone would know what is going on below.

All of a sudden I’m getting this assertion thrown:

Assertion failed: (New->getType() == getType() && "replaceAllUses of value with new value of different type!"), function replaceAllUsesWith, file /Users/meister/Development/externals-clasp/llvm36/lib/IR/Value.cpp, line 345.

It’s happening when DIBuilder::finalize is being called at the end of a source file compilation.

Here’s the most illuminating debugging information I could pull out of a frame:

(lldb)
frame #6: 0x0000000103a67c3e clasp_boehm_d`llvm::DIDescriptor::replaceAllUsesWith(this=0x00007fff5fb9e288, D=0x000000010985b330) + 254 at DebugInfo.cpp:399
   396 MDNode *Node = const_cast<MDNode *>(DbgNode);
   397 const MDNode *DN = D;
   398 const Value *V = cast_or_null<Value>(DN);
-> 399 Node->replaceAllUsesWith(const_cast<Value *>(V));
   400 MDNode::deleteTemporary(Node);
   401 }
   402
(lldb) print Node
(llvm::MDNode *) $3 = 0x00000001180b74c0
(lldb) call Node->dump()
!{i32 786468}

(lldb) call V->dump()
!{}

(lldb)

Here’s the first part of the backtrace:

(lldb) bt
* thread #1: tid = 0x4ec96f, 0x00007fff93137866 libsystem_kernel.dylib`__pthread_kill + 10, queue = 'com.apple.main-thread', stop reason = signal SIGABRT
    frame #0: 0x00007fff93137866 libsystem_kernel.dylib`__pthread_kill + 10
    frame #1: 0x00007fff8cd8035c libsystem_pthread.dylib`pthread_kill + 92
    frame #2: 0x0000000103ca78ab clasp_boehm_d`raise(sig=6) + 27 at Signals.inc:373
    frame #3: 0x0000000103ca7962 clasp_boehm_d`abort + 18 at Signals.inc:390
    frame #4: 0x0000000103ca7941 clasp_boehm_d`__assert_rtn(func=0x000000010432361c, file=0x00000001043231df, line=345, expr=0x0000000104323720) + 129 at Signals.inc:386
    frame #5: 0x0000000103bfa48d clasp_boehm_d`llvm::Value::replaceAllUsesWith(this=0x00000001180b74c0, New=0x000000010985b330) + 317 at Value.cpp:344
    frame #6: 0x0000000103a67c3e clasp_boehm_d`llvm::DIDescriptor::replaceAllUsesWith(this=0x00007fff5fb9e288, D=0x000000010985b330) + 254 at DebugInfo.cpp:399
  * frame #7: 0x0000000103a4e8e9 clasp_boehm_d`llvm::DIBuilder::finalize(this=0x0000000116bba4e0) + 185 at DIBuilder.cpp:40
    frame #8: 0x00000001010cd4c8 clasp_boehm_d`core::IndirectVariadicMethoid<core::policies::policies_<>, llvmo::DIBuilder_O, void (this=0x000000010c6ea5b8, lcc_resultP=0x00007fff5fb9eb58, arg0=<unavailable>)()>::invoke(gctools::multiple_values<core::T_O>*, gctools::smart_ptr<core::T_O>) + 232 at external_wrappers_indirect_methoids.h:2704
    frame #9: 0x00000001010cd1f1 clasp_boehm_d`core::IndirectVariadicMethoid<core::policies::policies_<>, llvmo::DIBuilder_O, void (this=0x000000010c6ea5b8, lcc_resultP=0x00007fff5fb9eb58, lcc_nargs=1, lcc_fixed_arg0=0x000000010d1dd098, lcc_fixed_arg1=0x0000000000000000, lcc_fixed_arg2=0x0000000000000000, lcc_fixed_arg3=0x0000000000000000, lcc_fixed_arg4=0x0000000000000000)()>::invoke(gctools::multiple_values<core::T_O>*, unsigned long, core::T_O*, core::T_O*, core::T_O*, core::T_O*, core::T_O*) + 577 at external_wrappers_indirect_methoids.h:2698
    frame #10: 0x00000001009a2426 clasp_boehm_d`core::SingleDispatchGenericFunctionClosure::invoke(this=0x000000010c6ea558, lcc_resultP=0x00007fff5fb9eb58, lcc_nargs=1, lcc_fixed_arg0=0x000000010d1dd098, lcc_fixed_arg1=0x0000000000000000, lcc_fixed_arg2=0x0000000000000000, lcc_fixed_arg3=0x0000000000000000, lcc_fixed_arg4=0x0000000000000000) + 2022 at singleDispatchGenericFunction.cc:183
    frame #11: 0x00000001010f5d5f clasp_boehm_d`sp_FUNCALL(resultP=0x00007fff5fb9f168, closure=0x000000010c6ea558, lcc_nargs=1, lcc_fixed_arg0=0x000000010d1dd098, lcc_fixed_arg1=0x0000000000000000, lcc_fixed_arg2=0x0000000000000000, lcc_fixed_arg3=0x0000000000000000, lcc_fixed_arg4=0x0000000000000000) + 815 at intrinsics.cc:272

I'm not sure what's going on, but I do know this code wouldn't
(or, shouldn't) compile on ToT for the last couple of months,
since `Value` and `MDNode` belong to different class hierarchies.

I forgot to mention this in my initial email.

The build of LLVM that I was using was commit a0d5d7aed8e177cea381b3d054d80c212ece9f2c
The date on the commit is: Date: Fri Sep 26 12:34:06 2014

Also:
Today I grabbed the ToT llvm/clang/clang-extra-tools and I’m working on getting my code to be compatible with it.

I can switch back and forth between the current ToT llvm and the old one.

Thanks,

.Chris.

I forgot to mention this in my initial email.

The build of LLVM that I was using was commit a0d5d7aed8e177cea381b3d054d80c212ece9f2c
The date on the commit is: Date: Fri Sep 26 12:34:06 2014

Also:
Today I grabbed the ToT llvm/clang/clang-extra-tools and I’m working on getting my code to be compatible with it.

I can switch back and forth between the current ToT llvm and the old one.

Hmmm, I didn’t look closely enough and I thought you were hitting an assertions I added a few weeks after that commit in the Metadata RAUW method. But it is the equivalent assertion in Value::RAUW that you are hitting and that has been there forever. Looking at your exact revision, the assertion seems to trigger while executing:

DIType(TempEnumTypes).replaceAllUsesWith(Enums);

in DIBuilder::finalize(). Can you check if TempEnumTypes is null at this point? If that is the issue (which I’m not sure), then you need to call DIBuilder::createCompileUnit() at some point.

Fred

I had a thought, too: are you using two different `LLVMContext`s? That
would cause the `metadata` type to compare unequal.

No, I only declare an LLVMContext once at the start of the program - but I’ll check to see if I can guarantee that I only have one LLVMContext.

Thank you.

Some more data.

I upgraded to todays llvm/clang/clang-extra-tools top-of-trunk and I upgraded my compiler to deal with all of the changes in llvm/clang since last September.
My current ToT llvm commit is 4b678bff4ebae28ec7e04ec936cf924ee8d289df

I am still getting an assertion failure at exactly the same point, when I’m calling DIBuilder::finalize but the assertion has changed (but similar)- it is now:

Assertion failed: (isa(Val) && “cast() argument of incompatible type!”), function cast, file /Users/meister/Development/externals-clasp/llvm36/include/llvm/Support/Casting.h, line 237.

Below is some info that may answer your (Duncan and Frederic) questions:

  1. Duncan asked “are you using two different LLVMContexts?”
    Answer: I may be - in frame 6 the DbgNode->Context reference looks mangled

  2. Frederic asked “is TempEnumTypes null at this point”
    Answer: No, it has the value 0x000000011c81fda8

Below is an lldb session where I’m looking at the backtrace.

(lldb) up
frame #4: 0x0000000103de1811 clasp_boehm_d__assert_rtn(func=0x00000001043a5749, file=0x00000001043a574e, line=237, expr=0x00000001043a579f) + 129 at Signals.inc:533 530 else 531 fprintf(stderr, "Assertion failed: (%s), file %s, line %d.\n", 532 expr, file, line); -> 533 abort(); 534 } 535 536 void abort() { (lldb) up frame #5: 0x0000000103cf47dc clasp_boehm_dllvm::cast_retty<llvm::MDNodeFwdDecl, llvm::MDNode*>::ret_type llvm::cast<llvm::MDNodeFwdDecl, llvm::MDNode>(Val=0x000000011c81fda8) + 108 at Casting.h:237
234
235 template <class X, class Y>
236 inline typename cast_retty<X, Y >::ret_type cast(Y Val) {
→ 237 assert(isa(Val) && “cast() argument of incompatible type!”);
238 return cast_convert_val<X, Y
,
239 typename simplify_type<Y
>::SimpleType>::doit(Val);
240 }

(lldb) up

frame #6: 0x0000000103b6bf6a clasp_boehm_dllvm::DIDescriptor::replaceAllUsesWith(this=0x00007fff5fbdba18, D=0x0000000109d24380) + 218 at DebugInfo.cpp:349 346 void DIDescriptor::replaceAllUsesWith(MDNode *D) { 347 assert(DbgNode && "Trying to replace an unverified type!"); 348 assert(DbgNode != D && "This replacement should always happen"); -> 349 auto *Node = cast<MDNodeFwdDecl>(const_cast<MDNode *>(DbgNode)); 350 Node->replaceAllUsesWith(D); 351 MDNode::deleteTemporary(Node); 352 } (lldb) up frame #7: 0x0000000103b4ff19 clasp_boehm_dllvm::DIBuilder::finalize(this=0x000000011c81feb0) + 185 at DIBuilder.cpp:74
71
72 void DIBuilder::finalize() {
73 DIArray Enums = getOrCreateArray(AllEnumTypes);
→ 74 DIType(TempEnumTypes).replaceAllUsesWith(Enums);
75
76 SmallVector<Metadata *, 16> RetainValues;
77 // Declarations and definitions of the same type may be retained. Some
(lldb) print TempEnumTypes
(llvm::MDNode *) $0 = 0x000000011c81fda8

;;; Later on

(lldb) down
frame #6: 0x0000000103b6bf6a clasp_boehm_d`llvm::DIDescriptor::replaceAllUsesWith(this=0x00007fff5fbdba18, D=0x0000000109d24380) + 218 at DebugInfo.cpp:349
346 void DIDescriptor::replaceAllUsesWith(MDNode *D) {
347 assert(DbgNode && “Trying to replace an unverified type!”);
348 assert(DbgNode != D && “This replacement should always happen”);
→ 349 auto *Node = cast(const_cast<MDNode *>(DbgNode));
350 Node->replaceAllUsesWith(D);
351 MDNode::deleteTemporary(Node);
352 }
(lldb) print DbgNode
(const llvm::MDNode *) $1 = 0x000000011c81fda8
(lldb) call DbgNode->dump()
!{error: Execution was interrupted, reason: EXC_BAD_ACCESS (code=EXC_I386_GPFLT).
The process has been returned to the state before expression evaluation.
(lldb) frame variable
(llvm::DIDescriptor *) this = 0x00007fff5fbdba18
(llvm::MDNode *) D = 0x0000000109d24380
(llvm::MDNodeFwdDecl *) Node = 0x0000000102f55985
(lldb) call D->dump()
!{}

(lldb) call DbgNode
(const llvm::MDNode *) $2 = 0x000000011c81fda8
(lldb) print *DbgNode
(const llvm::MDNode) $3 = {
llvm::Metadata = {
SubclassID = ‘\0’
IsDistinctInContext = false
SubclassData16 = 0
SubclassData32 = 2415919104
}
Context = 0x0000000109e00009
NumOperands = 1
MDNodeSubclassData = 0
}
(lldb) print *D
(llvm::MDNode) $4 = {
llvm::Metadata = {
SubclassID = ‘\0’
IsDistinctInContext = false
SubclassData16 = 0
SubclassData32 = 0
}
Context = 0x0000000109e02430
NumOperands = 0
MDNodeSubclassData = 3267742850
}
(lldb) print D->Context
(llvm::LLVMContext) $5 = {
pImpl = 0x000000010b003000
}
(lldb) print DbgNode->Context
(llvm::LLVMContext) $6 = {
pImpl = 0xd00000000109d003
}
(lldb)

Some more data.

I upgraded to todays llvm/clang/clang-extra-tools top-of-trunk and I upgraded my compiler to deal with all of the changes in llvm/clang since last September.
My current ToT llvm commit is 4b678bff4ebae28ec7e04ec936cf924ee8d289df

I am still getting an assertion failure at exactly the same point, when I’m calling DIBuilder::finalize but the assertion has changed (but similar)- it is now:
Assertion failed: (isa(Val) && “cast() argument of incompatible type!”), function cast, file /Users/meister/Development/externals-clasp/llvm36/include/llvm/Support/Casting.h, line 237.

Below is some info that may answer your (Duncan and Frederic) questions:

  1. Duncan asked “are you using two different LLVMContexts?”
    Answer: I may be - in frame 6 the DbgNode->Context reference looks mangled

  2. Frederic asked “is TempEnumTypes null at this point”
    Answer: No, it has the value 0x000000011c81fda8

Below is an lldb session where I’m looking at the backtrace.

(lldb) up
frame #4: 0x0000000103de1811 clasp_boehm_d__assert_rtn(func=0x00000001043a5749, file=0x00000001043a574e, line=237, expr=0x00000001043a579f) + 129 at Signals.inc:533 530 else 531 fprintf(stderr, "Assertion failed: (%s), file %s, line %d.\n", 532 expr, file, line); -> 533 abort(); 534 } 535 536 void abort() { (lldb) up frame #5: 0x0000000103cf47dc clasp_boehm_dllvm::cast_retty<llvm::MDNodeFwdDecl, llvm::MDNode*>::ret_type llvm::cast<llvm::MDNodeFwdDecl, llvm::MDNode>(Val=0x000000011c81fda8) + 108 at Casting.h:237
234
235 template <class X, class Y>
236 inline typename cast_retty<X, Y >::ret_type cast(Y Val) {
→ 237 assert(isa(Val) && “cast() argument of incompatible type!”);
238 return cast_convert_val<X, Y
,
239 typename simplify_type<Y
>::SimpleType>::doit(Val);
240 }
(lldb) up
frame #6: 0x0000000103b6bf6a clasp_boehm_d`llvm::DIDescriptor::replaceAllUsesWith(this=0x00007fff5fbdba18, D=0x0000000109d24380) + 218 at DebugInfo.cpp:349
346 void DIDescriptor::replaceAllUsesWith(MDNode *D) {
347 assert(DbgNode && “Trying to replace an unverified type!”);
348 assert(DbgNode != D && “This replacement should always happen”);
→ 349 auto *Node = cast(const_cast<MDNode *>(DbgNode));

According to the backtrace, DbgNode here should be TempEnumTypes. In a correct flow, TempEnumTypes has been initialized by createCompileUnit() to a temporary node (a MDNodeFwdDecl nowadays). This cast should not be able to fail if you have called createCompileUnit() and of course if TempEnumTypes hasn’t been corrupted. Can you check that the value you have at that point is the same that was assigned by createCompileUnit()? If not, then you have your bug (another thought: would it be possible that finalize is called twice on the same CU?).

Fred

Fred and Duncan,

Thank you so very much.
Your advice helped me nail down the problem to either: (1) I’m not calling createCompileUnit or (2) I’m calling finalize twice.

It put in some tests and it turned out that there was a code path where I was calling DIBuilder::finalize twice.
I fixed the problem and now I’m on to the next problem!

Thank you so much.

Best,

.Chris.