Static Value-Flow Analysis
Loading...
Searching...
No Matches
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#include "Graphs/CallGraph.h"
39
40using namespace SVF;
41using namespace SVFUtil;
42
49
50
55
60{
61 DBOUT(DGENERAL, outs() << pasMsg("path condition allocation starts\n"));
62
64 for (const auto& item: *svfirCallGraph)
65 {
66 const SVFFunction *func = (item.second)->getFunction();
67 if (!SVFUtil::isExtCall(func))
68 {
69 // Allocate conditions for a program.
70 for (SVFFunction::const_iterator bit = func->begin(), ebit = func->end();
71 bit != ebit; ++bit)
72 {
73 const SVFBasicBlock* bb = *bit;
75 allocateForBB(*bb);
76 }
77 }
78 }
79
82
83 DBOUT(DGENERAL, outs() << pasMsg("path condition allocation ends\n"));
84}
85
90{
91
93
94 // if successor number greater than 1, allocate new decision variable for successors
95 if (succ_number > 1)
96 {
97
98 //allocate log2(num_succ) decision variables
99 double num = log(succ_number) / log(2);
101 u32_t succ_index = 0;
102 std::vector<Condition> condVec;
103 for (u32_t i = 0; i < bit_num; i++)
104 {
105 condVec.push_back(newCond(bb.back()));
106 }
107
108 // iterate each successor
109 for (const SVFBasicBlock* svf_succ_bb : bb.getSuccessors())
110 {
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 {
125 }
126 else
127 {
129 }
130 }
132
133 succ_index++;
134 }
135
136 }
137}
138
143{
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
164
169{
171 assert(bb->getNumSuccessors() > 1 && "not more than one successor??");
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 (condVar->isConstDataOrAggDataButNotNullPtr())
193 {
194 // branch condition is a constant value, return nullexpr because it cannot be test null
195 // br i1 false, label %44, label %75, !dbg !7669 { "ln": 2033, "cl": 7, "fl": "re_lexer.c" }
196 return Condition::nullExpr();
197 }
198 if (isTestNullExpr(SVFUtil::cast<ICFGNode>(condVar->getICFGNode())))
199 {
200 // succ is then branch
201 if (succ1 == succ)
202 return getFalseCond();
203 // succ is else branch
204 else
205 return getTrueCond();
206 }
207 if (isTestNotNullExpr(condVar->getICFGNode()))
208 {
209 // succ is then branch
210 if (succ1 == succ)
211 return getTrueCond();
212 // succ is else branch
213 else
214 return getFalseCond();
215 }
216 return Condition::nullExpr();
217}
218
223{
224 const SVFBasicBlock* succ1 = branchStmt->getSuccessor(0)->getBB();
225 const SVFBasicBlock* succ2 = branchStmt->getSuccessor(1)->getBB();
226
229
231 if (branch1 && !branch2)
232 {
233 // succ is then branch
234 if (succ1 == succ)
235 return getFalseCond();
236 // succ is else branch
237 else
238 return getTrueCond();
239 }
241 else if (!branch1 && branch2)
242 {
243 // succ is else branch
244 if (succ2 == succ)
245 return getFalseCond();
246 // succ is then branch
247 else
248 return getTrueCond();
249 }
250 // two branches both call program exit
251 else if (branch1 && branch2)
252 {
253 return getFalseCond();
254 }
256 else
257 return Condition::nullExpr();
258
259}
260
267{
268 const SVFFunction* svffun = bb->getParent();
269 assert(svffun == dst->getParent() && "two basic blocks should be in the same function");
270
271 if (svffun->isLoopHeader(bb))
272 {
274 std::vector<const SVFBasicBlock*> exitbbs;
275 svffun->getExitBlocksOfLoop(bb,exitbbs);
277 for(const SVFBasicBlock* eb : exitbbs)
278 {
280 filteredbbs.insert(eb);
281 }
282
284 bool allPDT = true;
285 for (const auto &filteredbb: filteredbbs)
286 {
287 if (!postDominate(dst, filteredbb))
288 allPDT = false;
289 }
290
291 if (allPDT)
292 return getTrueCond();
293 }
294 return Condition::nullExpr();
295}
296
303{
304 if(bb->getNumSuccessors() == 1)
305 {
306 return getTrueCond();
307 }
308
309 assert(!bb->getICFGNodeList().empty() && "bb not empty");
310 if (const ICFGNode* icfgNode = bb->back())
311 {
312 for (const auto &svfStmt: icfgNode->getSVFStmts())
313 {
314 if (const BranchStmt *branchStmt = SVFUtil::dyn_cast<BranchStmt>(svfStmt))
315 {
316 if (branchStmt->getNumSuccessors() == 2)
317 {
318 const SVFBasicBlock* succ1 = branchStmt->getSuccessor(0)->getBB();
319 const SVFBasicBlock* succ2 = branchStmt->getSuccessor(1)->getBB();
320 bool is_succ = (succ1 == succ || succ2 == succ);
321 (void)is_succ; // Suppress warning of unused variable under release build
322 assert(is_succ && "not a successor??");
325 return evalLoopExit;
326
329 return evalProgExit;
330
333 return evalTestNullLike;
334 break;
335 }
336 }
337 }
338 }
339
340 return getBranchCond(bb, succ);
341}
342
344{
345 return (cmp->getPredicate() == CmpStmt::ICMP_EQ);
346}
347
349{
350 return (cmp->getPredicate() == CmpStmt::ICMP_NE);
351}
352
354{
355 if(!test) return false;
356 for(const SVFStmt* stmt : PAG::getPAG()->getSVFStmtList(test))
357 {
358 if(const CmpStmt* cmp = SVFUtil::dyn_cast<CmpStmt>(stmt))
359 {
361 }
362 }
363 return false;
364}
365
367{
368 if(!test) return false;
369 for(const SVFStmt* stmt : PAG::getPAG()->getSVFStmtList(test))
370 {
371 if(const CmpStmt* cmp = SVFUtil::dyn_cast<CmpStmt>(stmt))
372 {
374 }
375 }
376 return false;
377}
378
400{
401
402 const SVFVar* op0 = cmp->getOpVar(0);
403 const SVFVar* op1 = cmp->getOpVar(1);
404 if (SVFUtil::isa<ConstantNullPtrValVar>(op1))
405 {
407 inDirVal.insert(getCurEvalSVFGNode()->getValue());
408 for (const auto &it: getCurEvalSVFGNode()->getOutEdges())
409 {
410 inDirVal.insert(it->getDstNode()->getValue());
411 }
412 return inDirVal.find(op0->getValue()) != inDirVal.end();
413 }
414 else if (SVFUtil::isa<ConstantNullPtrValVar>(op0))
415 {
418 for (const auto &it: getCurEvalSVFGNode()->getOutEdges())
419 {
420 inDirVal.insert(it->getDstNode()->getValue());
421 }
422 return inDirVal.find(op1->getValue()) != inDirVal.end();
423 }
424 return false;
425}
426
431{
432
433 for (const auto& icfgNode: bb.getICFGNodeList())
434 {
435 if (const CallICFGNode* cs = SVFUtil::dyn_cast<CallICFGNode>(icfgNode))
437 {
438 const SVFFunction* svfun = bb.getParent();
439 funToExitBBsMap[svfun].insert(&bb);
440 }
441 }
442}
443
448{
449 const SVFFunction* svfun = bb->getParent();
450 FunToExitBBsMap::const_iterator it = funToExitBBsMap.find(svfun);
451 if (it != funToExitBBsMap.end())
452 {
453 for (const auto &bit: it->second)
454 {
455 if (postDominate(bit, bb))
456 return true;
457 }
458 }
459 return false;
460}
461
470{
471 assert(BB1 && BB2 && "expect nullptr BB here!");
472
474 if (dominate(BB1, BB2) && ! dominate(BB0, BB2))
475 {
477 return condNeg(cond);
478 }
479
480 return getTrueCond();
481}
482
499
516
521{
522
523 assert(srcBB->getParent() == dstBB->getParent() && "two basic blocks are not in the same function??");
524
526 return getTrueCond();
527
528 CFWorkList worklist;
529 worklist.push(srcBB);
531
532 while (!worklist.empty())
533 {
534 const SVFBasicBlock* bb = worklist.pop();
535 Condition cond = getCFCond(bb);
536
541 return condAnd(cond, loopExitCond);
542
543 for (const SVFBasicBlock* succ : bb->getSuccessors())
544 {
550 if (postDominate(succ, bb))
552 else
554
555 DBOUT(DSaber, outs() << " bb (" << bb->getName() <<
556 ") --> " << "succ_bb (" << succ->getName() << ") condition: " << brCond << "\n");
559 worklist.push(succ);
560 }
561 }
562
563 DBOUT(DSaber, outs() << " src_bb (" << srcBB->getName() <<
564 ") --> " << "dst_bb (" << dstBB->getName() << ") condition: " << getCFCond(dstBB)
565 << "\n");
566
567 return getCFCond(dstBB);
568}
569
570
575{
576
577 outs() << "print path condition\n";
578
579 for (const auto &bbCond: bbConds)
580 {
581 const SVFBasicBlock* bb = bbCond.first;
582 for (const auto &cit: bbCond.second)
583 {
584 u32_t i = 0;
585 for (const SVFBasicBlock* succ: bb->getSuccessors())
586 {
587 if (i == cit.first)
588 {
589 Condition cond = cit.second;
590 outs() << bb->getName() << "-->" << succ->getName() << ":";
591 outs() << dumpCond(cond) << "\n";
592 break;
593 }
594 i++;
595 }
596 }
597 }
598}
599
602{
604 Condition expr = Condition::getContext().bool_const(("c" + std::to_string(condCountIdx)).c_str());
606 setCondInst(expr, inst);
607 setNegCondInst(negCond, inst);
608 conditionVec.push_back(expr);
609 conditionVec.push_back(negCond);
610 return expr;
611}
612
615 const Condition &rhs) const
616{
617 Condition::getSolver().push();
618 Condition::getSolver().add(lhs.getExpr() != rhs.getExpr());
619 z3::check_result res = Condition::getSolver().check();
620 Condition::getSolver().pop();
621 return res == z3::unsat;
622}
623
626{
627 Condition::getSolver().add(condition.getExpr());
628 z3::check_result result = Condition::getSolver().check();
629 Condition::getSolver().pop();
630 if (result == z3::sat || result == z3::unknown)
631 return true;
632 else
633 return false;
634}
635
638{
639 if (condition.getExpr().num_args() == 1 && isNegCond(condition.id()))
640 {
641 support.set(condition.getExpr().id());
642 return;
643 }
644 if (condition.getExpr().num_args() == 0)
645 if (!condition.getExpr().is_true() && !condition.getExpr().is_false())
646 support.set(condition.getExpr().id());
647 for (u32_t i = 0; i < condition.getExpr().num_args(); ++i)
648 {
649 Condition expr = condition.getExpr().arg(i);
651 }
652
653}
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
@ 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
const GEdgeSetTy & getOutEdges() const
static const Option< bool > PrintPathCond
Definition Options.h:199
const SVFFunction * getParent() const
Definition SVFValue.h:595
const std::vector< const ICFGNode * > & getICFGNodeList() const
Definition SVFValue.h:580
const std::vector< const SVFBasicBlock * > & getSuccessors() const
Definition SVFValue.h:617
u32_t getBBSuccessorPos(const SVFBasicBlock *succbb)
Definition SVFValue.cpp:212
u32_t getNumSuccessors() const
Definition SVFValue.h:626
const ICFGNode * back() const
Definition SVFValue.h:611
const_iterator end() const
Definition SVFValue.h:451
const_iterator begin() const
Definition SVFValue.h:446
std::vector< constSVFBasicBlock * >::const_iterator const_iterator
Definition SVFValue.h:305
const SVFBasicBlock * getEntryBlock() const
Definition SVFValue.h:420
CallGraph * getCallGraph()
Definition SVFIR.h:193
SVFStmtList & getSVFStmtList(const ICFGNode *inst)
Given an instruction, get all its PAGEdges.
Definition SVFIR.h:222
static SVFIR * getPAG(bool buildFromFile=false)
Singleton design here to make sure we only have one instance during any analysis.
Definition SVFIR.h:116
const std::string & getName() const
Definition SVFValue.h:243
void allocate(const SVFModule *module)
Perform path allocation.
virtual void allocateForBB(const SVFBasicBlock &bb)
Allocate path condition for every basic block.
std::string dumpCond(const Condition &cond) const
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.
Condition condOr(const Condition &lhs, const Condition &rhs)
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.
bool postDominate(const SVFBasicBlock *bbKey, const SVFBasicBlock *bbValue) const
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)
BBCondMap bbConds
map basic block to its successors/predecessors branch conditions
Condition condNeg(const Condition &cond)
static u32_t totalCondNum
vector storing z3expression
Condition condAnd(const Condition &lhs, const Condition &rhs)
Condition operations.
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)
const SVFGNode * getCurEvalSVFGNode() const
Get current value for branch condition evaluation.
Condition getFalseCond() const
bool setCFCond(const SVFBasicBlock *bb, const Condition &cond)
Get/Set control-flow conditions.
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.
Condition getTrueCond() const
FIFOWorkList< const SVFBasicBlock * > CFWorkList
worklist for control-flow guard computation
bool isTestNotNullExpr(const ICFGNode *test) const
Return true if this is a test not null expression.
Condition getCFCond(const SVFBasicBlock *bb) const
FunToExitBBsMap funToExitBBsMap
map a function to all its basic blocks calling program exit
bool isNegCond(u32_t id) const
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)
void setNegCondInst(const Condition &condition, const ICFGNode *inst)
mark neg Z3 expression
bool dominate(const SVFBasicBlock *bbKey, const SVFBasicBlock *bbValue) const
void setCondInst(const Condition &condition, const ICFGNode *inst)
virtual Condition ComputeIntraVFGGuard(const SVFBasicBlock *src, const SVFBasicBlock *dst)
Guard Computation for a value-flow (between two basic blocks)
std::vector< Condition > conditionVec
bit vector for distinguish neg
virtual const SVFValue * getValue() const
Return the corresponding LLVM value, if possible, nullptr otherwise.
Definition VFGNode.h:85
const z3::expr & getExpr() const
Definition Z3Expr.h:86
static z3::solver & getSolver()
Get z3 solver, singleton design here to make sure we only have one context.
Definition Z3Expr.cpp:56
static Z3Expr NEG(const Z3Expr &z3Expr)
compute NEG
Definition Z3Expr.h:301
static z3::expr nullExpr()
null expression
Definition Z3Expr.h:105
u32_t id() const
get id
Definition Z3Expr.h:111
static z3::context & getContext()
Get z3 context, singleton design here to make sure we only have one context.
Definition Z3Expr.cpp:66
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:100
bool isProgExitCall(const CallICFGNode *cs)
Definition SVFUtil.cpp:397
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
llvm::IRBuilder IRBuilder
Definition BasicTypes.h:74
unsigned u32_t
Definition GeneralType.h:46