Skip to content

Commit 78dca61

Browse files
authored
Merge pull request #1774 from FXTi/master
Fix isSameThisPtrInConstructor for LLVM 15+ opaque pointers
2 parents 80c478f + f992104 commit 78dca61

File tree

2 files changed

+85
-15
lines changed

2 files changed

+85
-15
lines changed

svf-llvm/lib/CHGBuilder.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -174,10 +174,9 @@ void CHGBuilder::connectInheritEdgeViaCall(const Function* caller, const CallBas
174174
if (cs->arg_size() < 1 || (cs->arg_size() < 2 && cs->paramHasAttr(0, llvm::Attribute::StructRet)))
175175
return;
176176
const Value* csThisPtr = cppUtil::getVCallThisPtr(cs);
177-
//const Argument* consThisPtr = getConstructorThisPtr(caller);
178-
//bool samePtr = isSameThisPtrInConstructor(consThisPtr, csThisPtr);
179-
bool samePtrTrue = true;
180-
if (csThisPtr != nullptr && samePtrTrue)
177+
const Argument* consThisPtr = getConstructorThisPtr(caller);
178+
bool samePtr = isSameThisPtrInConstructor(consThisPtr, csThisPtr);
179+
if (csThisPtr != nullptr && samePtr)
181180
{
182181
struct DemangledName basename = demangle(callee->getName().str());
183182
if (!LLVMUtil::isCallSite(csThisPtr) &&

svf-llvm/lib/CppUtil.cpp

Lines changed: 82 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -420,25 +420,92 @@ const Value* cppUtil::getVCallThisPtr(const CallBase* cs)
420420
}
421421
}
422422

423+
/// Check if V is derived from thisPtr
424+
/// Handles O0 pattern: %this1 = load ptr, ptr %this.addr
425+
static bool isDerivedFromThisPtr(const Argument* thisPtr, const Value* V)
426+
{
427+
V = V->stripPointerCasts();
428+
if (V == thisPtr)
429+
return true;
430+
431+
if (const LoadInst* load = SVFUtil::dyn_cast<LoadInst>(V))
432+
{
433+
if (const AllocaInst* alloca =
434+
SVFUtil::dyn_cast<AllocaInst>(load->getPointerOperand()))
435+
{
436+
for (const User* U : alloca->users())
437+
{
438+
if (const StoreInst* store = SVFUtil::dyn_cast<StoreInst>(U))
439+
{
440+
if (store->getPointerOperand() == alloca &&
441+
store->getValueOperand()->stripPointerCasts() == thisPtr)
442+
return true;
443+
}
444+
}
445+
}
446+
}
447+
return false;
448+
}
449+
423450
/*!
424-
* Given a inheritance relation B is a child of A
451+
* Given an inheritance relation B is a child of A
425452
* We assume B::B(thisPtr1){ A::A(thisPtr2) } such that thisPtr1 == thisPtr2
426-
* In the following code thisPtr1 is "%class.B1* %this" and thisPtr2 is
427-
* "%class.A* %0".
428453
*
454+
* === Typed pointer mode ===
455+
* %this.addr = alloca %class.B1*
456+
* store %class.B1* %this, %class.B1** %this.addr
457+
* %this1 = load %class.B1*, %class.B1** %this.addr
458+
* %0 = bitcast %class.B1* %this1 to %class.A*
459+
* call void @A::A()(%class.A* %0)
429460
*
430-
* define linkonce_odr dso_local void @B1::B1()(%class.B1* %this) unnamed_addr #6 comdat
431-
* %this.addr = alloca %class.B1*, align 8
432-
* store %class.B1* %this, %class.B1** %this.addr, align 8
433-
* %this1 = load %class.B1*, %class.B1** %this.addr, align 8
434-
* %0 = bitcast %class.B1* %this1 to %class.A*
435-
* call void @A::A()(%class.A* %0)
461+
* === Opaque pointer mode ===
462+
*
463+
* Case 1: Primary base class (offset 0) at O1+
464+
* call ptr @Base::Base(ptr %this)
465+
* → thisPtr2 == thisPtr1, return true
466+
*
467+
* Case 2: Primary base class (offset 0) at O0
468+
* %this.addr = alloca ptr
469+
* store ptr %this, ptr %this.addr
470+
* %this1 = load ptr, ptr %this.addr
471+
* call void @Base::Base(ptr %this1)
472+
* → thisPtr2 is LoadInst from alloca storing thisPtr1, return true
473+
*
474+
* Case 3: Non-primary base class (multiple inheritance, offset > 0)
475+
* %0 = getelementptr inbounds i8, ptr %this1, i64 4
476+
* call void @Base2::Base2(ptr %0)
477+
* → i8 GEP from this, return true
478+
*
479+
* Case 4: Member field initialization (NOT base class)
480+
* %mem = getelementptr inbounds %struct.Derived, ptr %this1, i32 0, i32 1
481+
* call void @Member::Member(ptr %mem)
482+
* → struct GEP from this, return false
436483
*/
437484
bool cppUtil::isSameThisPtrInConstructor(const Argument* thisPtr1,
438485
const Value* thisPtr2)
439486
{
440487
if (thisPtr1 == thisPtr2)
441488
return true;
489+
490+
const Value* stripped = thisPtr2->stripPointerCasts();
491+
if (stripped == thisPtr1)
492+
return true;
493+
494+
// === Opaque pointer: Load from this.addr (Case 2: primary base at O0) ===
495+
if (isDerivedFromThisPtr(thisPtr1, stripped))
496+
return true;
497+
498+
// === Opaque pointer: GEP check (Case 3 & 4) ===
499+
if (const GetElementPtrInst* GEP = SVFUtil::dyn_cast<GetElementPtrInst>(stripped))
500+
{
501+
if (!isDerivedFromThisPtr(thisPtr1, GEP->getPointerOperand()))
502+
return false;
503+
// i8 GEP = non-primary base class (Case 3)
504+
// struct GEP = member field (Case 4)
505+
return GEP->getSourceElementType()->isIntegerTy(8);
506+
}
507+
508+
// === Typed pointer (legacy): store -> load -> bitcast ===
442509
for (const Value* thisU : thisPtr1->users())
443510
{
444511
if (const StoreInst* store = SVFUtil::dyn_cast<StoreInst>(thisU))
@@ -463,7 +530,11 @@ const Argument* cppUtil::getConstructorThisPtr(const Function* fun)
463530
assert((isConstructor(fun) || isDestructor(fun)) &&
464531
"not a constructor?");
465532
assert(fun->arg_size() >= 1 && "argument size >= 1?");
466-
const Argument* thisPtr = &*(fun->arg_begin());
533+
const bool isStructRet = fun->hasParamAttribute(0, llvm::Attribute::StructRet);
534+
assert((isStructRet ? fun->arg_size() >= 2 : true) &&
535+
"argument size for struct ret constructor >= 2?");
536+
const Argument* thisPtr = isStructRet ?
537+
fun->getArg(1) : fun->getArg(0);
467538
return thisPtr;
468539
}
469540

@@ -936,4 +1007,4 @@ const Type *cppUtil::cppClsNameToType(const std::string &className)
9361007
StructType *classTy = StructType::getTypeByName(LLVMModuleSet::getLLVMModuleSet()->getContext(),
9371008
clsName + className);
9381009
return classTy ? classTy : LLVMModuleSet::getLLVMModuleSet()->getTypeInference()->ptrType();
939-
}
1010+
}

0 commit comments

Comments
 (0)