Static Value-Flow Analysis
SaberCondAllocator.cpp
Go to the documentation of this file.
1 //===- PathAllocator.cpp -- Path condition analysis---------------------------//
2 //
3 // SVF: Static Value-Flow Analysis
4 //
5 // Copyright (C) <2013-> <Yulei Sui>
6 //
7 
8 // This program is free software: you can redistribute it and/or modify
9 // it under the terms of the GNU Affero General Public License as published by
10 // the Free Software Foundation, either version 3 of the License, or
11 // (at your option) any later version.
12 
13 // This program is distributed in the hope that it will be useful,
14 // but WITHOUT ANY WARRANTY; without even the implied warranty of
15 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 // GNU Affero General Public License for more details.
17 
18 // You should have received a copy of the GNU Affero General Public License
19 // along with this program. If not, see <http://www.gnu.org/licenses/>.
20 //
21 //===----------------------------------------------------------------------===//
22 
23 
24 /*
25  * PathAllocator.cpp
26  *
27  * Created on: Apr 3, 2014
28  * Author: Yulei Sui
29  */
30 
31 #include "Util/Options.h"
33 #include "Util/DPItem.h"
34 #include "Graphs/SVFG.h"
35 #include <climits>
36 #include <cmath>
37 #include "SVFIR/SVFStatements.h"
38 
39 using namespace SVF;
40 using namespace SVFUtil;
41 
42 u64_t DPItem::maximumBudget = ULONG_MAX - 1;
48 
49 
51 {
52 
53 }
54 
59 {
60  DBOUT(DGENERAL, outs() << pasMsg("path condition allocation starts\n"));
61 
62  PTACallGraph* svfirCallGraph = PAG::getPAG()->getCallGraph();
63  for (const auto& item: *svfirCallGraph)
64  {
65  const SVFFunction *func = (item.second)->getFunction();
66  if (!SVFUtil::isExtCall(func))
67  {
68  // Allocate conditions for a program.
69  for (SVFFunction::const_iterator bit = func->begin(), ebit = func->end();
70  bit != ebit; ++bit)
71  {
72  const SVFBasicBlock* bb = *bit;
73  collectBBCallingProgExit(*bb);
74  allocateForBB(*bb);
75  }
76  }
77  }
78 
80  printPathCond();
81 
82  DBOUT(DGENERAL, outs() << pasMsg("path condition allocation ends\n"));
83 }
84 
89 {
90 
91  u32_t succ_number = bb.getNumSuccessors();
92 
93  // if successor number greater than 1, allocate new decision variable for successors
94  if (succ_number > 1)
95  {
96 
97  //allocate log2(num_succ) decision variables
98  double num = log(succ_number) / log(2);
99  u32_t bit_num = (u32_t) ceil(num);
100  u32_t succ_index = 0;
101  std::vector<Condition> condVec;
102  for (u32_t i = 0; i < bit_num; i++)
103  {
104  const IntraICFGNode* svfInst = cast<IntraICFGNode>(bb.back());
105  condVec.push_back(newCond(svfInst));
106  }
107 
108  // iterate each successor
109  for (const SVFBasicBlock* svf_succ_bb : bb.getSuccessors())
110  {
111  Condition path_cond = getTrueCond();
112 
114 
115  // for each successor decide its bit representation
116  // decide whether each bit of succ_index is 1 or 0, if (three successor) succ_index is 000 then use C1^C2^C3
117  // if 001 use C1^C2^negC3
118  for (u32_t j = 0; j < bit_num; j++)
119  {
120  //test each bit of this successor's index (binary representation)
121  u32_t tool = 0x01 << j;
122  if (tool & succ_index)
123  {
124  path_cond = condAnd(path_cond, (condNeg(condVec.at(j))));
125  }
126  else
127  {
128  path_cond = condAnd(path_cond, condVec.at(j));
129  }
130  }
131  setBranchCond(&bb, svf_succ_bb, path_cond);
132 
133  succ_index++;
134  }
135 
136  }
137 }
138 
143 {
144  u32_t pos = bb->getBBSuccessorPos(succ);
145  if(bb->getNumSuccessors() == 1)
146  return getTrueCond();
147  else
148  {
149  BBCondMap::const_iterator it = bbConds.find(bb);
150  assert(it != bbConds.end() && "basic block does not have branch and conditions??");
151  CondPosMap::const_iterator cit = it->second.find(pos);
152  assert(cit != it->second.end() && "no condition on the branch??");
153  return cit->second;
154  }
155 }
156 
158 {
159  if (getCurEvalSVFGNode() && getCurEvalSVFGNode()->getValue())
160  return evaluateBranchCond(bb, succ);
161  else
162  return getBranchCond(bb, succ);
163 }
164 
169 {
171  assert(bb->getNumSuccessors() > 1 && "not more than one successor??");
172  u32_t pos = bb->getBBSuccessorPos(succ);
173  CondPosMap& condPosMap = bbConds[bb];
174 
177  //assert(condPosMap.find(pos) == condPosMap.end() && "this branch has already been set ");
178 
179  condPosMap[pos] = cond;
180 }
181 
187 {
188 
189  const SVFBasicBlock* succ1 = branchStmt->getSuccessor(0)->getBB();
190 
191  const ValVar* condVar = SVFUtil::cast<ValVar>(branchStmt->getCondition());
192  if (isTestNullExpr(SVFUtil::cast<ICFGNode>(condVar->getGNode())))
193  {
194  // succ is then branch
195  if (succ1 == succ)
196  return getFalseCond();
197  // succ is else branch
198  else
199  return getTrueCond();
200  }
201  if (isTestNotNullExpr(SVFUtil::cast<ICFGNode>(condVar->getGNode())))
202  {
203  // succ is then branch
204  if (succ1 == succ)
205  return getTrueCond();
206  // succ is else branch
207  else
208  return getFalseCond();
209  }
210  return Condition::nullExpr();
211 }
212 
217 {
218  const SVFBasicBlock* succ1 = branchStmt->getSuccessor(0)->getBB();
219  const SVFBasicBlock* succ2 = branchStmt->getSuccessor(1)->getBB();
220 
221  bool branch1 = isBBCallsProgExit(succ1);
222  bool branch2 = isBBCallsProgExit(succ2);
223 
225  if (branch1 && !branch2)
226  {
227  // succ is then branch
228  if (succ1 == succ)
229  return getFalseCond();
230  // succ is else branch
231  else
232  return getTrueCond();
233  }
235  else if (!branch1 && branch2)
236  {
237  // succ is else branch
238  if (succ2 == succ)
239  return getFalseCond();
240  // succ is then branch
241  else
242  return getTrueCond();
243  }
244  // two branches both call program exit
245  else if (branch1 && branch2)
246  {
247  return getFalseCond();
248  }
250  else
251  return Condition::nullExpr();
252 
253 }
254 
261 {
262  const SVFFunction* svffun = bb->getParent();
263  assert(svffun == dst->getParent() && "two basic blocks should be in the same function");
264 
265  if (svffun->isLoopHeader(bb))
266  {
267  Set<const SVFBasicBlock* > filteredbbs;
268  std::vector<const SVFBasicBlock*> exitbbs;
269  svffun->getExitBlocksOfLoop(bb,exitbbs);
271  for(const SVFBasicBlock* eb : exitbbs)
272  {
273  if(!isBBCallsProgExit(eb))
274  filteredbbs.insert(eb);
275  }
276 
278  bool allPDT = true;
279  for (const auto &filteredbb: filteredbbs)
280  {
281  if (!postDominate(dst, filteredbb))
282  allPDT = false;
283  }
284 
285  if (allPDT)
286  return getTrueCond();
287  }
288  return Condition::nullExpr();
289 }
290 
297 {
298  if(bb->getNumSuccessors() == 1)
299  {
300  return getTrueCond();
301  }
302 
303  assert(!bb->getICFGNodeList().empty() && "bb not empty");
304  if (const ICFGNode* icfgNode = bb->back())
305  {
306  for (const auto &svfStmt: icfgNode->getSVFStmts())
307  {
308  if (const BranchStmt *branchStmt = SVFUtil::dyn_cast<BranchStmt>(svfStmt))
309  {
310  if (branchStmt->getNumSuccessors() == 2)
311  {
312  const SVFBasicBlock* succ1 = branchStmt->getSuccessor(0)->getBB();
313  const SVFBasicBlock* succ2 = branchStmt->getSuccessor(1)->getBB();
314  bool is_succ = (succ1 == succ || succ2 == succ);
315  (void)is_succ; // Suppress warning of unused variable under release build
316  assert(is_succ && "not a successor??");
317  Condition evalLoopExit = evaluateLoopExitBranch(bb, succ);
318  if (!eq(evalLoopExit, Condition::nullExpr()))
319  return evalLoopExit;
320 
321  Condition evalProgExit = evaluateProgExit(branchStmt, succ);
322  if (!eq(evalProgExit, Condition::nullExpr()))
323  return evalProgExit;
324 
325  Condition evalTestNullLike = evaluateTestNullLikeExpr(branchStmt, succ);
326  if (!eq(evalTestNullLike, Condition::nullExpr()))
327  return evalTestNullLike;
328  break;
329  }
330  }
331  }
332  }
333 
334  return getBranchCond(bb, succ);
335 }
336 
337 bool SaberCondAllocator::isEQCmp(const CmpStmt *cmp) const
338 {
339  return (cmp->getPredicate() == CmpStmt::ICMP_EQ);
340 }
341 
342 bool SaberCondAllocator::isNECmp(const CmpStmt *cmp) const
343 {
344  return (cmp->getPredicate() == CmpStmt::ICMP_NE);
345 }
346 
348 {
349  if(!test) return false;
350  for(const SVFStmt* stmt : PAG::getPAG()->getSVFStmtList(test))
351  {
352  if(const CmpStmt* cmp = SVFUtil::dyn_cast<CmpStmt>(stmt))
353  {
354  return isTestContainsNullAndTheValue(cmp) && isEQCmp(cmp);
355  }
356  }
357  return false;
358 }
359 
361 {
362  if(!test) return false;
363  for(const SVFStmt* stmt : PAG::getPAG()->getSVFStmtList(test))
364  {
365  if(const CmpStmt* cmp = SVFUtil::dyn_cast<CmpStmt>(stmt))
366  {
367  return isTestContainsNullAndTheValue(cmp) && isNECmp(cmp);
368  }
369  }
370  return false;
371 }
372 
394 {
395 
396  const SVFValue* op0 = cmp->getOpVar(0)->getValue();
397  const SVFValue* op1 = cmp->getOpVar(1)->getValue();
398  if (SVFUtil::isa<SVFConstantNullPtr>(op1))
399  {
400  Set<const SVFValue* > inDirVal;
401  inDirVal.insert(getCurEvalSVFGNode()->getValue());
402  for (const auto &it: getCurEvalSVFGNode()->getOutEdges())
403  {
404  inDirVal.insert(it->getDstNode()->getValue());
405  }
406  return inDirVal.find(op0) != inDirVal.end();
407  }
408  else if (SVFUtil::isa<SVFConstantNullPtr>(op0))
409  {
410  Set<const SVFValue* > inDirVal;
411  inDirVal.insert(getCurEvalSVFGNode()->getValue());
412  for (const auto &it: getCurEvalSVFGNode()->getOutEdges())
413  {
414  inDirVal.insert(it->getDstNode()->getValue());
415  }
416  return inDirVal.find(op1) != inDirVal.end();
417  }
418  return false;
419 }
420 
425 {
426 
427  for (const auto& icfgNode: bb.getICFGNodeList())
428  {
429  if (const CallICFGNode* cs = SVFUtil::dyn_cast<CallICFGNode>(icfgNode))
430  if (SVFUtil::isProgExitCall(cs))
431  {
432  const SVFFunction* svfun = bb.getParent();
433  funToExitBBsMap[svfun].insert(&bb);
434  }
435  }
436 }
437 
442 {
443  const SVFFunction* svfun = bb->getParent();
444  FunToExitBBsMap::const_iterator it = funToExitBBsMap.find(svfun);
445  if (it != funToExitBBsMap.end())
446  {
447  for (const auto &bit: it->second)
448  {
449  if (postDominate(bit, bb))
450  return true;
451  }
452  }
453  return false;
454 }
455 
464 {
465  assert(BB1 && BB2 && "expect nullptr BB here!");
466 
468  if (dominate(BB1, BB2) && ! dominate(BB0, BB2))
469  {
470  Condition cond = ComputeIntraVFGGuard(BB1, BB2);
471  return condNeg(cond);
472  }
473 
474  return getTrueCond();
475 }
476 
484  const SVFBasicBlock* callBB)
485 {
486  const SVFBasicBlock* funEntryBB = dstBB->getParent()->getEntryBlock();
487 
488  Condition c1 = ComputeIntraVFGGuard(srcBB, callBB);
489  setCFCond(funEntryBB, condOr(getCFCond(funEntryBB), getCFCond(callBB)));
490  Condition c2 = ComputeIntraVFGGuard(funEntryBB, dstBB);
491  return condAnd(c1, c2);
492 }
493 
501 {
502  const SVFFunction* parent = srcBB->getParent();
503  const SVFBasicBlock* funExitBB = parent->getExitBB();
504 
505  Condition c1 = ComputeIntraVFGGuard(srcBB, funExitBB);
506  setCFCond(retBB, condOr(getCFCond(retBB), getCFCond(funExitBB)));
507  Condition c2 = ComputeIntraVFGGuard(retBB, dstBB);
508  return condAnd(c1, c2);
509 }
510 
515 {
516 
517  assert(srcBB->getParent() == dstBB->getParent() && "two basic blocks are not in the same function??");
518 
519  if (postDominate(dstBB, srcBB))
520  return getTrueCond();
521 
522  CFWorkList worklist;
523  worklist.push(srcBB);
524  setCFCond(srcBB, getTrueCond());
525 
526  while (!worklist.empty())
527  {
528  const SVFBasicBlock* bb = worklist.pop();
529  Condition cond = getCFCond(bb);
530 
533  Condition loopExitCond = evaluateLoopExitBranch(bb, dstBB);
534  if (!eq(loopExitCond, Condition::nullExpr()))
535  return condAnd(cond, loopExitCond);
536 
537  for (const SVFBasicBlock* succ : bb->getSuccessors())
538  {
543  Condition brCond;
544  if (postDominate(succ, bb))
545  brCond = getTrueCond();
546  else
547  brCond = getEvalBrCond(bb, succ);
548 
549  DBOUT(DSaber, outs() << " bb (" << bb->getName() <<
550  ") --> " << "succ_bb (" << succ->getName() << ") condition: " << brCond << "\n");
551  Condition succPathCond = condAnd(cond, brCond);
552  if (setCFCond(succ, condOr(getCFCond(succ), succPathCond)))
553  worklist.push(succ);
554  }
555  }
556 
557  DBOUT(DSaber, outs() << " src_bb (" << srcBB->getName() <<
558  ") --> " << "dst_bb (" << dstBB->getName() << ") condition: " << getCFCond(dstBB)
559  << "\n");
560 
561  return getCFCond(dstBB);
562 }
563 
564 
569 {
570 
571  outs() << "print path condition\n";
572 
573  for (const auto &bbCond: bbConds)
574  {
575  const SVFBasicBlock* bb = bbCond.first;
576  for (const auto &cit: bbCond.second)
577  {
578  u32_t i = 0;
579  for (const SVFBasicBlock* succ: bb->getSuccessors())
580  {
581  if (i == cit.first)
582  {
583  Condition cond = cit.second;
584  outs() << bb->getName() << "-->" << succ->getName() << ":";
585  outs() << dumpCond(cond) << "\n";
586  break;
587  }
588  i++;
589  }
590  }
591  }
592 }
593 
596 {
597  u32_t condCountIdx = totalCondNum++;
598  Condition expr = Condition::getContext().bool_const(("c" + std::to_string(condCountIdx)).c_str());
599  Condition negCond = Condition::NEG(expr);
600  setCondInst(expr, inst);
601  setNegCondInst(negCond, inst);
602  conditionVec.push_back(expr);
603  conditionVec.push_back(negCond);
604  return expr;
605 }
606 
609  const Condition &rhs) const
610 {
611  Condition::getSolver().push();
612  Condition::getSolver().add(lhs.getExpr() != rhs.getExpr());
613  z3::check_result res = Condition::getSolver().check();
614  Condition::getSolver().pop();
615  return res == z3::unsat;
616 }
617 
620 {
621  Condition::getSolver().add(condition.getExpr());
622  z3::check_result result = Condition::getSolver().check();
623  Condition::getSolver().pop();
624  if (result == z3::sat || result == z3::unknown)
625  return true;
626  else
627  return false;
628 }
629 
631 void SaberCondAllocator::extractSubConds(const Condition &condition, NodeBS &support) const
632 {
633  if (condition.getExpr().num_args() == 1 && isNegCond(condition.id()))
634  {
635  support.set(condition.getExpr().id());
636  return;
637  }
638  if (condition.getExpr().num_args() == 0)
639  if (!condition.getExpr().is_true() && !condition.getExpr().is_false())
640  support.set(condition.getExpr().id());
641  for (u32_t i = 0; i < condition.getExpr().num_args(); ++i)
642  {
643  Condition expr = condition.getExpr().arg(i);
644  extractSubConds(expr, support);
645  }
646 
647 }
unsigned u32_t
Definition: CommandLine.h:18
#define DBOUT(TYPE, X)
LLVM debug macros, define type of your DBUG model of each pass.
Definition: SVFType.h:484
#define DGENERAL
Definition: SVFType.h:490
#define DSaber
Definition: SVFType.h:504
cJSON * item
Definition: cJSON.h:222
const ICFGNode * getSuccessor(u32_t i) const
const SVFVar * getCondition() const
Return the condition.
u32_t getPredicate() const
@ ICMP_NE
not equal
static u32_t maximumCxt
Definition: DPItem.h:378
static u32_t maximumCxtLen
Definition: DPItem.h:374
static u32_t maximumPath
Definition: DPItem.h:379
static u32_t maximumPathLen
Definition: DPItem.h:375
static u64_t maximumBudget
Definition: DPItem.h:48
bool push(const Data &data)
Definition: WorkList.h:165
bool empty() const
Definition: WorkList.h:146
virtual const SVFBasicBlock * getBB() const
Return the basic block of this ICFGNode.
Definition: ICFGNode.h:82
const SVFVar * getOpVar(u32_t pos) const
Operand SVFVars.
static const Option< bool > PrintPathCond
Definition: Options.h:199
const std::vector< const ICFGNode * > & getICFGNodeList() const
Definition: SVFValue.h:569
const std::vector< const SVFBasicBlock * > & getSuccessors() const
Definition: SVFValue.h:606
u32_t getBBSuccessorPos(const SVFBasicBlock *succbb)
Definition: SVFValue.cpp:212
const ICFGNode * back() const
Definition: SVFValue.h:600
u32_t getNumSuccessors() const
Definition: SVFValue.h:615
const SVFFunction * getParent() const
Definition: SVFValue.h:584
const_iterator end() const
Definition: SVFValue.h:440
const_iterator begin() const
Definition: SVFValue.h:435
void getExitBlocksOfLoop(const SVFBasicBlock *bb, BBList &exitbbs) const
Definition: SVFValue.h:465
const SVFBasicBlock * getEntryBlock() const
Definition: SVFValue.h:409
std::vector< const SVFBasicBlock * >::const_iterator const_iterator
Definition: SVFValue.h:305
const SVFBasicBlock * getExitBB() const
Definition: SVFValue.cpp:186
bool isLoopHeader(const SVFBasicBlock *bb) const
Definition: SVFValue.h:500
PTACallGraph * getCallGraph()
Definition: SVFIR.h:192
static SVFIR * getPAG(bool buildFromFile=false)
Singleton design here to make sure we only have one instance during any analysis.
Definition: SVFIR.h:115
const std::string & getName() const
Definition: SVFValue.h:243
const SVFValue * getValue() const
Get/has methods of the components.
Definition: SVFVariables.h:83
void allocate(const SVFModule *module)
Perform path allocation.
virtual void allocateForBB(const SVFBasicBlock &bb)
Allocate path condition for every basic block.
Condition newCond(const ICFGNode *inst)
Allocate a new condition.
Condition evaluateTestNullLikeExpr(const BranchStmt *branchStmt, const SVFBasicBlock *succ)
Return branch condition after evaluating test null like expression.
Condition evaluateProgExit(const BranchStmt *branchStmt, const SVFBasicBlock *succ)
Return condition when there is a branch calls program exit.
bool isTestContainsNullAndTheValue(const CmpStmt *cmp) const
Return true if two values on the predicate are what we want.
bool isTestNullExpr(const ICFGNode *test) const
Return true if this is a test null expression.
void printPathCond()
Print out the path condition information.
void setBranchCond(const SVFBasicBlock *bb, const SVFBasicBlock *succ, const Condition &cond)
Get/Set a branch condition, and its terminator instruction.
virtual Condition getPHIComplementCond(const SVFBasicBlock *BB1, const SVFBasicBlock *BB2, const SVFBasicBlock *BB0)
static u32_t totalCondNum
vector storing z3expression
bool isSatisfiable(const Condition &condition)
whether condition is satisfiable
Condition getBranchCond(const SVFBasicBlock *bb, const SVFBasicBlock *succ) const
Get branch condition.
virtual Condition ComputeInterRetVFGGuard(const SVFBasicBlock *src, const SVFBasicBlock *dst, const SVFBasicBlock *retBB)
void collectBBCallingProgExit(const SVFBasicBlock &bb)
Collect basic block contains program exit function call.
bool isBBCallsProgExit(const SVFBasicBlock *bb)
void extractSubConds(const Condition &condition, NodeBS &support) const
extract subexpression from a Z3 expression
Map< u32_t, Condition > CondPosMap
id to instruction map for z3
bool isEquivalentBranchCond(const Condition &lhs, const Condition &rhs) const
Whether lhs and rhs are equivalent branch conditions.
bool isEQCmp(const CmpStmt *cmp) const
Evaluate test null/not null like expressions.
bool isNECmp(const CmpStmt *cmp) const
Return true if the predicate of this compare instruction is not equal.
Condition evaluateBranchCond(const SVFBasicBlock *bb, const SVFBasicBlock *succ)
Evaluate branch conditions.
Condition evaluateLoopExitBranch(const SVFBasicBlock *bb, const SVFBasicBlock *succ)
Evaluate loop exit branch.
bool isTestNotNullExpr(const ICFGNode *test) const
Return true if this is a test not null expression.
Condition getEvalBrCond(const SVFBasicBlock *bb, const SVFBasicBlock *succ)
Get a condition, evaluate the value for conditions if necessary (e.g., testNull like express)
virtual Condition ComputeInterCallVFGGuard(const SVFBasicBlock *src, const SVFBasicBlock *dst, const SVFBasicBlock *callBB)
virtual Condition ComputeIntraVFGGuard(const SVFBasicBlock *src, const SVFBasicBlock *dst)
Guard Computation for a value-flow (between two basic blocks)
void set(unsigned Idx)
const SVFBaseNode * getGNode() const
Definition: SVFVariables.h:311
const z3::expr & getExpr() const
Definition: Z3Expr.h:86
u32_t id() const
get id
Definition: Z3Expr.h:111
const SVFFunction * getFunction(const std::string &name)
Get the corresponding Function based on its name.
Definition: LLVMUtil.cpp:412
bool isExtCall(const SVFFunction *fun)
Definition: SVFUtil.h:278
std::string pasMsg(const std::string &msg)
Print each pass/phase message by converting a string into blue string output.
Definition: SVFUtil.cpp:99
bool isProgExitCall(const CallICFGNode *cs)
Definition: SVFUtil.cpp:396
std::ostream & outs()
Overwrite llvm::outs()
Definition: SVFUtil.h:50
for isBitcode
Definition: BasicTypes.h:68
unsigned long long u64_t
Definition: GeneralType.h:48
unsigned u32_t
Definition: GeneralType.h:46
std::unordered_set< Key, Hash, KeyEqual, Allocator > Set
Definition: GeneralType.h:96