svf-tools 1.0.657 → 1.0.659

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "svf-tools",
3
- "version": "1.0.657",
3
+ "version": "1.0.659",
4
4
  "description": "* <b>[TypeClone](https://github.com/SVF-tools/SVF/wiki/TypeClone) published in our [ECOOP paper](https://yuleisui.github.io/publications/ecoop20.pdf) is now available in SVF </b> * <b>SVF now uses a single script for its build. Just type [`source ./build.sh`](https://github.com/SVF-tools/SVF/blob/master/build.sh) in your terminal, that's it!</b> * <b>SVF now supports LLVM-10.0.0! </b> * <b>We thank [bsauce](https://github.com/bsauce) for writing a user manual of SVF ([link1](https://www.jianshu.com/p/068a08ec749c) and [link2](https://www.jianshu.com/p/777c30d4240e)) in Chinese </b> * <b>SVF now supports LLVM-9.0.0 (Thank [Byoungyoung Lee](https://github.com/SVF-tools/SVF/issues/142) for his help!). </b> * <b>SVF now supports a set of [field-sensitive pointer analyses](https://yuleisui.github.io/publications/sas2019a.pdf). </b> * <b>[Use SVF as an external lib](https://github.com/SVF-tools/SVF/wiki/Using-SVF-as-a-lib-in-your-own-tool) for your own project (Contributed by [Hongxu Chen](https://github.com/HongxuChen)). </b> * <b>SVF now supports LLVM-7.0.0. </b> * <b>SVF now supports Docker. [Try SVF in Docker](https://github.com/SVF-tools/SVF/wiki/Try-SVF-in-Docker)! </b> * <b>SVF now supports [LLVM-6.0.0](https://github.com/svf-tools/SVF/pull/38) (Contributed by [Jack Anthony](https://github.com/jackanth)). </b> * <b>SVF now supports [LLVM-4.0.0](https://github.com/svf-tools/SVF/pull/23) (Contributed by Jared Carlson. Thank [Jared](https://github.com/jcarlson23) and [Will](https://github.com/dtzWill) for their in-depth [discussions](https://github.com/svf-tools/SVF/pull/18) about updating SVF!) </b> * <b>SVF now supports analysis for C++ programs.</b> <br />",
5
5
  "main": "index.js",
6
6
  "scripts": {
@@ -51,6 +51,10 @@ public:
51
51
  /// Initialize the grammar, graph, solver
52
52
  virtual void initialize();
53
53
 
54
+ /// Initialize Solver
55
+ virtual void initializeSolver();
56
+
57
+
54
58
  /// Print grammar and graph
55
59
  virtual void finalize();
56
60
 
@@ -143,9 +147,19 @@ public:
143
147
  POCRAlias(SVFIR* ir) : CFLAlias(ir)
144
148
  {
145
149
  }
150
+ /// Initialize POCR Solver
151
+ virtual void initializeSolver();
152
+ };
146
153
 
147
- /// Initialize the grammar, graph, CFLData, solver
148
- virtual void initialize();
154
+ class POCRHybrid : public CFLAlias
155
+ {
156
+ public:
157
+ POCRHybrid(SVFIR* ir) : CFLAlias(ir)
158
+ {
159
+ }
160
+
161
+ /// Initialize POCRHybrid Solver
162
+ virtual void initializeSolver();
149
163
  };
150
164
  } // End namespace SVF
151
165
 
@@ -3,7 +3,7 @@ Start:
3
3
  Terminal:
4
4
  addr copy store load gep vgep
5
5
  Productions:
6
- F -> epsilon | F copy | addr Memflow | F store V load | store Memflow load;
6
+ F -> epsilon | F copy | addr Memflow | F store V load | store Memflow load | F F;
7
7
  Fbar -> epsilon | copybar Fbar | Memflowbar addrbar | loadbar V storebar Fbar | loadbar Memflowbar storebar;
8
8
  V -> Fbar V F | addrbar addr | gepbar_i V gep_i | gepbarpath V gep_0 | gepbar_i F gep_i | gepbar_i Fbar gep_i;
9
9
  copy -> vgep;
