Static Value-Flow Analysis
Loading...
Searching...
No Matches
SVF::SaberCondAllocator Class Reference

#include <SaberCondAllocator.h>

Public Types

typedef Z3Expr Condition
typedef Map< u32_t, const ICFGNode * > IndexToTermInstMap
 z3 condition
typedef Map< u32_t, Condition > CondPosMap
 id to instruction map for z3
typedef Map< const SVFBasicBlock *, CondPosMap > BBCondMap
typedef Set< const SVFBasicBlock * > BasicBlockSet
 map bb to a Condition
typedef Map< const FunObjVar *, BasicBlockSet > FunToExitBBsMap
 map a function to all its basic blocks calling program exit
typedef Map< const SVFBasicBlock *, Condition > BBToCondMap
 map a basic block to its condition during control-flow guard computation
typedef FIFOWorkList< const SVFBasicBlock * > CFWorkList
 worklist for control-flow guard computation
typedef Map< const SVFGNode *, Set< const SVFGNode * > > SVFGNodeToSVFGNodeSetMap

Public Member Functions

 SaberCondAllocator ()
 Constructor.
virtual ~SaberCondAllocator ()
 Destructor.
std::string getMemUsage ()
 Statistics.
u32_t getCondNum ()
Condition condAnd (const Condition &lhs, const Condition &rhs)
 Condition operations.
Condition condOr (const Condition &lhs, const Condition &rhs)
Condition condNeg (const Condition &cond)
Condition getTrueCond () const
Condition getFalseCond () const
NodeBS exactCondElem (const Condition &cond)
 Iterator every element of the condition.
std::string dumpCond (const Condition &cond) const
Condition newCond (const ICFGNode *inst)
 Allocate a new condition.
void allocate ()
 Perform path allocation.
const ICFGNode * getCondInst (u32_t id) const
 Get/Set instruction based on Z3 expression id.
void setCondInst (const Condition &condition, const ICFGNode *inst)
bool isNegCond (u32_t id) const
bool postDominate (const SVFBasicBlock *bbKey, const SVFBasicBlock *bbValue) const
bool dominate (const SVFBasicBlock *bbKey, const SVFBasicBlock *bbValue) const
virtual Condition ComputeIntraVFGGuard (const SVFBasicBlock *src, const SVFBasicBlock *dst)
 Guard Computation for a value-flow (between two basic blocks).
virtual Condition ComputeInterCallVFGGuard (const SVFBasicBlock *src, const SVFBasicBlock *dst, const SVFBasicBlock *callBB)
virtual Condition ComputeInterRetVFGGuard (const SVFBasicBlock *src, const SVFBasicBlock *dst, const SVFBasicBlock *retBB)
virtual Condition getPHIComplementCond (const SVFBasicBlock *BB1, const SVFBasicBlock *BB2, const SVFBasicBlock *BB0)
void clearCFCond ()
void setCurEvalSVFGNode (const SVFGNode *node)
 Set current value for branch condition evaluation.
const SVFGNode * getCurEvalSVFGNode () const
 Get current value for branch condition evaluation.
void printPathCond ()
 Print out the path condition information.
bool isSatisfiable (const Condition &condition)
 whether condition is satisfiable
bool isAllPathReachable (Condition &condition)
 whether condition is satisfiable for all possible boolean guards
bool isEquivalentBranchCond (const Condition &lhs, const Condition &rhs) const
 Whether lhs and rhs are equivalent branch conditions.
ICFG * getICFG () const
bool setCFCond (const SVFBasicBlock *bb, const Condition &cond)
 Get/Set control-flow conditions.
Condition getCFCond (const SVFBasicBlock *bb) const
void setNegCondInst (const Condition &condition, const ICFGNode *inst)
 mark neg Z3 expression
SVFGNodeToSVFGNodeSetMap & getRemovedSUVFEdges ()

Protected Attributes

BBCondMap bbConds
 map basic block to its successors/predecessors branch conditions

Private Member Functions

virtual void allocateForBB (const SVFBasicBlock &bb)
 Allocate path condition for every basic block.
void setBranchCond (const SVFBasicBlock *bb, const SVFBasicBlock *succ, const Condition &cond)
 Get/Set a branch condition, and its terminator instruction.
Condition getBranchCond (const SVFBasicBlock *bb, const SVFBasicBlock *succ) const
 Get branch condition.
Condition getEvalBrCond (const SVFBasicBlock *bb, const SVFBasicBlock *succ)
 Get a condition, evaluate the value for conditions if necessary (e.g., testNull like express).
Condition evaluateBranchCond (const SVFBasicBlock *bb, const SVFBasicBlock *succ)
 Evaluate branch conditions.
Condition evaluateLoopExitBranch (const SVFBasicBlock *bb, const SVFBasicBlock *succ)
 Evaluate loop exit branch.
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.
void collectBBCallingProgExit (const SVFBasicBlock &bb)
 Collect basic block contains program exit function call.
bool isBBCallsProgExit (const SVFBasicBlock *bb)
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.
bool isTestNullExpr (const ICFGNode *test) const
 Return true if this is a test null expression.
bool isTestNotNullExpr (const ICFGNode *test) const
 Return true if this is a test not null expression.
bool isTestContainsNullAndTheValue (const CmpStmt *cmp) const
 Return true if two values on the predicate are what we want.
void destroy ()
 Release memory.
void extractSubConds (const Condition &condition, NodeBS &support) const
 extract subexpression from a Z3 expression

Private Attributes

FunToExitBBsMap funToExitBBsMap
 map a function to all its basic blocks calling program exit
BBToCondMap bbToCondMap
 map a basic block to its path condition starting from root
