diff --git a/svf-llvm/lib/SVFIRBuilder.cpp b/svf-llvm/lib/SVFIRBuilder.cpp index f774308a1..5bcc6cf41 100644 --- a/svf-llvm/lib/SVFIRBuilder.cpp +++ b/svf-llvm/lib/SVFIRBuilder.cpp @@ -681,9 +681,15 @@ bool SVFIRBuilder::computeGepOffset(const User *V, AccessPath& ap) if(const ArrayType* arrTy = SVFUtil::dyn_cast(gepTy)) { if (!Options::ModelArrays() && arrTy->getElementType()->isPointerTy()) + { + if(Options::FieldSensitiveSound()) isConst = false; continue; + } if(!op || (arrTy->getArrayNumElements() <= (u32_t)LLVMUtil::getIntegerValue(op).first)) + { + if(Options::FieldSensitiveSound()) isConst = false; continue; + } APOffset idx = (u32_t)LLVMUtil::getIntegerValue(op).first; u32_t offset = pag->getFlattenedElemIdx(llvmModuleSet()->getSVFType(arrTy), idx); ap.setFldIdx(ap.getConstantStructFldIdx() + offset); @@ -730,6 +736,9 @@ bool SVFIRBuilder::computeGepOffset(const User *V, AccessPath& ap) // For pointer arithmetic we ignore the byte offset // consider using inferFieldIdxFromByteOffset(geopOp,dataLayout,ap,idx)? // ap.setFldIdx(ap.getConstantFieldIdx() + inferFieldIdxFromByteOffset(geopOp,idx)); + + // For soundness, if ap.setFldIdx is not called, then we consider it as a non-constant access + if(Options::FieldSensitiveSound()) isConst = false; } } return isConst; diff --git a/svf/include/SVFIR/SVFVariables.h b/svf/include/SVFIR/SVFVariables.h index 8711a7c2c..3310597c0 100644 --- a/svf/include/SVFIR/SVFVariables.h +++ b/svf/include/SVFIR/SVFVariables.h @@ -507,10 +507,7 @@ class GepValVar: public ValVar std::to_string(getConstantFieldIdx()); } - virtual bool isPointer() const - { - return base->isPointer(); - } + virtual inline bool isPointer() const; inline const SVFType* getType() const { @@ -852,10 +849,7 @@ class GepObjVar: public ObjVar return base->isConstDataOrAggDataButNotNullPtr(); } - virtual bool isPointer() const - { - return base->isPointer(); - } + virtual inline bool isPointer() const; }; diff --git a/svf/include/Util/Options.h b/svf/include/Util/Options.h index 978efa488..a67c9e4ba 100644 --- a/svf/include/Util/Options.h +++ b/svf/include/Util/Options.h @@ -33,6 +33,9 @@ class Options /// Maximum number of field derivations for an object. static const Option MaxFieldLimit; + /// Ensure field-sensitive soundness. + static const Option FieldSensitiveSound; + /// Whether to stage Andersen's with Steensgaard and cluster based on that data. static const Option ClusterAnder; diff --git a/svf/lib/MemoryModel/PointerAnalysis.cpp b/svf/lib/MemoryModel/PointerAnalysis.cpp index 53a864e54..4349e8962 100644 --- a/svf/lib/MemoryModel/PointerAnalysis.cpp +++ b/svf/lib/MemoryModel/PointerAnalysis.cpp @@ -430,34 +430,35 @@ void PointerAnalysis::getVFnsFromCHA(const CallICFGNode* cs, VFunSet &vfns) */ void PointerAnalysis::getVFnsFromPts(const CallICFGNode* cs, const PointsTo &target, VFunSet &vfns) { - - if (chgraph->csHasVtblsBasedonCHA(cs)) + // CHA vtables sometimes cannot be resolved (for a virtual call) + // When CHA vtables can be resolved, use CHA vtables to filter the target points-to set + // Otherwise, use the points-to set from the pointer analysis + const VTableSet *pChaVtbls = chgraph->csHasVtblsBasedonCHA(cs) ? + &chgraph->getCSVtblsBasedonCHA(cs) : + nullptr; + if (!pChaVtbls && !Options::FieldSensitiveSound()) return; + Set vtbls; + for (PointsTo::iterator it = target.begin(), eit = target.end(); it != eit; ++it) { - Set vtbls; - const VTableSet &chaVtbls = chgraph->getCSVtblsBasedonCHA(cs); - for (PointsTo::iterator it = target.begin(), eit = target.end(); it != eit; ++it) + const SVFVar* ptdnode = pag->getSVFVar(*it); + const GlobalObjVar* pVar = nullptr; + if (isa(ptdnode) && isa(pag->getBaseObject(ptdnode->getId()))) { - const SVFVar* ptdnode = pag->getSVFVar(*it); - const GlobalObjVar* pVar = nullptr; - if (isa(ptdnode) && isa(pag->getBaseObject(ptdnode->getId()))) - { - pVar = cast(pag->getBaseObject(ptdnode->getId())); - - } - else if (isa(ptdnode) && - isa( - pag->getBaseValVar(ptdnode->getId()))) - { - pVar = cast( - SVFUtil::getObjVarOfValVar(cast( - pag->getBaseValVar(ptdnode->getId())))); - } - - if (pVar && chaVtbls.find(pVar) != chaVtbls.end()) - vtbls.insert(pVar); + pVar = cast(pag->getBaseObject(ptdnode->getId())); } - chgraph->getVFnsFromVtbls(cs, vtbls, vfns); + else if (isa(ptdnode) && + isa( + pag->getBaseValVar(ptdnode->getId()))) + { + pVar = cast( + SVFUtil::getObjVarOfValVar(cast( + pag->getBaseValVar(ptdnode->getId())))); + } + + if (pVar && (!pChaVtbls || pChaVtbls->find(pVar) != pChaVtbls->end())) + vtbls.insert(pVar); } + chgraph->getVFnsFromVtbls(cs, vtbls, vfns); } /* diff --git a/svf/lib/SVFIR/SVFVariables.cpp b/svf/lib/SVFIR/SVFVariables.cpp index 51e81bf4c..d8f0d8a9d 100644 --- a/svf/lib/SVFIR/SVFVariables.cpp +++ b/svf/lib/SVFIR/SVFVariables.cpp @@ -212,6 +212,13 @@ const std::string GepValVar::toString() const return rawstr.str(); } +bool GepValVar::isPointer() const +{ + if (Options::FieldSensitiveSound()) + return true; + return base->isPointer(); +} + RetValPN::RetValPN(NodeID i, const FunObjVar* node, const SVFType* svfType, const ICFGNode* icn) : ValVar(i, svfType, icn, RetValNode), callGraphNode(node) { @@ -253,6 +260,13 @@ const SVFType *GepObjVar::getType() const return SVFIR::getPAG()->getFlatternedElemType(type, apOffset); } +bool GepObjVar::isPointer() const +{ + if (Options::FieldSensitiveSound()) + return true; + return base->isPointer(); +} + bool BaseObjVar::isBlackHoleObj() const { return IRGraph::isBlkObj(getId()); diff --git a/svf/lib/Util/Options.cpp b/svf/lib/Util/Options.cpp index 4e15f9236..47f6ccc4d 100644 --- a/svf/lib/Util/Options.cpp +++ b/svf/lib/Util/Options.cpp @@ -45,6 +45,12 @@ const Option Options::MaxFieldLimit( 512 ); +const Option Options::FieldSensitiveSound( + "fs-sound", + "Ensure field-sensitive soundness", + false +); + const OptionMap Options::ptDataBacking( "ptd", "Overarching points-to data structure",