From ccbff5c73f7d15500c8c4d4fa241c7ba0d1b3b3c Mon Sep 17 00:00:00 2001 From: canliture Date: Thu, 30 Nov 2023 22:39:23 -0600 Subject: [PATCH] fix a bug: 'getExitBB' of SVFFunction may get incorrect exit block. (#1262) * fix a bug: 'getExitBlock' of SVFFunction may get incorrect exit block. * handle multi exit basic blocks: introduce a unique exit basic block, and connect all exit basic blocks to it. * 1. remove redundant entry block setting 2. setting exit block more concisely * remove assert about nullness of exit basic block * revise assertion:When caller calls 'getExitBB', let caller ensures the function must have return instruction * make recognizing exit basic block more robust * fix crash: ensure the function has an exit basic block * fix incorrect recognizing exit basic block * revise assert about SVFFunction#back() * fix a crash: before call SVFFunction#getExitBB, need to ensure the function has ret instruction * more clearly setting exit Basic Block * remove redundant method 'hasReturn' in class SVFFunction --- svf-llvm/include/SVF-LLVM/LLVMUtil.h | 3 +++ svf-llvm/lib/LLVMModule.cpp | 11 +++++++++++ svf-llvm/lib/LLVMUtil.cpp | 22 +++++++++++++++++----- svf/include/SVFIR/SVFValue.h | 15 +++++++++++++-- svf/lib/Graphs/ICFG.cpp | 14 ++++++++++---- svf/lib/SVFIR/SVFValue.cpp | 9 ++++++++- 6 files changed, 62 insertions(+), 12 deletions(-) diff --git a/svf-llvm/include/SVF-LLVM/LLVMUtil.h b/svf-llvm/include/SVF-LLVM/LLVMUtil.h index fc1d8f08f..924839b2f 100644 --- a/svf-llvm/include/SVF-LLVM/LLVMUtil.h +++ b/svf-llvm/include/SVF-LLVM/LLVMUtil.h @@ -205,6 +205,9 @@ inline bool isArgOfUncalledFunction (const Value* val) } //@} +/// Return true if the function has a return instruction +bool basicBlockHasRetInst(const BasicBlock* bb); + /// Return true if the function has a return instruction reachable from function /// entry bool functionDoesNotRet(const Function* fun); diff --git a/svf-llvm/lib/LLVMModule.cpp b/svf-llvm/lib/LLVMModule.cpp index 9aeda6c37..bec5118a6 100644 --- a/svf-llvm/lib/LLVMModule.cpp +++ b/svf-llvm/lib/LLVMModule.cpp @@ -305,6 +305,7 @@ void LLVMModuleSet::initSVFFunction() void LLVMModuleSet::initSVFBasicBlock(const Function* func) { + SVFFunction *svfFun = getSVFFunction(func); for (Function::const_iterator bit = func->begin(), ebit = func->end(); bit != ebit; ++bit) { const BasicBlock* bb = &*bit; @@ -319,6 +320,16 @@ void LLVMModuleSet::initSVFBasicBlock(const Function* func) const SVFBasicBlock* svf_pred_bb = getSVFBasicBlock(*pred_it); svfbb->addPredBasicBlock(svf_pred_bb); } + + /// set exit block: exit basic block must have no successors and have a return instruction + if (svfbb->getSuccessors().empty()) + { + if (LLVMUtil::basicBlockHasRetInst(bb)) + { + svfFun->setExitBlock(svfbb); + } + } + for (BasicBlock::const_iterator iit = bb->begin(), eiit = bb->end(); iit != eiit; ++iit) { const Instruction* inst = &*iit; diff --git a/svf-llvm/lib/LLVMUtil.cpp b/svf-llvm/lib/LLVMUtil.cpp index ece420bef..613c9c447 100644 --- a/svf-llvm/lib/LLVMUtil.cpp +++ b/svf-llvm/lib/LLVMUtil.cpp @@ -98,10 +98,24 @@ void LLVMUtil::getFunReachableBBs (const Function* fun, std::vectorbegin(), eit = bb->end(); + it != eit; ++it) + { + if(SVFUtil::isa(*it)) + return true; + } + return false; +} + /*! * Return true if the function has a return instruction reachable from function entry */ -bool LLVMUtil::functionDoesNotRet (const Function* fun) +bool LLVMUtil::functionDoesNotRet(const Function* fun) { const SVFFunction* svffun = LLVMModuleSet::getLLVMModuleSet()->getSVFFunction(fun); if (SVFUtil::isExtCall(svffun)) @@ -115,11 +129,9 @@ bool LLVMUtil::functionDoesNotRet (const Function* fun) { const BasicBlock* bb = bbVec.back(); bbVec.pop_back(); - for (BasicBlock::const_iterator it = bb->begin(), eit = bb->end(); - it != eit; ++it) + if (basicBlockHasRetInst(bb)) { - if(SVFUtil::isa(*it)) - return false; + return false; } for (succ_const_iterator sit = succ_begin(bb), esit = succ_end(bb); diff --git a/svf/include/SVFIR/SVFValue.h b/svf/include/SVFIR/SVFValue.h index f300c4c6d..302f3d5c5 100644 --- a/svf/include/SVFIR/SVFValue.h +++ b/svf/include/SVFIR/SVFValue.h @@ -320,6 +320,7 @@ class SVFFunction : public SVFValue std::vector allBBs; /// all BasicBlocks of this function std::vector allArgs; /// all formal arguments of this function std::vector annotations; /// annotations of this function + SVFBasicBlock *exitBlock; /// a 'single' basic block having no successors and containing return instruction in a function protected: ///@{ attributes to be set only through Module builders e.g., LLVMModule @@ -412,12 +413,17 @@ class SVFFunction : public SVFValue return allBBs.front(); } + /// Carefully! when you call getExitBB, you need ensure the function has return instruction + /// more refer to: https://github.com/SVF-tools/SVF/pull/1262 inline const SVFBasicBlock* getExitBB() const { assert(hasBasicBlock() && "function does not have any Basicblock, external function?"); - return allBBs.back(); + assert((!isNotRet && exitBlock) && "ensure the function has a single basic block containing a return instruction!"); + return exitBlock; } + void setExitBlock(SVFBasicBlock *bb); + inline const SVFBasicBlock* front() const { return getEntryBlock(); @@ -425,7 +431,11 @@ class SVFFunction : public SVFValue inline const SVFBasicBlock* back() const { - return getExitBB(); + assert(hasBasicBlock() && "function does not have any Basicblock, external function?"); + /// Carefully! 'back' is just the last basic block of function, + /// but not necessarily a exit basic block + /// more refer to: https://github.com/SVF-tools/SVF/pull/1262 + return allBBs.back(); } inline const_iterator begin() const @@ -520,6 +530,7 @@ class SVFBasicBlock : public SVFValue friend class SVFIRWriter; friend class SVFIRReader; friend class SVFIRBuilder; + friend class SVFFunction; public: typedef std::vector::const_iterator const_iterator; diff --git a/svf/lib/Graphs/ICFG.cpp b/svf/lib/Graphs/ICFG.cpp index ef983c6ca..3f69121a1 100644 --- a/svf/lib/Graphs/ICFG.cpp +++ b/svf/lib/Graphs/ICFG.cpp @@ -54,7 +54,11 @@ FunExitICFGNode::FunExitICFGNode(NodeID id, const SVFFunction* f) // if function is implemented if (f->begin() != f->end()) { - bb = f->getExitBB(); + // ensure the enclosing function has exit basic block + if (!f->isNotRetFunction()) + { + bb = f->getExitBB(); + } } } @@ -112,12 +116,14 @@ const std::string FunEntryICFGNode::toString() const const std::string FunExitICFGNode::toString() const { + const SVFFunction *fun = getFun(); std::string str; std::stringstream rawstr(str); rawstr << "FunExitICFGNode" << getId(); - rawstr << " {fun: " << getFun()->getName(); - if (isExtCall(getFun())==false) - rawstr << getFun()->getExitBB()->front()->getSourceLoc(); + rawstr << " {fun: " << fun->getName(); + // ensure the enclosing function has exit basic block + if (!isExtCall(fun) && !fun->isNotRetFunction()) + rawstr << fun->getExitBB()->front()->getSourceLoc(); rawstr << "}"; for (const SVFStmt *stmt : getSVFStmts()) rawstr << "\n" << stmt->toString(); diff --git a/svf/lib/SVFIR/SVFValue.cpp b/svf/lib/SVFIR/SVFValue.cpp index 14744b41f..106823254 100644 --- a/svf/lib/SVFIR/SVFValue.cpp +++ b/svf/lib/SVFIR/SVFValue.cpp @@ -160,7 +160,8 @@ SVFFunction::SVFFunction(const SVFType* ty, const SVFFunctionType* ft, SVFLoopAndDomInfo* ld, std::vector annos) : SVFValue(ty, SVFValue::SVFFunc), isDecl(declare), intrinsic(intrinsic), addrTaken(adt), isUncalled(false), isNotRet(false), varArg(varg), - funcType(ft), loopAndDom(ld), realDefFun(nullptr), annotations(std::move(annos)) + funcType(ft), loopAndDom(ld), realDefFun(nullptr), annotations(std::move(annos)), + exitBlock(nullptr) { } @@ -189,6 +190,12 @@ bool SVFFunction::isVarArg() const return varArg; } +void SVFFunction::setExitBlock(SVFBasicBlock *bb) +{ + assert(!exitBlock && "have already set exit Basicblock!"); + exitBlock = bb; +} + SVFBasicBlock::SVFBasicBlock(const SVFType* ty, const SVFFunction* f) : SVFValue(ty, SVFValue::SVFBB), fun(f) {