const SVFGNode * curEvalSVFGNode {}
 current llvm value to evaluate branch condition when computing guards
IndexToTermInstMap idToTermInstMap
NodeBS negConds
 key: z3 expression id, value: instruction
std::vector< Condition > conditionVec
 bit vector for distinguish neg
SVFGNodeToSVFGNodeSetMap removedSUVFEdges
 a counter for fresh condition

Static Private Attributes

static u32_t totalCondNum = 0
 vector storing z3expression

Detailed Description

SaberCondAllocator allocates conditions for each basic block of a certain CFG.

Definition at line 45 of file SaberCondAllocator.h.

Member Typedef Documentation

◆ BasicBlockSet

map bb to a Condition

Definition at line 54 of file SaberCondAllocator.h.

◆ BBCondMap

◆ BBToCondMap

map a basic block to its condition during control-flow guard computation

Definition at line 56 of file SaberCondAllocator.h.

◆ CFWorkList

worklist for control-flow guard computation

Definition at line 57 of file SaberCondAllocator.h.

◆ Condition

◆ CondPosMap

id to instruction map for z3

map a branch to its Condition

Definition at line 52 of file SaberCondAllocator.h.

◆ FunToExitBBsMap

map a function to all its basic blocks calling program exit

Definition at line 55 of file SaberCondAllocator.h.

◆ IndexToTermInstMap

z3 condition

Definition at line 51 of file SaberCondAllocator.h.

◆ SVFGNodeToSVFGNodeSetMap

Definition at line 58 of file SaberCondAllocator.h.

Constructor & Destructor Documentation

◆ SaberCondAllocator()

SaberCondAllocator::SaberCondAllocator ( )

Constructor.

Definition at line 51 of file SaberCondAllocator.cpp.

52{
53
54}

◆ ~SaberCondAllocator()

virtual SVF::SaberCondAllocator::~SaberCondAllocator ( )
inlinevirtual

Destructor.

Definition at line 65 of file SaberCondAllocator.h.

66 {
67 }

Member Function Documentation

◆ allocate()

void SaberCondAllocator::allocate ( )

Perform path allocation.

Allocate path condition for each branch

Definition at line 59 of file SaberCondAllocator.cpp.

60{
61 DBOUT(DGENERAL, outs() << pasMsg("path condition allocation starts\n"));
62
63 const CallGraph* svfirCallGraph = PAG::getPAG()->getCallGraph();
64 for (const auto& item: *svfirCallGraph)
65 {
66 const FunObjVar *func = (item.second)->getFunction();
67 if (!SVFUtil::isExtCall(func))
68 {
69 // Allocate conditions for a program.
70 for (FunObjVar::const_bb_iterator bit = func->begin(), ebit = func->end();
71 bit != ebit; ++bit)
72 {
73 const SVFBasicBlock* bb = bit->second;
75 allocateForBB(*bb);
76 }
77 }
78 }
79
82
83 DBOUT(DGENERAL, outs() << pasMsg("path condition allocation ends\n"));
84}
#define DBOUT(TYPE, X)
LLVM debug macros, define type of your DBUG model of each pass.
Definition SVFType.h:576
#define DGENERAL
Definition SVFType.h:582
cJSON * item
Definition cJSON.h:222
BasicBlockGraph::IDToNodeMapTy::const_iterator const_bb_iterator
const_bb_iterator begin() const
const_bb_iterator end() const
static const Option< bool > PrintPathCond
Definition Options.h:191
const CallGraph * getCallGraph()
Get CG.
Definition SVFIR.h:249
static SVFIR * getPAG(bool buildFromFile=false)
Singleton design here to make sure we only have one instance during any analysis.
Definition SVFIR.h:121
virtual void allocateForBB(const SVFBasicBlock &bb)
Allocate path condition for every basic block.
void printPathCond()
Print out the path condition information.
void collectBBCallingProgExit(const SVFBasicBlock &bb)
Collect basic block contains program exit function call.
std::string pasMsg(const std::string &msg)
Print each pass/phase message by converting a string into blue string output.
Definition SVFUtil.cpp:121
bool isExtCall(const FunObjVar *fun)
Definition SVFUtil.cpp:526
std::ostream & outs()
Overwrite llvm::outs().
Definition SVFUtil.h:58

◆ allocateForBB()

void SaberCondAllocator::allocateForBB ( const SVFBasicBlock & bb)
privatevirtual

Allocate path condition for every basic block.

Allocate conditions for a basic block and propagate its condition to its successors.

TODO: handle BranchInst and SwitchInst individually here!!

Definition at line 89 of file SaberCondAllocator.cpp.

90{
91
92 u32_t succ_number = bb.getNumSuccessors();
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);
100 u32_t bit_num = (u32_t) ceil(num);
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 {
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}
u32_t getNumSuccessors() const
const ICFGNode * back() const
std::vector< const SVFBasicBlock * > getSuccessors() const
Condition newCond(const ICFGNode *inst)
Allocate a new condition.
void setBranchCond(const SVFBasicBlock *bb, const SVFBasicBlock *succ, const Condition &cond)
Get/Set a branch condition, and its terminator instruction.
Condition condNeg(const Condition &cond)
Condition condAnd(const Condition &lhs, const Condition &rhs)
Condition operations.
Condition getTrueCond() const
unsigned u32_t
Definition GeneralType.h:67

◆ clearCFCond()

void SVF::SaberCondAllocator::clearCFCond ( )
inline

Definition at line 176 of file SaberCondAllocator.h.

177 {
178 bbToCondMap.clear();
179 }
BBToCondMap bbToCondMap
map a basic block to its path condition starting from root

◆ collectBBCallingProgExit()

