Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add simplify ICFG #1386

Merged
merged 22 commits into from
Mar 3, 2024
Merged
11 changes: 9 additions & 2 deletions svf-llvm/tools/AE/ae.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -653,17 +653,24 @@
AndersenWaveDiff* ander = AndersenWaveDiff::createAndersenWaveDiff(pag);
PTACallGraph* callgraph = ander->getPTACallGraph();
builder.updateCallGraph(callgraph);
pag->getICFG()->updateCallGraph(callgraph);
if (Options::SimplifyICFG()) {
ICFGSimplification::simplify(pag->getICFG());
if (Options::DumpSimplifiedICFG())
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we can remove this option and use -dump-icfg as the name of the output icfg.simplify.dot is different from original icfg.dot

pag->getICFG()->dump("ICFG.simplified");

Check warning on line 660 in svf-llvm/tools/AE/ae.cpp

View check run for this annotation

Codecov / codecov/patch

svf-llvm/tools/AE/ae.cpp#L660

Added line #L660 was not covered by tests
}

if (Options::BufferOverflowCheck())
{
BufOverflowChecker ae;
ae.initExtAPI();
ae.runOnModule(pag);
ae.runOnModule(pag->getICFG());
}
else
{
AbstractExecution ae;
ae.initExtAPI();
ae.runOnModule(pag);
ae.runOnModule(pag->getICFG());
}

LLVMModuleSet::releaseLLVMModuleSet();
Expand Down
13 changes: 7 additions & 6 deletions svf/include/AE/Svfexe/AbstractExecution.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,14 +27,13 @@
//
// Created by Jiawei Wang on 2024/1/10.
//
#include <exception>
#include <string>
#include "AE/Core/ICFGWTO.h"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

could we put this header and these two #include "Util/WorkList.h" #include "WPA/Andersen.h" into cpp if their methods are not explicitly used in this header?

#include "AE/Svfexe/ICFGSimplification.h"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

remove this header?

#include "AE/Svfexe/SVFIR2ItvExeState.h"
#include "Util/WorkList.h"
#include "MSSA/SVFGBuilder.h"
#include "AE/Core/ICFGWTO.h"
#include "WPA/Andersen.h"
#include "Util/SVFBugReport.h"
#include "Util/WorkList.h"
#include "WPA/Andersen.h"

namespace SVF
{
Expand Down Expand Up @@ -118,7 +117,7 @@ class AbstractExecution

virtual void initExtAPI();

virtual void runOnModule(SVFIR* svfModule);
virtual void runOnModule(ICFG* icfg);

/// Destructor
virtual ~AbstractExecution();
Expand Down Expand Up @@ -276,6 +275,7 @@ class AbstractExecution
Map<const ICFGNode*, IntervalExeState> _postES;
std::string _moduleName;


};

class AEAPI
Expand Down Expand Up @@ -430,5 +430,6 @@ class AEAPI

Set<const CallICFGNode*> _checkpoints;
Set<std::string> _checkpoint_names;

};
}
307 changes: 307 additions & 0 deletions svf/include/AE/Svfexe/ICFGSimplification.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,307 @@
//===- ICFGSimplification.h -- Simplify ICFG----------------------------------//
//
// SVF: Static Value-Flow Analysis
//
// Copyright (C) <2013-> <Yulei Sui>
//

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.

// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
// The implementation is based on
// Xiao Cheng, Jiawei Wang and Yulei Sui. Precise Sparse Abstract Execution via Cross-Domain Interaction.
// 46th International Conference on Software Engineering. (ICSE24)
//===----------------------------------------------------------------------===//


//
// Created by Jiawei Wang on 2024/2/25.
//
#include "Graphs/ICFG.h"
#include "AE/Svfexe/SVFIR2ItvExeState.h"


