Skip to content

Commit

Permalink
fix a bug: 'getExitBB' of SVFFunction may get incorrect exit block. (#…
Browse files Browse the repository at this point in the history
…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
  • Loading branch information
canliture authored Dec 1, 2023
1 parent 595665b commit ccbff5c
Show file tree
Hide file tree
Showing 6 changed files with 62 additions and 12 deletions.
3 changes: 3 additions & 0 deletions svf-llvm/include/SVF-LLVM/LLVMUtil.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
11 changes: 11 additions & 0 deletions svf-llvm/lib/LLVMModule.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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;
Expand Down
22 changes: 17 additions & 5 deletions svf-llvm/lib/LLVMUtil.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,24 @@ void LLVMUtil::getFunReachableBBs (const Function* fun, std::vector<const SVFBas
}
}

/**
* Return true if the basic block has a return instruction
*/
bool LLVMUtil::basicBlockHasRetInst(const BasicBlock* bb)
{
for (BasicBlock::const_iterator it = bb->begin(), eit = bb->end();
it != eit; ++it)
{
if(SVFUtil::isa<ReturnInst>(*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))
Expand All @@ -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<ReturnInst>(*it))
return false;
return false;
}

for (succ_const_iterator sit = succ_begin(bb), esit = succ_end(bb);
Expand Down
15 changes: 13 additions & 2 deletions svf/include/SVFIR/SVFValue.h
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,7 @@ class SVFFunction : public SVFValue
std::vector<const SVFBasicBlock*> allBBs; /// all BasicBlocks of this function
std::vector<const SVFArgument*> allArgs; /// all formal arguments of this function
std::vector<std::string> 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
Expand Down Expand Up @@ -412,20 +413,29 @@ 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();
}

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
Expand Down Expand Up @@ -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 SVFInstruction*>::const_iterator const_iterator;
Expand Down
14 changes: 10 additions & 4 deletions svf/lib/Graphs/ICFG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
}
}
}

Expand Down Expand Up @@ -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();
Expand Down
9 changes: 8 additions & 1 deletion svf/lib/SVFIR/SVFValue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,8 @@ SVFFunction::SVFFunction(const SVFType* ty, const SVFFunctionType* ft,
SVFLoopAndDomInfo* ld, std::vector<std::string> 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)
{
}

Expand Down Expand Up @@ -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)
{
Expand Down

0 comments on commit ccbff5c

Please sign in to comment.