void SaberCondAllocator::collectBBCallingProgExit ( const SVFBasicBlock & bb)
private

Collect basic block contains program exit function call.

Whether this basic block contains program exit function call

Definition at line 431 of file SaberCondAllocator.cpp.

432{
433
434 for (const auto& icfgNode: bb.getICFGNodeList())
435 {
436 if (const CallICFGNode* cs = SVFUtil::dyn_cast<CallICFGNode>(icfgNode))
438 {
439 const FunObjVar* svfun = bb.getParent();
440 funToExitBBsMap[svfun].insert(&bb);
441 }
442 }
443}
const FunObjVar * getParent() const
const std::vector< const ICFGNode * > & getICFGNodeList() const
FunToExitBBsMap funToExitBBsMap
map a function to all its basic blocks calling program exit
bool isProgExitCall(const CallICFGNode *cs)
Definition SVFUtil.cpp:480
LLVM_NODISCARD std::enable_if_t<!is_simple_type< Y >::value, typename cast_retty< X, const Y >::ret_type > dyn_cast(const Y &Val)
Definition Casting.h:405

◆ ComputeInterCallVFGGuard()

SaberCondAllocator::Condition SaberCondAllocator::ComputeInterCallVFGGuard ( const SVFBasicBlock * srcBB,
const SVFBasicBlock * dstBB,
const SVFBasicBlock * callBB )
virtual

Compute calling inter-procedural guards between two SVFGNodes (from caller to callee) src –c1--> callBB –true--> funEntryBB –c2--> dst the InterCallVFGGuard is c1 ^ c2

Definition at line 490 of file SaberCondAllocator.cpp.

492{
493 const SVFBasicBlock* funEntryBB = dstBB->getParent()->getEntryBlock();
494
495 Condition c1 = ComputeIntraVFGGuard(srcBB, callBB);
496 setCFCond(funEntryBB, condOr(getCFCond(funEntryBB), getCFCond(callBB)));
497 Condition c2 = ComputeIntraVFGGuard(funEntryBB, dstBB);
498 return condAnd(c1, c2);
499}
const SVFBasicBlock * getEntryBlock() const
Condition condOr(const Condition &lhs, const Condition &rhs)
bool setCFCond(const SVFBasicBlock *bb, const Condition &cond)
Get/Set control-flow conditions.
Condition getCFCond(const SVFBasicBlock *bb) const
virtual Condition ComputeIntraVFGGuard(const SVFBasicBlock *src, const SVFBasicBlock *dst)
Guard Computation for a value-flow (between two basic blocks).

◆ ComputeInterRetVFGGuard()

SaberCondAllocator::Condition SaberCondAllocator::ComputeInterRetVFGGuard ( const SVFBasicBlock * srcBB,
const SVFBasicBlock * dstBB,
const SVFBasicBlock * retBB )
virtual

Compute return inter-procedural guards between two SVFGNodes (from callee to caller) src –c1--> funExitBB –true--> retBB –c2--> dst the InterRetVFGGuard is c1 ^ c2

Definition at line 507 of file SaberCondAllocator.cpp.

508{
509 const FunObjVar* parent = srcBB->getParent();
510 const SVFBasicBlock* funExitBB = parent->getExitBB();
511
512 Condition c1 = ComputeIntraVFGGuard(srcBB, funExitBB);
513 setCFCond(retBB, condOr(getCFCond(retBB), getCFCond(funExitBB)));
514 Condition c2 = ComputeIntraVFGGuard(retBB, dstBB);
515 return condAnd(c1, c2);
516}
const SVFBasicBlock * getExitBB() const

◆ ComputeIntraVFGGuard()

SaberCondAllocator::Condition SaberCondAllocator::ComputeIntraVFGGuard ( const SVFBasicBlock * srcBB,
const SVFBasicBlock * dstBB )
virtual

Guard Computation for a value-flow (between two basic blocks).

Compute intra-procedural guards between two SVFGNodes (inside same function)

if the dstBB is the eligible loop exit of the current basic block we can early terminate the computation

calculate the branch condition if succ post dominate bb, then we get brCond quicker by using postDT note that we assume loop exit always post dominate loop bodys which means loops are approximated only once.

Definition at line 521 of file SaberCondAllocator.cpp.

522{
523
524 assert(srcBB->getParent() == dstBB->getParent() && "two basic blocks are not in the same function??");
525
526 if (postDominate(dstBB, srcBB))
527 return getTrueCond();
528
529 CFWorkList worklist;
530 worklist.push(srcBB);
531 setCFCond(srcBB, getTrueCond());
532
533 while (!worklist.empty())
534 {
535 const SVFBasicBlock* bb = worklist.pop();
536 Condition cond = getCFCond(bb);
537
540 Condition loopExitCond = evaluateLoopExitBranch(bb, dstBB);
541 if (!eq(loopExitCond, Condition::nullExpr()))
542 return condAnd(cond, loopExitCond);
543
544 for (const SVFBasicBlock* succ : bb->getSuccessors())
545 {
550 Condition brCond;
551 if (postDominate(succ, bb))
552 brCond = getTrueCond();
553 else
554 brCond = getEvalBrCond(bb, succ);
555
556 DBOUT(DSaber, outs() << " bb (" << bb->getName() <<
557 ") --> " << "succ_bb (" << succ->getName() << ") condition: " << brCond << "\n");
558 Condition succPathCond = condAnd(cond, brCond);
559 if (setCFCond(succ, condOr(getCFCond(succ), succPathCond)))
560 worklist.push(succ);
561 }
562 }
563
564 DBOUT(DSaber, outs() << " src_bb (" << srcBB->getName() <<
565 ") --> " << "dst_bb (" << dstBB->getName() << ") condition: " << getCFCond(dstBB)
566 << "\n");
567
568 return getCFCond(dstBB);
569}
#define DSaber
Definition SVFType.h:596
virtual const std::string & getName() const
Definition SVFValue.h:184
bool postDominate(const SVFBasicBlock *bbKey, const SVFBasicBlock *bbValue) const
Condition evaluateLoopExitBranch(const SVFBasicBlock *bb, const SVFBasicBlock *succ)
Evaluate loop exit branch.
FIFOWorkList< const SVFBasicBlock * > CFWorkList
worklist for control-flow guard computation
Condition getEvalBrCond(const SVFBasicBlock *bb, const SVFBasicBlock *succ)
Get a condition, evaluate the value for conditions if necessary (e.g., testNull like express).
static z3::expr nullExpr()
null expression
Definition Z3Expr.h:105