namespace SVF
{

class ICFGSimplification
{
public:
ICFGSimplification() = default;

virtual ~ICFGSimplification() = default;

static void simplify(ICFG* icfg)
{
Map<const SVFBasicBlock*, std::vector<const ICFGNode*>> bbToNodes;
Set<ICFGNode*> rm_nodes;
Set<const ICFGNode*> simplifiedNodes;
for (const auto& func : *PAG::getPAG()->getModule())
{
for (const auto& bb : *func)
{
for (const auto& inst : *bb)
{
if (SVFUtil::isIntrinsicInst(inst))
continue;
const ICFGNode* icfgNode = icfg->getICFGNode(inst);
// e.g.
// block: entry
// insts: call = i32 %fun(i32 %arg)
// We put the callnode in an icfgnode alone, and the retnode is similar.
if (const CallICFGNode* callNode =
SVFUtil::dyn_cast<CallICFGNode>(icfgNode))
{
icfg->appendSubNode(callNode, callNode);
icfg->addRepNode(callNode, callNode);
bbToNodes[bb].push_back(callNode);
simplifiedNodes.insert(callNode);

const RetICFGNode* retNode = callNode->getRetICFGNode();
icfg->appendSubNode(retNode, retNode);
icfg->addRepNode(retNode, retNode);
bbToNodes[bb].push_back(retNode);
simplifiedNodes.insert(retNode);
}
else
{
// For ordinary instructions, we put multiple instructions in an ICFGNode
if (bbToNodes.find(bb) == bbToNodes.end())
{
icfg->appendSubNode(icfgNode, icfgNode);
icfg->addRepNode(icfgNode, icfgNode);
bbToNodes[bb] = {icfgNode};
simplifiedNodes.insert(icfgNode);
}
else
{
const ICFGNode* pNode = bbToNodes[bb].back();
if (!SVFUtil::isa<RetICFGNode>(pNode))
{
icfg->appendSubNode(pNode, icfgNode);
icfg->addRepNode(icfgNode, pNode);
}
else
{
icfg->appendSubNode(icfgNode, icfgNode);
icfg->addRepNode(icfgNode, icfgNode);
bbToNodes[bb].push_back(icfgNode);
simplifiedNodes.insert(icfgNode);
}
}
}
}
}

if (const FunEntryICFGNode* funEntryNode =
icfg->getFunEntryICFGNode(func))
{
if (const SVFBasicBlock* bb = funEntryNode->getBB())
{
std::vector<const ICFGNode*>& nodes = bbToNodes[bb];
icfg->appendSubNode(funEntryNode, funEntryNode);
icfg->addRepNode(funEntryNode, funEntryNode);
nodes.insert(nodes.begin(), funEntryNode);
simplifiedNodes.insert(funEntryNode);
}
}
if (const FunExitICFGNode* funExitNode = icfg->getFunExitICFGNode(func))
{
if (const SVFBasicBlock* bb = funExitNode->getBB())
{
std::vector<const ICFGNode*>& nodes = bbToNodes[bb];
icfg->appendSubNode(funExitNode, funExitNode);
icfg->addRepNode(funExitNode, funExitNode);
nodes.push_back(funExitNode);
simplifiedNodes.insert(funExitNode);
}
}
}

for (auto &it: *icfg) {
if (simplifiedNodes.find(it.second) == simplifiedNodes.end() &&
!SVFUtil::isa<GlobalICFGNode>(it.second)) {
rm_nodes.insert(const_cast<ICFGNode*>(it.second));
}
}

/// reconnect the ICFGNodes,
/// 1. intraCFGEdges between different basicblocks, but in the safe function e.g. entry:
/// cond = icmp eq i32 %a, 0 ---------> srcblk
/// br i1 cond, label %bb1, label %bb2 ---------> srcblk_tail
/// bb1:
/// ... --------> dstblk
/// bb2:
/// ... --------> another dstblk
/// tmpEdge is the edge between srcblk and dstblk, may have condition var (cond is true or false)
for (const auto& node : *icfg)
{
for (const auto& succ : node.second->getOutEdges())
{
if (succ->isIntraCFGEdge())
{
const SVFFunction* node_fun = node.second->getFun();
const SVFFunction* succ_fun = succ->getDstNode()->getFun();
const SVFBasicBlock* node_bb = node.second->getBB();
const SVFBasicBlock* succ_bb = succ->getDstNode()->getBB();
if (node_fun == succ_fun)
{
if (node_bb != succ_bb)
{
ICFGNode* srcblk = const_cast<ICFGNode*>(
bbToNodes[node_bb].back());
ICFGNode* dstblk = const_cast<ICFGNode*>(
bbToNodes[succ_bb].front());
ICFGNode* srcblk_tail = const_cast<ICFGNode*>(
icfg->getSubNodes(bbToNodes[node_bb].back()).back());
ICFGEdge* tmpEdge =
icfg->getICFGEdge(srcblk_tail, dstblk,
ICFGEdge::ICFGEdgeK::IntraCF);
IntraCFGEdge* pEdge = nullptr;
if (tmpEdge)
{
IntraCFGEdge* intraEdge =
SVFUtil::dyn_cast<IntraCFGEdge>(tmpEdge);
pEdge = new IntraCFGEdge(srcblk, dstblk);
if (intraEdge->getCondition())
pEdge->setBranchCondition(
intraEdge->getCondition(),
intraEdge->getSuccessorCondValue());
}
else
{
pEdge = new IntraCFGEdge(srcblk, dstblk);
}
// avoid duplicate edges
if (srcblk->hasIncomingEdge(pEdge) ||
dstblk->hasIncomingEdge(pEdge))
continue;
else
icfg->addICFGEdge(pEdge);
}
}
}
}
}

/// 2. intraCFGEdges in the same basicblock, but seperated by callInst
/// e.g. entry:
/// ..... --------> bbNode0
/// call void @foo() ---------> callNode: bbNode1, retNode bbNode2
/// ..... --------> bbNode3
/// entry block has 4 bbNodes. the following for loop just links bbNodes in the same basic block.
for (const auto& bbNodes : bbToNodes)
{
for (u32_t i = 0; i < bbNodes.second.size() - 1; ++i)
{
ICFGNode* srcblk_tail =
const_cast<ICFGNode*>(icfg->getSubNodes(bbNodes.second[i]).back());
ICFGNode* srcblk = const_cast<ICFGNode*>(bbNodes.second[i]);
ICFGNode* dstblk = const_cast<ICFGNode*>(bbNodes.second[i + 1]);
if (!icfg->hasIntraICFGEdge(srcblk_tail, dstblk,
ICFGEdge::ICFGEdgeK::IntraCF))
continue;
IntraCFGEdge* pEdge = new IntraCFGEdge(srcblk, dstblk);
if (srcblk->hasIncomingEdge(pEdge) ||
dstblk->hasIncomingEdge(pEdge))
continue;
else
icfg->addICFGEdge(pEdge);
}
}

/// 3. CallCFGEdges and RetCFGEdges
/// CallEdge is the edge between CallNode and FunEntryNode.
/// RetEdge is the edge between FunExitNode and RetNode.

for (const auto& bbNodes : bbToNodes)
{
for (u32_t i = 0; i < bbNodes.second.size(); ++i)
{
if (const CallICFGNode* callICFGNode =
SVFUtil::dyn_cast<CallICFGNode>(bbNodes.second[i]))
{
for (const auto& icfgEdge : callICFGNode->getOutEdges())
{
if (const CallCFGEdge* callEdge =
SVFUtil::dyn_cast<CallCFGEdge>(icfgEdge))
{
ICFGNode* srcblk =
const_cast<ICFGNode*>(bbNodes.second[i]);
ICFGNode* dstblk =
const_cast<ICFGNode*>(callEdge->getDstNode());
ICFGEdge* pEdge = new ICFGEdge(
srcblk, dstblk, ICFGEdge::ICFGEdgeK::CallCF);
if (srcblk->hasIncomingEdge(pEdge) ||
dstblk->hasIncomingEdge(pEdge))
continue;
else
icfg->addICFGEdge(pEdge);

Check warning on line 249 in svf/include/AE/Svfexe/ICFGSimplification.h

View check run for this annotation

Codecov / codecov/patch

svf/include/AE/Svfexe/ICFGSimplification.h#L249

Added line #L249 was not covered by tests
}
}
}
else if (const RetICFGNode* retICFGNode =
SVFUtil::dyn_cast<RetICFGNode>(bbNodes.second[i]))
{
for (const auto& icfgEdge : retICFGNode->getInEdges())
{
if (const RetCFGEdge* retEdge =
SVFUtil::dyn_cast<RetCFGEdge>(icfgEdge))
{
if (!retEdge->getSrcNode()->getFun()->hasReturn())
continue;

Check warning on line 262 in svf/include/AE/Svfexe/ICFGSimplification.h

View check run for this annotation

Codecov / codecov/patch

svf/include/AE/Svfexe/ICFGSimplification.h#L262

Added line #L262 was not covered by tests
ICFGNode* srcblk =
const_cast<ICFGNode*>(retEdge->getSrcNode());
ICFGNode* dstblk =
const_cast<ICFGNode*>(bbNodes.second[i]);
ICFGEdge* pEdge = new ICFGEdge(
srcblk, dstblk, ICFGEdge::ICFGEdgeK::RetCF);
if (srcblk->hasIncomingEdge(pEdge) ||
dstblk->hasIncomingEdge(pEdge))
continue;
else
icfg->addICFGEdge(pEdge);

Check warning on line 273 in svf/include/AE/Svfexe/ICFGSimplification.h

View check run for this annotation

Codecov / codecov/patch

svf/include/AE/Svfexe/ICFGSimplification.h#L273

Added line #L273 was not covered by tests
}
}
}
else
{
}
}
}
for (auto& it : rm_nodes)
{
ICFGNode* node = it;
Set<ICFGEdge*> rm_outedges, rm_inedges;
for (ICFGEdge* edge : node->getOutEdges())
{
rm_outedges.insert(edge);
}
for (ICFGEdge* edge : node->getInEdges())
{
rm_inedges.insert(edge);
}
for (ICFGEdge* edge : rm_outedges)
{
node->removeOutgoingEdge(edge);
edge->getDstNode()->removeIncomingEdge(edge);
}
for (ICFGEdge* edge : rm_inedges)
{
node->removeIncomingEdge(edge);
edge->getSrcNode()->removeOutgoingEdge(edge);
}
}
}
};
}
Loading
Loading