@@ -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 */
437484bool 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