◆ condAnd()

Condition SVF::SaberCondAllocator::condAnd ( const Condition & lhs,
const Condition & rhs )
inline

Condition operations.

Definition at line 86 of file SaberCondAllocator.h.

87 {
88 return Condition::AND(lhs,rhs);
89 }
static Z3Expr AND(const Z3Expr &lhs, const Z3Expr &rhs)
compute AND, used for branch condition
Definition Z3Expr.cpp:92

◆ condNeg()

Condition SVF::SaberCondAllocator::condNeg ( const Condition & cond)
inline

Definition at line 94 of file SaberCondAllocator.h.

95 {
96 return Condition::NEG(cond);
97 }
static Z3Expr NEG(const Z3Expr &z3Expr)
compute NEG
Definition Z3Expr.h:301

◆ condOr()

Condition SVF::SaberCondAllocator::condOr ( const Condition & lhs,
const Condition & rhs )
inline

Definition at line 90 of file SaberCondAllocator.h.

91 {
92 return Condition::OR(lhs,rhs);
93 }
static Z3Expr OR(const Z3Expr &lhs, const Z3Expr &rhs)
compute OR, used for branch condition
Definition Z3Expr.cpp:130

◆ destroy()

void SVF::SaberCondAllocator::destroy ( )
inlineprivate

Release memory.

Definition at line 292 of file SaberCondAllocator.h.

293 {
294
295 }

◆ dominate()

bool SVF::SaberCondAllocator::dominate ( const SVFBasicBlock * bbKey,
const SVFBasicBlock * bbValue ) const
inline

Definition at line 156 of file SaberCondAllocator.h.

157 {
158 const FunObjVar* keyFunc = bbKey->getParent();
159 const FunObjVar* valueFunc = bbValue->getParent();
160 bool funcEq = (keyFunc == valueFunc);
161 (void)funcEq; // Suppress warning of unused variable under release build
162 assert(funcEq && "two basicblocks should be in the same function!");
163 return keyFunc->dominate(bbKey,bbValue);
164 }

◆ dumpCond()

std::string SVF::SaberCondAllocator::dumpCond ( const Condition & cond) const
inline

Definition at line 114 of file SaberCondAllocator.h.

115 {
116 return Condition::dumpStr(cond);
117 }
static std::string dumpStr(const Z3Expr &z3Expr)
output Z3 expression as a string
Definition Z3Expr.cpp:168

◆ evaluateBranchCond()

SaberCondAllocator::Condition SaberCondAllocator::evaluateBranchCond ( const SVFBasicBlock * bb,
const SVFBasicBlock * succ )
private

Evaluate branch conditions.

Evaluate the branch condition

(1) Evaluate a branch when it reaches a program exit (2) Evaluate a branch when it is loop exit branch (3) Evaluate a branch when it is a test null like condition

Definition at line 302 of file SaberCondAllocator.cpp.

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??");
323 Condition evalLoopExit = evaluateLoopExitBranch(bb, succ);
324 if (!eq(evalLoopExit, Condition::nullExpr()))
325 return evalLoopExit;
326
327 Condition evalProgExit = evaluateProgExit(branchStmt, succ);
328 if (!eq(evalProgExit, Condition::nullExpr()))
329 return evalProgExit;
330
331 Condition evalTestNullLike = evaluateTestNullLikeExpr(branchStmt, succ);
332 if (!eq(evalTestNullLike, Condition::nullExpr()))
333 return evalTestNullLike;
334 break;
335 }
336 }
337 }
338 }
339
340 return getBranchCond(bb, succ);
341}
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 getBranchCond(const SVFBasicBlock *bb, const SVFBasicBlock *succ) const
Get branch condition.

◆ evaluateLoopExitBranch()

SaberCondAllocator::Condition SaberCondAllocator::evaluateLoopExitBranch ( const SVFBasicBlock * bb,
const SVFBasicBlock * dst )
private

Evaluate loop exit branch.

Evaluate loop exit branch to be true if bb is loop header and succ is the only exit basic block outside the loop (excluding exit bbs which call program exit) for all other case, we conservatively evaluate false for now

exclude exit bb which calls program exit

if the dst dominate all other loop exit bbs, then dst can certainly be reached

Definition at line 266 of file SaberCondAllocator.cpp.

