Skip to content

Commit

Permalink
SVF: Use our CallGraph when SVF's is not sufficient
Browse files Browse the repository at this point in the history
  • Loading branch information
lzaoral committed Nov 18, 2021
1 parent 5a1a85c commit 01c0d7d
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 30 deletions.
3 changes: 3 additions & 0 deletions include/dg/llvm/LLVMDependenceGraph.h
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,9 @@ class LLVMDependenceGraph : public DependenceGraph<LLVMNode> {
void handleInstruction(llvm::Value *val, LLVMNode *node,
LLVMNode *prevNode);

void handleCalledFunction(const llvm::CallInst *CInst,
const llvm::Function *F, LLVMNode *node);

// convert llvm basic block to our basic block
// That includes creating all the nodes and adding them
// to this graph and creating the basic block and
Expand Down
14 changes: 14 additions & 0 deletions include/dg/llvm/PointerAnalysis/SVFPointerAnalysis.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@

#include "dg/PointerAnalysis/Pointer.h"

#include "dg/llvm/CallGraph/CallGraph.h"

#include "dg/llvm/PointerAnalysis/LLVMPointerAnalysisOptions.h"
#include "dg/llvm/PointerAnalysis/LLVMPointsToSet.h"
#include "dg/llvm/PointerAnalysis/PointerAnalysis.h"
Expand All @@ -23,6 +25,7 @@

namespace dg {

using llvmdg::LazyLLVMCallGraph;
using pta::Pointer;

using SVF::LLVMModuleSet;
Expand Down Expand Up @@ -96,6 +99,7 @@ class SVFPointerAnalysis : public LLVMPointerAnalysis {
const llvm::Module *_module{nullptr};
SVF::SVFModule *_svfModule{nullptr};
std::unique_ptr<SVF::PointerAnalysis> _pta{};
std::unique_ptr<LazyLLVMCallGraph> _cg;

PointsTo &getUnknownPTSet() const {
static PointsTo _unknownPTSet;
Expand Down Expand Up @@ -127,6 +131,15 @@ class SVFPointerAnalysis : public LLVMPointerAnalysis {
return !pts.empty();
}

///
// SVF's call graph usually lacks information about calls made through
// function pointers. If that happens, use our, more precise, call graph.
LazyLLVMCallGraph &getPreciseCallGraph() {
if (!_cg)
_cg.reset(new LazyLLVMCallGraph(_module));
return *_cg;
}

///
// Get the points-to information for the given LLVM value.
// The return object has methods begin(), end() that can be used
Expand Down Expand Up @@ -165,6 +178,7 @@ class SVFPointerAnalysis : public LLVMPointerAnalysis {
_svfModule->buildSymbolTableInfo();

PAGBuilder builder;
PAG::handleBlackHole(true);
PAG *pag = builder.build(_svfModule);

_pta.reset(new Andersen(pag));
Expand Down
78 changes: 51 additions & 27 deletions lib/llvm/LLVMDependenceGraph.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,9 @@
#include "dg/llvm/LLVMDependenceGraph.h"
#include "dg/llvm/LLVMNode.h"
#include "dg/llvm/PointerAnalysis/PointerAnalysis.h"
#ifdef HAVE_SVF
#include "dg/llvm/PointerAnalysis/SVFPointerAnalysis.h"
#endif
// !FIXME
#include "../lib/llvm/ControlDependence/InterproceduralCD.h"
#include "../lib/llvm/ControlDependence/NTSCD.h"
Expand Down Expand Up @@ -393,6 +396,33 @@ static bool isMemAllocationFunc(const llvm::Function *func) {
name.equals("realloc");
}

void LLVMDependenceGraph::handleCalledFunction(const llvm::CallInst *CInst,
const llvm::Function *F,
LLVMNode *node) {
if (F->empty() || !llvmutils::callIsCompatible(F, CInst)) {
if (threads && F && F->getName() == "pthread_create") {
auto possibleFunctions =
getCalledFunctions(CInst->getArgOperand(2), PTA);
for (auto &function : possibleFunctions) {
if (!function->empty()) {
LLVMDependenceGraph *subg = buildSubgraph(
node, const_cast<llvm::Function *>(function),
true /*this is fork*/);
node->addSubgraph(subg);
}
}
} else {
// incompatible prototypes or the function
// is only declaration
return;
}
} else {
LLVMDependenceGraph *subg =
buildSubgraph(node, const_cast<llvm::Function *>(F));
node->addSubgraph(subg);
}
}

void LLVMDependenceGraph::handleInstruction(llvm::Value *val, LLVMNode *node,
LLVMNode *prevNode) {
using namespace llvm;
Expand All @@ -413,34 +443,28 @@ void LLVMDependenceGraph::handleInstruction(llvm::Value *val, LLVMNode *node,
if (pts.empty()) {
llvmutils::printerr("Had no PTA node", strippedValue);
}
for (const LLVMPointer &ptr : pts) {
// vararg may introduce imprecision here, so we
// must check that it is really pointer to a function
Function *F = dyn_cast<Function>(ptr.value);
if (!F)
continue;

if (F->empty() || !llvmutils::callIsCompatible(F, CInst)) {
if (threads && F && F->getName() == "pthread_create") {
auto possibleFunctions = getCalledFunctions(
CInst->getArgOperand(2), PTA);
for (auto &function : possibleFunctions) {
if (!function->empty()) {
LLVMDependenceGraph *subg = buildSubgraph(
node,
const_cast<llvm::Function *>(function),
true /*this is fork*/);
node->addSubgraph(subg);
}
}
} else {
// incompatible prototypes or the function
// is only declaration

if (PTA->getOptions().isSVF() && pts.size() == 1 &&
pts.hasUnknown()) {
#ifdef HAVE_SVF
auto &CG = static_cast<SVFPointerAnalysis *>(PTA)
->getPreciseCallGraph();

const auto &functions = CG.getCalledFunctions(CInst);
for (const auto *F : functions)
handleCalledFunction(CInst, F, node);
#else
assert(false && "trying to use SVF on a non-SVF build");
#endif
} else {
for (const LLVMPointer &ptr : pts) {
// vararg may introduce imprecision here, so we
// must check that it is really pointer to a function
Function *F = dyn_cast<Function>(ptr.value);
if (!F)
continue;
}
} else {
LLVMDependenceGraph *subg = buildSubgraph(node, F);
node->addSubgraph(subg);

handleCalledFunction(CInst, F, node);
}
}
}
Expand Down
25 changes: 22 additions & 3 deletions lib/llvm/ReadWriteGraph/Instructions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@
//#include "dg/llvm/PointerAnalysis/PointerGraph.h"
//#include "llvm/ForkJoin/ForkJoin.h"
#include "dg/ReadWriteGraph/RWNode.h"
#ifdef HAVE_SVF
#include "dg/llvm/PointerAnalysis/SVFPointerAnalysis.h"
#endif
#include "llvm/ReadWriteGraph/LLVMReadWriteGraphBuilder.h"
#include "llvm/llvm-utils.h"

Expand Down Expand Up @@ -306,9 +309,25 @@ LLVMReadWriteGraphBuilder::createCall(const llvm::Instruction *Inst) {

const auto &functions = getCalledFunctions(calledVal, PTA);
if (functions.empty()) {
llvm::errs() << "[RWG] error: could not determine the called function "
"in a call via pointer: \n"
<< ValInfo(CInst) << "\n";
#ifdef HAVE_SVF
if (PTA->getOptions().isSVF()) {
errs() << "[RWG] warning: could not determine the called function "
"in a call via pointer from SVF pointer analysis: \n"
<< ValInfo(CInst) << "\n"
<< "[RWG] note: trying our CallGraph instead!\n";

auto &CG = static_cast<SVFPointerAnalysis *>(PTA)
->getPreciseCallGraph();

const auto &functions = CG.getCalledFunctions(CInst);
if (!functions.empty())
return createCallToFunctions(functions, CInst);
}
#endif

errs() << "[RWG] error: could not determine the called function "
"in a call via pointer: \n"
<< ValInfo(CInst) << "\n";
return {createUnknownCall(CInst)};
}
return createCallToFunctions(functions, CInst);
Expand Down

0 comments on commit 01c0d7d

Please sign in to comment.