@@ -40,112 +40,6 @@ namespace SVF
40
40
  {
41
41
  typedef GrammarBase::Symbol Label;
42
42
 
43
- /*!
44
- * Hybrid graph representation for transitive relations
45
- * The implementation is based on
46
- * Yuxiang Lei, Yulei Sui, Shuo Ding, and Qirun Zhang.
47
- * Taming Transitive Redundancy for Context-Free Language Reachability.
48
- * ACM SIGPLAN Conference on Object-Oriented Programming, Systems, Languages, and Applications
49
- */
50
- class HybridData
51
- {
52
- public:
53
- struct TreeNode
54
- {
55
- NodeID id;
56
- std::unordered_set<TreeNode*> children;
57
-
58
- TreeNode(NodeID nId) : id(nId)
59
- {}
60
-
61
- ~TreeNode()
62
- {
63
- }
64
-
65
- inline bool operator==(const TreeNode& rhs) const
66
- {
67
- return id == rhs.id;
68
- }
69
-
70
- inline bool operator<(const TreeNode& rhs) const
71
- {
72
- return id < rhs.id;
73
- }
74
- };
75
-
76
-
77
- public:
78
- Map<NodeID, std::unordered_map<NodeID, TreeNode*>> indMap; // indMap[v][u] points to node v in tree(u)
79
-
80
- HybridData()
81
- {}
82
-
83
- ~HybridData()
84
- {
85
- for (auto iter1: indMap)
86
- {
87
- for (auto iter2: iter1.second)
88
- {
89
- delete iter2.second;
90
- iter2.second = NULL;
91
- }
92
- }
93
- }
94
-
95
- bool hasInd(NodeID src, NodeID dst)
96
- {
97
- auto it = indMap.find(dst);
98
- if (it == indMap.end())
99
- return false;
100
- return (it->second.find(src) != it->second.end());
101
- }
102
-
103
- /// Add a node dst to tree(src)
104
- TreeNode* addInd(NodeID src, NodeID dst)
105
- {
106
- auto resIns = indMap[dst].insert(std::make_pair(src, new TreeNode(dst)));
107
- if (resIns.second)
108
- return resIns.first->second;
109
- return nullptr;
110
- }
111
-
112
- /// Get the node dst in tree(src)
113
- TreeNode* getNode(NodeID src, NodeID dst)
114
- {
115
- return indMap[dst][src];
116
- }
117
-
118
- /// add v into desc(x) as a child of u
119
- void insertEdge(TreeNode* u, TreeNode* v)
120
- {
121
- u->children.insert(v);
122
- }
123
-
124
- void addArc(NodeID src, NodeID dst)
125
- {
126
- if (!hasInd(src, dst))
127
- {
128
- for (auto iter: indMap[src])
129
- {
130
- meld(iter.first, getNode(iter.first, src), getNode(dst, dst));
131
- }
132
- }
133
- }
134
-
135
- void meld(NodeID x, TreeNode* uNode, TreeNode* vNode)
136
- {
137
- TreeNode* newVNode = addInd(x, vNode->id);
138
- if (!newVNode)
139
- return;
140
-
141
- insertEdge(uNode, newVNode);
142
- for (TreeNode* vChild: vNode->children)
143
- {
144
- meld(x, newVNode, vChild);
145
- }
146
- }
147
- };
148
-
149
43
  class CFLSolver
150
44
  {
151
45
 
@@ -389,6 +283,92 @@ public:
389
283
 
390
284
  virtual void initialize();
391
285
  };
286
+ /*!
287
+ * Hybrid graph representation for transitive relations
288
+ * The implementation is based on
289
+ * Yuxiang Lei, Yulei Sui, Shuo Ding, and Qirun Zhang.
290
+ * Taming Transitive Redundancy for Context-Free Language Reachability.
291
+ * ACM SIGPLAN Conference on Object-Oriented Programming, Systems, Languages, and Applications
292
+ */
293
+ /// Solver Utilize Hybrid Representation of Graph
294
+ class POCRHybridSolver : public POCRSolver
295
+ {
296
+ //Hybrid
297
+ //{@
298
+ public:
299
+ struct TreeNode
300
+ {
301
+ NodeID id;
302
+ std::unordered_set<TreeNode*> children;
303
+
304
+ TreeNode(NodeID nId) : id(nId)
305
+ {}
306
+
307
+ ~TreeNode()
308
+ {
309
+ }
310
+
311
+ inline bool operator==(const TreeNode& rhs) const
312
+ {
313
+ return id == rhs.id;
314
+ }
315
+
316
+ inline bool operator<(const TreeNode& rhs) const
317
+ {
318
+ return id < rhs.id;
319
+ }
320
+ };
321
+
322
+ public:
323
+ Map<NodeID, std::unordered_map<NodeID, TreeNode*>> indMap; // indMap[v][u] points to node v in tree(u)
324
+
325
+ bool hasInd_h(NodeID src, NodeID dst);
326
+
327
+ /// Add a node dst to tree(src)
328
+ TreeNode* addInd_h(NodeID src, NodeID dst);
329
+
330
+ /// Get the node dst in tree(src)
331
+ TreeNode* getNode_h(NodeID src, NodeID dst)
332
+ {
333
+ return indMap[dst][src];
334
+ }
335
+
336
+ /// add v into desc(x) as a child of u
337
+ void insertEdge_h(TreeNode* u, TreeNode* v)
338
+ {
339
+ u->children.insert(v);
340
+ }
341
+
342
+ void addArc_h(NodeID src, NodeID dst);
343
+
344
+ void meld_h(NodeID x, TreeNode* uNode, TreeNode* vNode);
345
+ //@}
346
+ public:
347
+ POCRHybridSolver(CFLGraph* _graph, CFLGrammar* _grammar) : POCRSolver(_graph, _grammar)
348
+ {
349
+ }
350
+ /// Destructor
351
+ virtual ~POCRHybridSolver()
352
+ {
353
+ for (auto iter1: indMap)
354
+ {
355
+ for (auto iter2: iter1.second)
356
+ {
357
+ delete iter2.second;
358
+ iter2.second = NULL;
359
+ }
360
+ }
361
+ }
362
+
363
+ /// Process CFLEdge
364
+ virtual void processCFLEdge(const CFLEdge* Y_edge);
365
+
366
+ virtual void initialize();
367
+
368
+ public:
369
+ void addArc(NodeID src, NodeID dst);
370
+ void meld(NodeID x, TreeNode* uNode, TreeNode* vNode);
371
+ };
392
372
  }