267{
268 const FunObjVar* svffun = bb->getParent();
269 assert(svffun == dst->getParent() && "two basic blocks should be in the same function");
270
271 if (svffun->isLoopHeader(bb))
272 {
273 Set<const SVFBasicBlock* > filteredbbs;
274 std::vector<const SVFBasicBlock*> exitbbs;
275 svffun->getExitBlocksOfLoop(bb,exitbbs);
277 for(const SVFBasicBlock* eb : exitbbs)
278 {
279 if(!isBBCallsProgExit(eb))
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}
void getExitBlocksOfLoop(const SVFBasicBlock *bb, BBList &exitbbs) const
bool isLoopHeader(const SVFBasicBlock *bb) const
bool isBBCallsProgExit(const SVFBasicBlock *bb)
std::unordered_set< Key, Hash, KeyEqual, Allocator > Set
Definition GeneralType.h:51

◆ evaluateProgExit()

SaberCondAllocator::Condition SaberCondAllocator::evaluateProgExit ( const BranchStmt * branchStmt,
const SVFBasicBlock * succ )
private

Return condition when there is a branch calls program exit.

Evaluate condition for program exit (e.g., exit(0))

then branch calls program exit

else branch calls program exit

no branch call program exit

Definition at line 222 of file SaberCondAllocator.cpp.

223{
224 const SVFBasicBlock* succ1 = branchStmt->getSuccessor(0)->getBB();
225 const SVFBasicBlock* succ2 = branchStmt->getSuccessor(1)->getBB();
226
227 bool branch1 = isBBCallsProgExit(succ1);
228 bool branch2 = isBBCallsProgExit(succ2);
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}
const ICFGNode * getSuccessor(u32_t i) const
virtual const SVFBasicBlock * getBB() const
Return the basic block of this ICFGNode.
Definition ICFGNode.h:81
Condition getFalseCond() const

◆ evaluateTestNullLikeExpr()

SaberCondAllocator::Condition SaberCondAllocator::evaluateTestNullLikeExpr ( const BranchStmt * branchStmt,
const SVFBasicBlock * succ )
private

Return branch condition after evaluating test null like expression.

Evaluate null like expression for source-sink related bug detection in SABER

Definition at line 186 of file SaberCondAllocator.cpp.

187{
188
189 const SVFBasicBlock* succ1 = branchStmt->getSuccessor(0)->getBB();
190
191 const ValVar* condVar = SVFUtil::cast<ValVar>(branchStmt->getCondition());
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 }
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}
const ValVar * getCondition() const
Return the condition.
virtual bool isConstDataOrAggDataButNotNullPtr() const
Check if this variable represents constant data/metadata but not null pointer.
bool isTestNullExpr(const ICFGNode *test) const
Return true if this is a test null expression.
bool isTestNotNullExpr(const ICFGNode *test) const
Return true if this is a test not null expression.
const ICFGNode * getICFGNode() const
std::enable_if_t<!is_simple_type< Y >::value, typename cast_retty< X, const Y >::ret_type > cast(const Y &Val)
Definition Casting.h:360

◆ exactCondElem()

NodeBS SVF::SaberCondAllocator::exactCondElem ( const Condition & cond)
inline

Iterator every element of the condition.

Definition at line 107 of file SaberCondAllocator.h.

108 {
109 NodeBS elems;
110 extractSubConds(cond, elems);
111 return elems;
112 }
void extractSubConds(const Condition &condition, NodeBS &support) const
extract subexpression from a Z3 expression
SparseBitVector NodeBS
Definition GeneralType.h:82

◆ extractSubConds()

void SaberCondAllocator::extractSubConds ( const Condition & condition,
NodeBS & support ) const
private

extract subexpression from a Z3 expression

Definition at line 639 of file SaberCondAllocator.cpp.

640{
641 if (condition.getExpr().num_args() == 1 && isNegCond(condition.id()))
642 {
643 support.set(condition.getExpr().id());
644 return;
645 }
646 if (condition.getExpr().num_args() == 0)
647 if (!condition.getExpr().is_true() && !condition.getExpr().is_false())
648 support.set(condition.getExpr().id());
649 for (u32_t i = 0; i < condition.getExpr().num_args(); ++i)
650 {
651 Condition expr = condition.getExpr().arg(i);
652 extractSubConds(expr, support);
653 }
654
655}
bool isNegCond(u32_t id) const
void set(unsigned Idx)

◆ getBranchCond()

SaberCondAllocator::Condition SaberCondAllocator::getBranchCond ( const SVFBasicBlock * bb,
const SVFBasicBlock * succ ) const
private

Get branch condition.

Get a branch condition

Definition at line 142 of file SaberCondAllocator.cpp.

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}
u32_t getBBSuccessorPos(const SVFBasicBlock *Succ)
BBCondMap bbConds
map basic block to its successors/predecessors branch conditions

◆ getCFCond()

Condition SVF::SaberCondAllocator::getCFCond ( const SVFBasicBlock * bb) const
inline

Definition at line 224 of file SaberCondAllocator.h.

225 {
226 BBToCondMap::const_iterator it = bbToCondMap.find(bb);
227 if(it==bbToCondMap.end())
228 {
229 return getFalseCond();
230 }
231 return it->second;
232 }

◆ getCondInst()

const ICFGNode * SVF::SaberCondAllocator::getCondInst ( u32_t id) const
inline

Get/Set instruction based on Z3 expression id.

Definition at line 127 of file SaberCondAllocator.h.

128 {
129 IndexToTermInstMap::const_iterator it = idToTermInstMap.find(id);
130 assert(it != idToTermInstMap.end() && "this should be a fresh condition");
131 return it->second;
132 }
IndexToTermInstMap idToTermInstMap

◆ getCondNum()

u32_t SVF::SaberCondAllocator::getCondNum ( )
inline

Definition at line 78 of file SaberCondAllocator.h.

79 {
80 return totalCondNum;
81 }
static u32_t totalCondNum
vector storing z3expression

◆ getCurEvalSVFGNode()

const SVFGNode * SVF::SaberCondAllocator::getCurEvalSVFGNode ( ) const
inline

Get current value for branch condition evaluation.

Definition at line 186 of file SaberCondAllocator.h.

187 {
188 return curEvalSVFGNode;
189 }
const SVFGNode * curEvalSVFGNode
current llvm value to evaluate branch condition when computing guards

◆ getEvalBrCond()

SaberCondAllocator::Condition SaberCondAllocator::getEvalBrCond ( const SVFBasicBlock * bb,
const SVFBasicBlock * succ )
private

Get a condition, evaluate the value for conditions if necessary (e.g., testNull like express).

Definition at line 157 of file SaberCondAllocator.cpp.

158{
159 if (getCurEvalSVFGNode() && getCurEvalSVFGNode()->getValue())
160 return evaluateBranchCond(bb, succ);
161 else
162 return getBranchCond(bb, succ);
163}
const SVFGNode * getCurEvalSVFGNode() const
Get current value for branch condition evaluation.
Condition evaluateBranchCond(const SVFBasicBlock *bb, const SVFBasicBlock *succ)
Evaluate branch conditions.

◆ getFalseCond()

Condition SVF::SaberCondAllocator::getFalseCond ( ) const
inline

Definition at line 102 of file SaberCondAllocator.h.

103 {
105 }
static Z3Expr getFalseCond()
Return the unique false condition.
Definition Z3Expr.h:295

◆ getICFG()

ICFG * SVF::SaberCondAllocator::getICFG ( ) const
inline

Definition at line 207 of file SaberCondAllocator.h.

208 {
209 return PAG::getPAG()->getICFG();
210 }
ICFG * getICFG() const
Definition SVFIR.h:232

◆ getMemUsage()

std::string SVF::SaberCondAllocator::getMemUsage ( )
inline

Statistics.

Definition at line 70 of file SaberCondAllocator.h.

71 {
72 u32_t vmrss, vmsize;
73 if (SVFUtil::getMemoryUsageKB(&vmrss, &vmsize))
74 return std::to_string(vmsize) + "KB";
75 else
76 return "cannot read memory usage";
77 }
bool getMemoryUsageKB(u32_t *vmrss_kb, u32_t *vmsize_kb)
Get memory usage from system file. Return TRUE if succeed.
Definition SVFUtil.cpp:199

◆ getPHIComplementCond()

SaberCondAllocator::Condition SaberCondAllocator::getPHIComplementCond ( const SVFBasicBlock * BB1,
const SVFBasicBlock * BB2,
const SVFBasicBlock * BB0 )
virtual

Get complement condition (from B1 to B0) according to a complementBB (BB2) at a phi e.g., B0: dstBB; B1:incomingBB; B2:complementBB

Get complement phi condition e.g., B0: dstBB; B1:incomingBB; B2:complementBB Assume B0 (phi node) is the successor of both B1 and B2. If B1 dominates B2, and B0 not dominate B2 then condition from B1-->B0 = neg(B1-->B2)^(B1-->B0)

avoid both BB0 and BB1 dominate BB2 (e.g., while loop), then BB2 is not necessarily a complement BB

Definition at line 470 of file SaberCondAllocator.cpp.

471{
472 assert(BB1 && BB2 && "expect nullptr BB here!");
473
475 if (dominate(BB1, BB2) && ! dominate(BB0, BB2))
476 {
477 Condition cond = ComputeIntraVFGGuard(BB1, BB2);
478 return condNeg(cond);
479 }
480
481 return getTrueCond();
482}
bool dominate(const SVFBasicBlock *bbKey, const SVFBasicBlock *bbValue) const

◆ getRemovedSUVFEdges()

SVFGNodeToSVFGNodeSetMap & SVF::SaberCondAllocator::getRemovedSUVFEdges ( )
inline

Definition at line 243 of file SaberCondAllocator.h.

244 {
245 return removedSUVFEdges;
246 }
SVFGNodeToSVFGNodeSetMap removedSUVFEdges
a counter for fresh condition

◆ getTrueCond()

Condition SVF::SaberCondAllocator::getTrueCond ( ) const
inline

Definition at line 98 of file SaberCondAllocator.h.

99 {
100 return Condition::getTrueCond();
101 }
static Z3Expr getTrueCond()
Return the unique true condition.
Definition Z3Expr.h:288

◆ isAllPathReachable()

bool SVF::SaberCondAllocator::isAllPathReachable ( Condition & condition)
inline

whether condition is satisfiable for all possible boolean guards

Definition at line 199 of file SaberCondAllocator.h.

200 {
202 }
bool isEquivalentBranchCond(const Condition &lhs, const Condition &rhs) const
Whether lhs and rhs are equivalent branch conditions.

◆ isBBCallsProgExit()

bool SaberCondAllocator::isBBCallsProgExit ( const SVFBasicBlock * bb)
private

Whether this basic block contains program exit function call

Definition at line 448 of file SaberCondAllocator.cpp.

449{
450 const FunObjVar* svfun = bb->getParent();
451 FunToExitBBsMap::const_iterator it = funToExitBBsMap.find(svfun);
452 if (it != funToExitBBsMap.end())
453 {
454 for (const auto &bit: it->second)
455 {
456 if (postDominate(bit, bb))
457 return true;
458 }
459 }
460 return false;
461}

◆ isEQCmp()

bool SaberCondAllocator::isEQCmp ( const CmpStmt * cmp) const
private

Evaluate test null/not null like expressions.

Return true if the predicate of this compare instruction is equal

Definition at line 343 of file SaberCondAllocator.cpp.

344{
345 return (cmp->getPredicate() == CmpStmt::ICMP_EQ);
346}
u32_t getPredicate() const

◆ isEquivalentBranchCond()

bool SaberCondAllocator::isEquivalentBranchCond ( const Condition & lhs,
const Condition & rhs ) const

Whether lhs and rhs are equivalent branch conditions.