393
373
 
394
374
  #endif /* INCLUDE_CFL_CFLSolver_H_*/
@@ -223,6 +223,9 @@ public:
223
223
  // SaberCondAllocator.cpp
224
224
  static const Option<bool> PrintPathCond;
225
225
 
226
+ // SaberSVFGBuilder.cpp
227
+ static const Option<bool> CollectExtRetGlobals;
228
+
226
229
  // SVFUtil.cpp
227
230
  static const Option<bool> DisableWarn;
228
231
 
@@ -256,6 +259,7 @@ public:
256
259
  static const Option<bool> PEGTransfer;
257
260
  static const Option<bool> CFLSVFG;
258
261
  static const Option<bool> POCRAlias;
262
+ static const Option<bool> POCRHybrid;
259
263
 
260
264
  // Loop Analysis
261
265
  static const Option<bool> LoopAnalysis;
@@ -201,6 +201,11 @@ void CFLAlias::initialize()
201
201
  normalizeCFLGrammar();
202
202
 
203
203
  // Initialize sovler
204
+ initializeSolver();
205
+ }
206
+
207
+ void CFLAlias::initializeSolver()
208
+ {
204
209
  solver = new CFLSolver(graph, grammar);
205
210
  }
206
211
 
@@ -238,19 +243,12 @@ void CFLAlias::solve()
238
243
  timeOfSolving += (end - start) / TIMEINTERVAL;
239
244
  }
240
245
 
241
- void POCRAlias::initialize()
246
+ void POCRAlias::initializeSolver()
242
247
  {
243
- stat = new CFLStat(this);
244
-
245
- // Build CFL Grammar
246
- buildCFLGrammar();
247
-
248
- // Build CFL Graph
249
- buildCFLGraph();
250
-
251
- // Normalize CFL Grammar
252
- normalizeCFLGrammar();
253
-
254
- // Initialize POCRSolver
255
248
  solver = new POCRSolver(graph, grammar);
256
249
  }
250
+
251
+ void POCRHybrid::initializeSolver()
252
+ {
253
+ solver = new POCRHybridSolver(graph, grammar);
254
+ }
@@ -191,15 +191,110 @@ void POCRSolver::processCFLEdge(const CFLEdge* Y_edge)
191
191
 
192
192
  void POCRSolver::initialize()
193
193
  {
194
- for(auto it = graph->begin(); it!= graph->end(); it++)
194
+ for(auto edge : graph->getCFLEdges())
195
195
  {
196
- for(const CFLEdge* edge : (*it).second->getOutEdges())
196
+ pushIntoWorklist(edge);
197
+ }
198
+
199
+ /// Foreach production X -> epsilon
200
+ /// add X(i,i) if not exist to E and to worklist
201
+ for(const Production& prod : grammar->getEpsilonProds())
202
+ {
203
+ for(auto IDMap : getSuccMap())
197
204
  {
198
- pushIntoWorklist(edge);
205
+ Symbol X = grammar->getLHSSymbol(prod);
206
+ if (addEdge(IDMap.first, IDMap.first, X))
207
+ {
208
+ CFLNode* i = graph->getGNode(IDMap.first);
209
+ const CFLEdge* newEdge = graph->addCFLEdge(i, i, X);
210
+ pushIntoWorklist(newEdge);
211
+ }
199
212
  }
200
213
  }
214
+ }
215
+
216
+ void POCRHybridSolver::processCFLEdge(const CFLEdge* Y_edge)
217
+ {
218
+ CFLNode* i = Y_edge->getSrcNode();
219
+ CFLNode* j = Y_edge->getDstNode();
220
+
221
+ /// For each production X -> Y
222
+ /// add X(i,j) if not exist to E and to worklist
223
+ Symbol Y = Y_edge->getEdgeKind();
224
+ if (grammar->hasProdsFromSingleRHS(Y))
225
+ for(const Production& prod : grammar->getProdsFromSingleRHS(Y))
226
+ {
227
+ Symbol X = grammar->getLHSSymbol(prod);
228
+ numOfChecks++;
229
+ if (addEdge(i->getId(), j->getId(), X))
230
+ {
231
+ const CFLEdge* newEdge = graph->addCFLEdge(Y_edge->getSrcNode(), Y_edge->getDstNode(), X);
232
+ pushIntoWorklist(newEdge);
233
+ }
234
+
235
+ }
236
+
237
+ /// For each production X -> Y Z
238
+ /// Foreach outgoing edge Z(j,k) from node j do
239
+ /// add X(i,k) if not exist to E and to worklist
240
+ if (grammar->hasProdsFromFirstRHS(Y))
241
+ for(const Production& prod : grammar->getProdsFromFirstRHS(Y))
242
+ {
243
+ if ((grammar->getLHSSymbol(prod) == grammar->str2Symbol("F")) && (Y == grammar->str2Symbol("F")) && (grammar->getSecondRHSSymbol(prod) == grammar->str2Symbol("F")))
244
+ {
245
+ addArc(i->getId(), j->getId());
246
+ }
247
+ else
248
+ {
249
+ Symbol X = grammar->getLHSSymbol(prod);
250
+ NodeBS diffDsts = addEdges(i->getId(), getSuccMap(j->getId())[grammar->getSecondRHSSymbol(prod)], X);
251
+ numOfChecks += getSuccMap(j->getId())[grammar->getSecondRHSSymbol(prod)].count();
252
+ for (NodeID diffDst: diffDsts)
253
+ {
254
+ const CFLEdge* newEdge = graph->addCFLEdge(i, graph->getGNode(diffDst), X);
255
+ pushIntoWorklist(newEdge);
256
+ }
257
+ }
258
+ }
259
+
260
+ /// For each production X -> Z Y
261
+ /// Foreach incoming edge Z(k,i) to node i do
262
+ /// add X(k,j) if not exist to E and to worklist
263
+ if(grammar->hasProdsFromSecondRHS(Y))
264
+ for(const Production& prod : grammar->getProdsFromSecondRHS(Y))
265
+ {
266
+ if ((grammar->getLHSSymbol(prod) == grammar->str2Symbol("F")) && (Y == grammar->str2Symbol("F")) && (grammar->getFirstRHSSymbol(prod) == grammar->str2Symbol("F")))
267
+ {
268
+ addArc(i->getId(), j->getId());
269
+ }
270
+ else
271
+ {
272
+ Symbol X = grammar->getLHSSymbol(prod);
273
+ NodeBS diffSrcs = addEdges(getPredMap(i->getId())[grammar->getFirstRHSSymbol(prod)], j->getId(), X);
274
+ numOfChecks += getPredMap(i->getId())[grammar->getFirstRHSSymbol(prod)].count();
275
+ for (NodeID diffSrc: diffSrcs)
276
+ {
277
+ const CFLEdge* newEdge = graph->addCFLEdge(graph->getGNode(diffSrc), j, X);
278
+ pushIntoWorklist(newEdge);
279
+ }
280
+ }
281
+ }
282
+ }
283
+
284
+ void POCRHybridSolver::initialize()
285
+ {
286
+ for(auto edge : graph->getCFLEdges())
287
+ {
288
+ pushIntoWorklist(edge);
289
+ }
290
+
291
+ // init hybrid dataset
292
+ for (auto it = graph->begin(); it != graph->end(); ++it)
293
+ {
294
+ NodeID nId = it->first;
295
+ addInd_h(nId, nId);
296
+ }
201
297
 
202
- /// Foreach production X -> epsilon
203
298
  /// add X(i,i) if not exist to E and to worklist
204
299
  for(const Production& prod : grammar->getEpsilonProds())
205
300
  {
@@ -214,4 +309,73 @@ void POCRSolver::initialize()
214
309
  }
215
310
  }
216
311
  }
312
+ }
313
+
314
+ void POCRHybridSolver::addArc(NodeID src, NodeID dst)
315
+ {
316
+ if(hasEdge(src, dst, grammar->str2Symbol("F")))
317
+ return;
318
+
319
+ for (auto& iter: indMap[src])
320
+ {
321
+ meld(iter.first, getNode_h(iter.first, src), getNode_h(dst, dst));
322
+ }
323
+ }
324
+
325
+
326
+ void POCRHybridSolver::meld(NodeID x, TreeNode* uNode, TreeNode* vNode)
327
+ {
328
+ numOfChecks++;
329
+
330
+ TreeNode* newVNode = addInd_h(x, vNode->id);
331
+ if (!newVNode)
332
+ return;
333
+
334
+ insertEdge_h(uNode, newVNode);
335
+ for (TreeNode* vChild: vNode->children)
336
+ {
337
+ meld_h(x, newVNode, vChild);
338
+ }
339
+ }
340
+
341
+ bool POCRHybridSolver::hasInd_h(NodeID src, NodeID dst)
342
+ {
343
+ auto it = indMap.find(dst);
344
+ if (it == indMap.end())
345
+ return false;
346
+ return (it->second.find(src) != it->second.end());
347
+ }
348
+
349
+ POCRHybridSolver::TreeNode* POCRHybridSolver::addInd_h(NodeID src, NodeID dst)
350
+ {
351
+ TreeNode* newNode = new TreeNode(dst);
352
+ auto resIns = indMap[dst].insert(std::make_pair(src, newNode));
353
+ if (resIns.second)
354
+ return resIns.first->second;
355
+ delete newNode;
356
+ return nullptr;
357
+ }
358
+
359
+ void POCRHybridSolver::addArc_h(NodeID src, NodeID dst)
360
+ {
361
+ if (!hasInd_h(src, dst))
362
+ {
363
+ for (auto iter: indMap[src])
364
+ {
365
+ meld_h(iter.first, getNode_h(iter.first, src), getNode_h(dst, dst));
366
+ }
367
+ }
368
+ }
369
+
370
+ void POCRHybridSolver::meld_h(NodeID x, TreeNode* uNode, TreeNode* vNode)
371
+ {
372
+ TreeNode* newVNode = addInd_h(x, vNode->id);
373
+ if (!newVNode)
374
+ return;
375
+
376
+ insertEdge_h(uNode, newVNode);
377
+ for (TreeNode* vChild: vNode->children)
378
+ {
379
+ meld_h(x, newVNode, vChild);
380
+ }
217
381
  }
@@ -31,6 +31,7 @@
31
31
  #include "SABER/SaberCheckerAPI.h"
32
32
  #include "MemoryModel/PointerAnalysisImpl.h"
33
33
  #include "Graphs/SVFG.h"
34
+ #include "Util/Options.h"
34
35
 
35
36
  using namespace SVF;
36
37
  using namespace SVFUtil;
@@ -99,17 +100,48 @@ void SaberSVFGBuilder::collectGlobals(BVDataPTAImpl* pta)
99
100
  }
100
101
  }
101
102
 
102
- PointsTo& SaberSVFGBuilder::CollectPtsChain(BVDataPTAImpl* pta,NodeID id, NodeToPTSSMap& cachedPtsMap)
103
+
104
+ /*
105
+ * https://github.com/SVF-tools/SVF/issues/991
106
+ *
107
+ * Originally, this function will collect all base pointers with all their fields
108
+ * inside the points-to set of global variables. But if a global variable points
109
+ * to the pointer returned by malloc() at some program points, then all pointers
110
+ * returned by malloc() will be included in the global set because of the
111
+ * context-insensitive pointer analysis results. This will make saber abandon
112
+ * too many slicing thus miss potential bugs.
113
+ *
114
+ * We add an option "saber-collect-extret-globals" to control whether this function
115
+ * will collect external functions' returned pointers. This option is true by default,
116
+ * making it to be false will let saber analyze more slicing but cause performance downgrade.
117
+ *
118
+ */
119
+ PointsTo& SaberSVFGBuilder::CollectPtsChain(BVDataPTAImpl* pta, NodeID id, NodeToPTSSMap& cachedPtsMap)
103
120
  {
104
121
  SVFIR* pag = svfg->getPAG();
105
122
 
106
123
  NodeID baseId = pag->getBaseObjVar(id);
107
124
  NodeToPTSSMap::iterator it = cachedPtsMap.find(baseId);
108
125
  if(it!=cachedPtsMap.end())
126
+ {
109
127
  return it->second;
128
+ }
110
129
  else
111
130
  {
112
131
  PointsTo& pts = cachedPtsMap[baseId];
132
+ // base object
133
+ if (!Options::CollectExtRetGlobals())
134
+ {
135
+ if(pta->isFIObjNode(baseId) && pag->getGNode(baseId)->hasValue())
136
+ {
137
+ const SVFCallInst* inst = SVFUtil::dyn_cast<SVFCallInst>(pag->getGNode(baseId)->getValue());
138
+ if(inst && SVFUtil::isExtCall(inst))
139
+ {
140
+ return pts;
141
+ }
142
+ }
143
+ }
144
+
113
145
  pts |= pag->getFieldsAfterCollapse(baseId);
114
146
 
115
147
  WorkList worklist;
@@ -127,7 +159,6 @@ PointsTo& SaberSVFGBuilder::CollectPtsChain(BVDataPTAImpl* pta,NodeID id, NodeTo
127
159
  }
128
160
  return pts;
129
161
  }
130
-
131
162
  }
132
163
 
133
164
  /*!
@@ -679,6 +679,14 @@ const Option<bool> Options::PrintPathCond(
679
679
  );
680
680
 
681
681
 
682
+ // SaberSVFGBuilder.cpp
683
+ const Option<bool> Options::CollectExtRetGlobals(
684
+ "saber-collect-extret-globals",
685
+ "Don't include pointers returned by external function during collecting globals",
686
+ true
687
+ );
688
+
689
+
682
690
  // SVFUtil.cpp
683
691
  const Option<bool> Options::DisableWarn(
684
692
  "dwarn",
@@ -829,6 +837,12 @@ const Option<bool> Options::POCRAlias(
829
837
  false
830
838
  );
831
839
 
840
+ const Option<bool> Options::POCRHybrid(
841
+ "pocr-hybrid",
842
+ "When explicit to true, POCRHybridSolver transfer CFL graph to internal hybird graph representation.",
843
+ false
844
+ );
845
+
832
846
  const Option<bool> Options::LoopAnalysis(
833
847
  "loop-analysis",
834
848
  "Analyze every func and get loop info and loop bounds.",
@@ -841,4 +855,4 @@ const Option<u32_t> Options::LoopBound(
841
855
  1
842
856
  );
843
857
 
844
- } // namespace SVF.
858
+ } // namespace SVF.
@@ -59,6 +59,8 @@ int main(int argc, char ** argv)
59
59
  std::unique_ptr<CFLBase> cfl;
60
60
  if (Options::CFLSVFG())
61
61
  cfl = std::make_unique<CFLVF>(svfir);
62
+ else if (Options::POCRHybrid())
63
+ cfl = std::make_unique<POCRHybrid>(svfir);
62
64
  else if (Options::POCRAlias())
63
65
  cfl = std::make_unique<POCRAlias>(svfir);
64
66
  else