check equal using z3 solver

Definition at line 615 of file SaberCondAllocator.cpp.

617{
618 Condition::getSolver().push();
619 Condition::getSolver().add(lhs.getExpr() != rhs.getExpr());
620 z3::check_result res = Condition::getSolver().check();
621 Condition::getSolver().pop();
622 return res == z3::unsat;
623}
static z3::solver & getSolver()
Get z3 solver, singleton design here to make sure we only have one context.
Definition Z3Expr.cpp:56

◆ isNECmp()

bool SaberCondAllocator::isNECmp ( const CmpStmt * cmp) const
private

Return true if the predicate of this compare instruction is not equal.

Definition at line 348 of file SaberCondAllocator.cpp.

349{
350 return (cmp->getPredicate() == CmpStmt::ICMP_NE);
351}
@ ICMP_NE
not equal

◆ isNegCond()

bool SVF::SaberCondAllocator::isNegCond ( u32_t id) const
inline

Definition at line 141 of file SaberCondAllocator.h.

142 {
143 return negConds.test(id);
144 }
NodeBS negConds
key: z3 expression id, value: instruction

◆ isSatisfiable()

bool SaberCondAllocator::isSatisfiable ( const Condition & condition)

whether condition is satisfiable

Definition at line 626 of file SaberCondAllocator.cpp.

627{
628 Condition::getSolver().push();
629 Condition::getSolver().add(condition.getExpr());
630 z3::check_result result = Condition::getSolver().check();
631 Condition::getSolver().pop();
632 if (result == z3::sat || result == z3::unknown)
633 return true;
634 else
635 return false;
636}

◆ isTestContainsNullAndTheValue()

bool SaberCondAllocator::isTestContainsNullAndTheValue ( const CmpStmt * cmp) const
private

Return true if two values on the predicate are what we want.

Return true if: (1) cmp contains a null value (2) there is an indirect/direct edge from cur evaluated SVFG node to cmp operand

e.g., indirect edge: cur svfg node -> 1. store i32* %0, i32** p, align 8, !dbg !157 cmp operand -> 2. %1 = load i32*, i32** p, align 8, !dbg !159

  1. tobool = icmp ne i32* %1, null, !dbg !159
  2. br i1 tobool, label if.end, label if.then, !dbg !161 There is an indirect edge 1->2 with value %0

direct edge: cur svfg node -> 1. %3 = tail call i8* @malloc(i64 16), !dbg !22 (cmp operand) 2. %4 = icmp eq i8* %3, null, !dbg !28

  1. br i1 %4, label %7, label %5, !dbg !30 There is an direct edge 1->2 with value %3

Definition at line 399 of file SaberCondAllocator.cpp.

400{
401
402 // must be val var?
403 const SVFVar* op0 = cmp->getOpVar(0);
404 const SVFVar* op1 = cmp->getOpVar(1);
406 {
407 Set<const SVFVar* > inDirVal;
408 inDirVal.insert(getCurEvalSVFGNode()->getValue());
409 for (const auto &it: getCurEvalSVFGNode()->getOutEdges())
410 {
411 inDirVal.insert(it->getDstNode()->getValue());
412 }
413 return inDirVal.find(op0) != inDirVal.end();
414 }
416 {
417 Set<const SVFVar* > inDirVal;
418 inDirVal.insert(getCurEvalSVFGNode()->getValue());
419 for (const auto &it: getCurEvalSVFGNode()->getOutEdges())
420 {
421 inDirVal.insert(it->getDstNode()->getValue());
422 }
423 return inDirVal.find(op1) != inDirVal.end();
424 }
425 return false;
426}
const ValVar * getOpVar(u32_t pos) const
Operand SVFVars.
LLVM_NODISCARD bool isa(const Y &Val)
Definition Casting.h:241

◆ isTestNotNullExpr()

bool SaberCondAllocator::isTestNotNullExpr ( const ICFGNode * test) const
private

Return true if this is a test not null expression.

Definition at line 366 of file SaberCondAllocator.cpp.

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 {
373 return isTestContainsNullAndTheValue(cmp) && isNECmp(cmp);
374 }
375 }
376 return false;
377}
bool isTestContainsNullAndTheValue(const CmpStmt *cmp) const
Return true if two values on the predicate are what we want.
bool isNECmp(const CmpStmt *cmp) const
Return true if the predicate of this compare instruction is not equal.

◆ isTestNullExpr()

bool SaberCondAllocator::isTestNullExpr ( const ICFGNode * test) const
private

Return true if this is a test null expression.

Definition at line 353 of file SaberCondAllocator.cpp.

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 {
360 return isTestContainsNullAndTheValue(cmp) && isEQCmp(cmp);
361 }
362 }
363 return false;
364}
bool isEQCmp(const CmpStmt *cmp) const
Evaluate test null/not null like expressions.

◆ newCond()

SaberCondAllocator::Condition SaberCondAllocator::newCond ( const ICFGNode * inst)

Allocate a new condition.

Definition at line 602 of file SaberCondAllocator.cpp.

603{
604 u32_t condCountIdx = totalCondNum++;
605 Condition expr = Condition::getContext().bool_const(("c" + std::to_string(condCountIdx)).c_str());
606 Condition negCond = Condition::NEG(expr);
607 setCondInst(expr, inst);
608 setNegCondInst(negCond, inst);
609 conditionVec.push_back(expr);
610 conditionVec.push_back(negCond);
611 return expr;
612}
void setNegCondInst(const Condition &condition, const ICFGNode *inst)
mark neg Z3 expression
void setCondInst(const Condition &condition, const ICFGNode *inst)
std::vector< Condition > conditionVec
bit vector for distinguish neg
static z3::context & getContext()
Get z3 context, singleton design here to make sure we only have one context.
Definition Z3Expr.cpp:66

◆ postDominate()

bool SVF::SaberCondAllocator::postDominate ( const SVFBasicBlock * bbKey,
const SVFBasicBlock * bbValue ) const
inline

Definition at line 146 of file SaberCondAllocator.h.

147 {
148 const FunObjVar* keyFunc = bbKey->getParent();
149 const FunObjVar* valueFunc = bbValue->getParent();
150 bool funcEq = (keyFunc == valueFunc);
151 (void)funcEq; // Suppress warning of unused variable under release build
152 assert(funcEq && "two basicblocks should be in the same function!");
153 return keyFunc->postDominate(bbKey,bbValue);
154 }

◆ printPathCond()

void SaberCondAllocator::printPathCond ( )

Print out the path condition information.

Print path conditions

Definition at line 575 of file SaberCondAllocator.cpp.

576{
577
578 outs() << "print path condition\n";
579
580 for (const auto &bbCond: bbConds)
581 {
582 const SVFBasicBlock* bb = bbCond.first;
583 for (const auto &cit: bbCond.second)
584 {
585 u32_t i = 0;
586 for (const SVFBasicBlock* succ: bb->getSuccessors())
587 {
588 if (i == cit.first)
589 {
590 Condition cond = cit.second;
591 outs() << bb->getName() << "-->" << succ->getName() << ":";
592 outs() << dumpCond(cond) << "\n";
593 break;
594 }
595 i++;
596 }
597 }
598 }
599}
std::string dumpCond(const Condition &cond) const

◆ setBranchCond()

void SaberCondAllocator::setBranchCond ( const SVFBasicBlock * bb,
const SVFBasicBlock * succ,
const Condition & cond )
private

Get/Set a branch condition, and its terminator instruction.

Set branch condition

Set a branch condition

we only care about basic blocks have more than one successor

FIXME: llvm getNumSuccessors allows duplicated block in the successors, it makes this assertion fail In this case we may waste a condition allocation, because the overwrite of the previous cond

Definition at line 168 of file SaberCondAllocator.cpp.

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}
Map< u32_t, Condition > CondPosMap
id to instruction map for z3

◆ setCFCond()

bool SVF::SaberCondAllocator::setCFCond ( const SVFBasicBlock * bb,
const Condition & cond )
inline

Get/Set control-flow conditions.

Definition at line 214 of file SaberCondAllocator.h.

215 {
216 BBToCondMap::iterator it = bbToCondMap.find(bb);
217 // until a fixed-point is reached (condition is not changed)
218 if(it!=bbToCondMap.end() && isEquivalentBranchCond(it->second, cond))
219 return false;
220
221 bbToCondMap[bb] = cond;
222 return true;
223 }

◆ setCondInst()

void SVF::SaberCondAllocator::setCondInst ( const Condition & condition,
const ICFGNode * inst )
inline

Definition at line 134 of file SaberCondAllocator.h.

135 {
136 assert(idToTermInstMap.find(condition.id()) == idToTermInstMap.end() && "this should be a fresh condition");
137 idToTermInstMap[condition.id()] = inst;
138 }

◆ setCurEvalSVFGNode()

void SVF::SaberCondAllocator::setCurEvalSVFGNode ( const SVFGNode * node)
inline

Set current value for branch condition evaluation.

Definition at line 181 of file SaberCondAllocator.h.

182 {
183 curEvalSVFGNode = node;
184 }

◆ setNegCondInst()

void SVF::SaberCondAllocator::setNegCondInst ( const Condition & condition,
const ICFGNode * inst )
inline

mark neg Z3 expression

Definition at line 237 of file SaberCondAllocator.h.

238 {
239 setCondInst(condition, inst);
240 negConds.set(condition.id());
241 }

Member Data Documentation

◆ bbConds

BBCondMap SVF::SaberCondAllocator::bbConds
protected

map basic block to its successors/predecessors branch conditions

Definition at line 311 of file SaberCondAllocator.h.

◆ bbToCondMap

BBToCondMap SVF::SaberCondAllocator::bbToCondMap
private

map a basic block to its path condition starting from root

Definition at line 302 of file SaberCondAllocator.h.

◆ conditionVec

std::vector<Condition> SVF::SaberCondAllocator::conditionVec
private

bit vector for distinguish neg

Definition at line 306 of file SaberCondAllocator.h.

◆ curEvalSVFGNode

const SVFGNode* SVF::SaberCondAllocator::curEvalSVFGNode {}
private

current llvm value to evaluate branch condition when computing guards

Definition at line 303 of file SaberCondAllocator.h.

303{};

◆ funToExitBBsMap

FunToExitBBsMap SVF::SaberCondAllocator::funToExitBBsMap
private

map a function to all its basic blocks calling program exit

Definition at line 301 of file SaberCondAllocator.h.

◆ idToTermInstMap

IndexToTermInstMap SVF::SaberCondAllocator::idToTermInstMap
private

Definition at line 304 of file SaberCondAllocator.h.

◆ negConds

NodeBS SVF::SaberCondAllocator::negConds
private

key: z3 expression id, value: instruction

Definition at line 305 of file SaberCondAllocator.h.

◆ removedSUVFEdges

SVFGNodeToSVFGNodeSetMap SVF::SaberCondAllocator::removedSUVFEdges
private

a counter for fresh condition

Definition at line 308 of file SaberCondAllocator.h.

◆ totalCondNum

u32_t SaberCondAllocator::totalCondNum = 0
staticprivate

vector storing z3expression

Definition at line 307 of file SaberCondAllocator.h.


The documentation for this class was generated from the following files: