Static Value-Flow Analysis
Loading...
Searching...
No Matches
AbstractInterpretation.cpp
Go to the documentation of this file.
1//===- AbstractExecution.cpp -- Abstract Execution---------------------------------//
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// Created on: Jan 10, 2024
26// Author: Xiao Cheng, Jiawei Wang
27//
28
31#include "AE/Svfexe/AbsExtAPI.h"
32#include "SVFIR/SVFIR.h"
33#include "Util/Options.h"
34#include "Util/WorkList.h"
35#include "Graphs/CallGraph.h"
36#include "WPA/Andersen.h"
37#include <cmath>
38#include <memory>
39
40using namespace SVF;
41using namespace SVFUtil;
42
43
45{
46 stat->startClk();
47 utils = new AbsExtAPI(this);
50
51 analyse();
53 stat->endClk();
55 if (Options::PStat())
57 for (auto& detector: detectors)
58 detector->reportBug();
59}
60
62{
63 stat = new AEStat(this);
64 // Run Andersen's pointer analysis and build WTO
66 icfg = svfir->getICFG();
71}
72
77{
78 // Leak the singleton on purpose. AbstractInterpretation owns a
79 // Map<std::string, std::function<void(const CallICFGNode*)>> func_map
80 // whose lambda closures back-reference state owned by other globals
81 // (preAnalysis's WTO, the call graph, ...). Letting the static
82 // unique_ptr's atexit-time destructor run hits a static-destruction-
83 // order issue: the func_map hashtable's destructor calls into
84 // std::function destroyers whose closures touch already-destroyed
85 // state, and ~_Hashtable() segfaults during normal program shutdown.
86 //
87 // Reliably reproducible from any downstream tool that drives a full
88 // AE analysis to completion and then exits normally:
89 // - SSA's ass3 binary (Software-Security-Analysis/Assignment-3)
90 // - pysvf via Python interpreter shutdown
91 //
92 // A process-lifetime singleton has no observable lifecycle past
93 // program exit, so leaking is benign and avoids the use-after-destroy.
95 {
96 switch (Options::AESparsity())
97 {
103 default:
104 return new AbstractInterpretation();
105 }
106 }();
107 return *instance;
108}
109
110
113{
114 delete utils;
115 delete stat;
116 delete preAnalysis;
117}
118
123{
127 auto* callGraphSCC = preAnalysis->getCallGraphSCC();
128
129 for (auto it = callGraph->begin(); it != callGraph->end(); ++it)
130 {
131 const CallGraphNode* cgNode = it->second;
132 const FunObjVar* fun = cgNode->getFunction();
133
134 // Skip declarations
135 if (fun->isDeclaration())
136 continue;
137
138 if (mainEntry)
139 {
141 {
142 entryFunctions.push(fun);
143 break;
144 }
145 }
146 else
147 {
148 NodeID repNodeId = callGraphSCC->repNode(cgNode->getId());
149 if (visitedEntrySCCs.count(repNodeId))
150 continue;
151
152 const NodeBS& cgSCCNodes = callGraphSCC->subNodes(repNodeId);
153 bool hasExternalCaller = false;
154 for (NodeID nodeId : cgSCCNodes)
155 {
157 for (auto inEdge : sccNode->getInEdges())
158 {
159 if (!cgSCCNodes.test(inEdge->getSrcID()))
160 {
161 hasExternalCaller = true;
162 break;
163 }
164 }
166 break;
167 }
168
170 continue;
171
173 const FunObjVar* entryFun = fun;
174 for (NodeID nodeId : cgSCCNodes)
175 {
176 const FunObjVar* sccFun = callGraph->getGNode(nodeId)->getFunction();
178 {
180 break;
181 }
182 }
184 }
185 }
186
187 if (mainEntry && entryFunctions.empty())
188 {
190 "AE -ae-fun-entry=main requires a program entry function, but main/svf.main was not found.\n");
191 assert(false && "No program entry function found for -ae-fun-entry=main");
192 abort();
193 }
194
195 return entryFunctions;
196}
197
198
204
209{
210 // Collect all entry point functions
212
213 if (entryFunctions.empty())
214 {
215 assert(false && "No entry functions found for analysis");
216 return;
217 }
218 // handle Global ICFGNode of SVFModule
221 while (!entryFunctions.empty())
222 {
223 const FunObjVar* entryFun = entryFunctions.pop();
226 handleFunction(funEntry, nullptr);
227 }
228}
229
236{
237 const ICFGNode* node = icfg->getGlobalICFGNode();
238 // Global init is one of the few legitimate direct-mutation sites:
239 // updateAbsState filters out ValVars in semi-sparse mode, but NullPtr/
240 // BlkPtr have no SVFVar so we cannot route them through updateAbsValue.
241 // Use the manager's operator[] (auto-creates the entry if absent).
242 AbstractState& init = abstractTrace[node];
243 init = AbstractState();
244 // NullPtr has no backing SVFVar. Model it directly as the singleton null
245 // address; BlkPtr is initialized directly below for the same reason.
247
248 // Global Node, we just need to handle addr, load, store, copy and gep
249 for (const SVFStmt *stmt: node->getSVFStmts())
250 {
251 handleSVFStatement(stmt);
252 }
253
254 // BlkPtr is the canonical unknown value. Keep its address-domain meaning
255 // for pointer uses, and also give it numeric top so external-input stores
256 // can flow through ordinary store/load state as [-inf, +inf].
258 blkPtrValue.getAddrs().insert(BlackHoleObjAddr);
260}
261
269{
270 // Collect all feasible predecessor states, then merge at the end.
272 bool hasFeasiblePred = false;
273
274 for (auto& edge : node->getInEdges())
275 {
276 const ICFGNode* pred = edge->getSrcNode();
277 if (!hasAbsState(pred))
278 continue;
279
281 bool feasible = false;
282 if (const IntraCFGEdge* intraCfgEdge = SVFUtil::dyn_cast<IntraCFGEdge>(edge))
283 {
284 if (intraCfgEdge->getCondition())
285 {
287 if (feasible)
289 }
290 else
291 {
292 feasible = true;
293 }
294 }
295 else if (SVFUtil::isa<CallCFGEdge>(edge))
296 {
297 feasible = true;
298 }
299 else if (SVFUtil::isa<RetCFGEdge>(edge))
300 {
301 switch (Options::HandleRecur())
302 {
303 case TOP:
304 feasible = true;
305 break;
306 case WIDEN_ONLY:
307 case WIDEN_NARROW:
308 {
309 const RetICFGNode* returnSite = SVFUtil::dyn_cast<RetICFGNode>(node);
310 const CallICFGNode* callSite = returnSite->getCallICFGNode();
312 break;
313 }
314 }
315 }
316
317 if (feasible)
318 {
320 {
321 // getAEInstance() selects this class for Sparse mode.
322 static_cast<FullSparseAbstractInterpretation*>(this)->mergeFreedAddrs(merged, predState);
323 }
324 else
326 hasFeasiblePred = true;
327 }
328 }
329
330 if (!hasFeasiblePred)
331 return false;
332
333 updateAbsState(node, merged);
334
335 return true;
336}
337
348static const LoadStmt* findBackingLoad(const SVFVar* var)
349{
350 if (var->getInEdges().empty())
351 return nullptr;
352 SVFStmt* inStmt = *var->getInEdges().begin();
353 if (const LoadStmt* ls = SVFUtil::dyn_cast<LoadStmt>(inStmt))
354 return ls;
355 if (const CopyStmt* cs = SVFUtil::dyn_cast<CopyStmt>(inStmt))
356 {
357 const SVFVar* src = cs->getRHSVar();
358 if (!src->getInEdges().empty())
359 return SVFUtil::dyn_cast<LoadStmt>(*src->getInEdges().begin());
360 }
361 return nullptr;
362}
363
378 bool isLHS, const IntervalValue& self,
379 const IntervalValue& other)
380{
381 // Normalize: always reason from the LHS perspective.
382 // If we are the RHS operand, swap the predicate direction.
383 if (!isLHS)
384 {
385 // a > b from b's perspective: b < a
386 static const Map<s32_t, s32_t> swapPred =
387 {
410 };
411 auto it = swapPred.find(predicate);
412 if (it == swapPred.end()) return IntervalValue::top();
413 predicate = it->second;
414 }
415
416 // If false branch, negate the predicate.
417 if (succ == 0)
418 {
419 static const Map<s32_t, s32_t> negPred =
420 {
443 };
444 auto it = negPred.find(predicate);
445 if (it == negPred.end()) return IntervalValue::top();
446 predicate = it->second;
447 }
448
449 // Now compute the constraint on LHS given: LHS <predicate> other
451 switch (predicate)
452 {
453 case CmpStmt::ICMP_EQ:
456 result.meet_with(other);
457 break;
458 case CmpStmt::ICMP_NE:
463 return IntervalValue::top(); // no useful narrowing
468 result.meet_with(IntervalValue(other.lb() + 1, IntervalValue::plus_infinity()));
469 break;
475 break;
480 result.meet_with(IntervalValue(IntervalValue::minus_infinity(), other.ub() - 1));
481 break;
487 break;
488 default:
489 return IntervalValue::top();
490 }
491 return result;
492}
493
496{
497 const ICFGNode* pred = edge->getSrcNode();
498 s64_t succ = edge->getSuccessorCondValue();
499 const CmpStmt* cmpStmt = SVFUtil::cast<CmpStmt>(
500 *edge->getCondition()->getInEdges().begin());
501 const AbstractValue& cmpValue = getAbsValue(cmpStmt->getRes(), pred);
502 assert(cmpValue.isInterval() &&
503 "CmpStmt result must be represented by a Boolean interval");
504
505 // Feasibility check: cmp result must be compatible with branch successor
506 IntervalValue resVal = cmpValue.getInterval();
508 return !resVal.isBottom();
509}
510
512{
513 // LLVM successor 0 is the default destination, not ICFGNode ID 0.
514 // switch(x) { case 1: work(); break; } after(); -> default goes to after().
515 // Explicit cases may enter the same block; this checks the destination only.
516 enum : u32_t { DefaultSuccessor = 0 };
517 const SVFStmt* terminator = edge->getSrcNode()->getSVFStmts().back();
518 const auto* branch = SVFUtil::cast<BranchStmt>(terminator);
519 return branch->getSuccessor(DefaultSuccessor) == edge->getDstNode();
520}
521
523 const IntraCFGEdge* edge, const IntervalValue& input) const
524{
525 if (input.isBottom())
526 return false;
527 else if (edge->getCondition()->getType()->getByteSize() > sizeof(s64_t))
528 return true;
529
530 const auto* branch = SVFUtil::cast<BranchStmt>(
531 edge->getSrcNode()->getSVFStmts().back());
533 for (u32_t i = 1; i < branch->getNumSuccessors(); ++i)
534 {
535 const s64_t caseValue = branch->getSuccessorCondValue(i);
536 if (input.lb().leq(caseValue) && input.ub().geq(caseValue))
537 {
538 // case 1: (input: [0,2])
539 // {block for case 1 }
540 // so input can satisfy this case
541 if (branch->getSuccessor(i) == edge->getDstNode())
542 return true;
543 ++matchedCases;
544 }
545 }
546
547 // after last for loop, we test all non-default edge. If we reach here
548 // 1)non-default edge, infeasible 2)default edge, it depends.
550 return false;
551 else if (input.is_infinite())
552 // default edge here
553 // if input reach infinity, conservatively think it can go default edge
554 return true;
555 else
556 {
557 // default edge here
558 // if we still have possible value to miss all non-default cases, it can
559 // go default now.
560 const u64_t span = static_cast<u64_t>(input.ub().getIntNumeral()) -
561 static_cast<u64_t>(input.lb().getIntNumeral());
562 return span >= matchedCases;
563 }
564}
565
568{
569 bool feasible = true;
570 std::vector<std::pair<const LoadStmt*, IntervalValue>> constraints;
571 // Step 1: collect Load ObjVars related to CmpStmt
572 // e.g. cmp = (*p>0), we need to get var p, constant number 0, and predicate > (greater than)
573 const SVFVar* cond = edge->getCondition();
574 const ICFGNode* pred = edge->getSrcNode();
575 s64_t succ = edge->getSuccessorCondValue();
576
577 assert(!cond->getInEdges().empty() &&
578 "branch condition has no defining edge?");
579 const SVFStmt* condDef = *cond->getInEdges().begin();
580
581 if (const CmpStmt* cmpStmt = SVFUtil::dyn_cast<CmpStmt>(condDef))
582 {
583 s32_t predicate = cmpStmt->getPredicate();
584
585 if (cmpStmt->getOpVarID(0) == IRGraph::NullPtr ||
586 cmpStmt->getOpVarID(1) == IRGraph::NullPtr)
587 {
588 // p == NULL / p != NULL: no interval obj to refine.
589 }
590 else
591 {
592 AbstractValue opVal[2] = {getAbsValue(cmpStmt->getOpVar(0), pred),
593 getAbsValue(cmpStmt->getOpVar(1), pred)
594 };
595
596 const bool hasIntervalCmp =
597 opVal[0].isInterval() && opVal[1].isInterval();
598 if (!hasIntervalCmp && (opVal[0].isAddr() || opVal[1].isAddr()))
599 {
600 // Pointer-valued cmp: branch feasibility only.
601 }
602 else
603 {
604 for (int i = 0; i < 2; i++)
605 {
606 const int other = 1 - i;
607 const LoadStmt* load =
608 findBackingLoad(cmpStmt->getOpVar(i));
609
610 if (opVal[i].getInterval().is_numeral())
611 {
612 // Example: in x < 5, operand 5 is not refined.
613 }
614 else if (!opVal[other].getInterval().is_numeral())
615 {
616 // Example: x < y, neither side has a fixed bound.
617 }
618 else if (!load)
619 {
620 // Example: cmp uses a computed temporary, not load p.
621 }
622 else
623 {
625 predicate, succ, i == 0, opVal[i].getInterval(),
626 opVal[other].getInterval());
627
628 if (narrowed.isTop())
629 {
630 // != and unsupported predicates reach here.
631 }
632 else
633 {
634 constraints.emplace_back(load, narrowed);
635 }
636 }
637 }
638 }
639 }
640 }
641 else
642 {
643 if (!isSwitchBranchEdgeFeasible(edge, getAbsValue(cond, pred).getInterval()))
644 return false;
645 else if (isSwitchDefaultEdge(edge))
646 return true;
647 else
648 {
649 const auto* branch = SVFUtil::cast<BranchStmt>(pred->getSVFStmts().back());
650 u32_t caseCount = 0;
651 s64_t caseValue = 0;
652 for (u32_t i = 1; i < branch->getNumSuccessors(); ++i)
653 {
654 if (branch->getSuccessor(i) == edge->getDstNode())
655 {
656 ++caseCount;
657 caseValue = branch->getSuccessorCondValue(i);
658 }
659 }
660
661 // case 10: A(); -> entering A requires x == 10.
662 // case 10: case 20: A(); -> do not select just one value.
663 // Reuse the Obj refinement below; do not modify the defining state.
664 if (caseCount == 1)
665 {
666 if (const LoadStmt* load = findBackingLoad(cond))
667 constraints.emplace_back(load, IntervalValue(caseValue));
668 }
669 }
670 }
671
672 // Step 2: refine Obj below.
673 // Example: x > 5 supplies [6,+inf]; narrowing [0,10] yields [6,10].
674 // Only this temporary input changes, never the backing load's trace.
675 for (const auto& [load, narrowed] : constraints)
676 {
677 const ICFGNode* loadICFG = load->getICFGNode();
678 const AbstractValue& pointer = getAbsValue(load->getRHSVar(), loadICFG);
679 if (!pointer.isAddr() || pointer.getAddrs().size() != 1)
680 {
681 // A condition on *p cannot refine every possible target of p.
682 }
683 else
684 {
685 const u32_t addr = *pointer.getAddrs().begin();
686 const NodeID objId = as.getIDFromAddr(addr);
688 {
689 // No backing memory cell to refine.
690 }
691 else if (!as.inAddrToValTable(objId))
692 {
693 // Refine only an interval Obj already carried by this state.
694 }
695 else
696 {
697 IntervalValue& value = as.load(addr).getInterval();
698 value.meet_with(narrowed);
699 feasible &= !value.isBottom();
700 }
701 }
702 }
703 return feasible;
704}
705
708{
709 const SVFVar* cmpVar = edge->getCondition();
710 assert(!cmpVar->getInEdges().empty() && "branch condition has no defining edge?");
711 if (SVFUtil::isa<CmpStmt>(*cmpVar->getInEdges().begin()))
714 getAbsValue(cmpVar, edge->getSrcNode()).getInterval());
715}
716
724{
725 // Check reachability: pre-state must have been propagated by predecessors
726 bool isFunEntry = SVFUtil::isa<FunEntryICFGNode>(node);
727 if (!hasAbsState(node))
728 {
729 if (isFunEntry)
730 {
731 // Entry point with no callers: inherit from global node
735 else
737 }
738 else
739 {
740 return false; // unreachable node
741 }
742 }
743
744 // Store the previous state for fixpoint detection
746
747 stat->getBlockTrace()++;
749
750 // Handle SVF statements
751 for (const SVFStmt *stmt: node->getSVFStmts())
752 {
753 handleSVFStatement(stmt);
754 }
755
756 // Handle call sites
757 if (const CallICFGNode* callNode = SVFUtil::dyn_cast<CallICFGNode>(node))
758 {
760 }
761
762 // Run detectors
763 for (auto& detector: detectors)
764 detector->detect(node);
766
767 // Track this node as analyzed (for coverage statistics across all entry points)
768 allAnalyzedNodes.insert(node);
769
770 if (getAbsState(node) == prevState)
771 return false;
772
773 return true;
774}
775
783{
784 auto it = preAnalysis->getFuncToWTO().find(funEntry->getFun());
785 assert(it != preAnalysis->getFuncToWTO().end() && "Missing WTO for function");
786
787 // Push all top-level WTO components into the worklist in WTO order
788 FIFOWorkList<const ICFGWTOComp*> worklist(it->second->getWTOComponents());
789
790 while (!worklist.empty())
791 {
792 const ICFGWTOComp* comp = worklist.pop();
793
794 if (const ICFGSingletonWTO* singleton = SVFUtil::dyn_cast<ICFGSingletonWTO>(comp))
795 {
796 const ICFGNode* node = singleton->getICFGNode();
798 handleICFGNode(node);
799 }
800 else if (const ICFGCycleWTO* cycle = SVFUtil::dyn_cast<ICFGCycleWTO>(comp))
801 {
802 if (mergeStatesFromPredecessors(cycle->head()->getICFGNode()))
804 }
805 }
806}
807
808
810{
811 if (const CallICFGNode* callNode = SVFUtil::dyn_cast<CallICFGNode>(node))
812 {
813 if (isExtCall(callNode))
814 {
816 }
817 else
818 {
819 // Handle both direct and indirect calls uniformly
821 }
822 }
823 else
824 assert (false && "it is not call node");
825}
826
828{
829 return SVFUtil::isExtCall(callNode->getCalledFunction());
830}
831
833{
835 for (auto& detector : detectors)
836 {
837 detector->handleStubFunctions(callNode);
838 }
839}
840
843{
844 // Direct call: get callee directly from call node
845 if (const FunObjVar* callee = callNode->getCalledFunction())
846 return callee;
847
848 // Indirect call: resolve callee through pointer analysis
850 auto it = callsiteMaps.find(callNode);
851 if (it == callsiteMaps.end())
852 return nullptr;
853
854 NodeID call_id = it->second;
855 if (!hasAbsState(callNode))
856 return nullptr;
857
859 if (!Addrs.isAddr() || Addrs.getAddrs().empty())
860 return nullptr;
861
862 NodeID addr = *Addrs.getAddrs().begin();
863 const SVFVar* func_var = getSVFVar(getAbsState(callNode).getIDFromAddr(addr));
864 return SVFUtil::dyn_cast<FunObjVar>(func_var);
865}
866
877{
879 return;
880
881 // Direct call: callee is known
882 if (const FunObjVar* callee = callNode->getCalledFunction())
883 {
886 const RetICFGNode* retNode = callNode->getRetICFGNode();
888 return;
889 }
890
891 // Indirect call: use Andersen's call graph to get all resolved callees.
892 const RetICFGNode* retNode = callNode->getRetICFGNode();
894 {
896 for (const FunObjVar* callee : callees)
897 {
898 if (callee->isDeclaration())
899 continue;
902 }
903 }
904 // Resume return node from caller's state (context-insensitive)
906}
907
908// Loop / recursion handling (handleLoopOrRecursion + cycle helpers +
909// recursion utilities) lives in AELoopRecursion.cpp.
910
912{
913 if (const AddrStmt *addr = SVFUtil::dyn_cast<AddrStmt>(stmt))
914 {
916 }
917 else if (const BinaryOPStmt *binary = SVFUtil::dyn_cast<BinaryOPStmt>(stmt))
918 {
920 }
921 else if (const CmpStmt *cmp = SVFUtil::dyn_cast<CmpStmt>(stmt))
922 {
924 }
925 else if (SVFUtil::isa<UnaryOPStmt>(stmt))
926 {
927 }
928 else if (SVFUtil::isa<BranchStmt>(stmt))
929 {
930 // branch stmt is handled in hasBranchES
931 }
932 else if (const LoadStmt *load = SVFUtil::dyn_cast<LoadStmt>(stmt))
933 {
934 updateStateOnLoad(load);
935 }
936 else if (const StoreStmt *store = SVFUtil::dyn_cast<StoreStmt>(stmt))
937 {
938 updateStateOnStore(store);
939 }
940 else if (const CopyStmt *copy = SVFUtil::dyn_cast<CopyStmt>(stmt))
941 {
943 }
944 else if (const GepStmt *gep = SVFUtil::dyn_cast<GepStmt>(stmt))
945 {
947 }
948 else if (const SelectStmt *select = SVFUtil::dyn_cast<SelectStmt>(stmt))
949 {
951 }
952 else if (const PhiStmt *phi = SVFUtil::dyn_cast<PhiStmt>(stmt))
953 {
955 }
956 else if (const CallPE *callPE = SVFUtil::dyn_cast<CallPE>(stmt))
957 {
958 // To handle Call Edge
959 updateStateOnCall(callPE);
960 }
961 else if (const RetPE *retPE = SVFUtil::dyn_cast<RetPE>(stmt))
962 {
963 updateStateOnRet(retPE);
964 }
965 else
966 assert(false && "implement this part");
967 // NullPtr should not be changed by any statement. If the entry is missing
968 // (not yet auto-inserted) we treat that as "unchanged" — only check the
969 // entry if it actually exists.
970 {
971 const auto& vmap = getAbsState(stmt->getICFGNode()).getVarToVal();
972 auto it = vmap.find(IRGraph::NullPtr);
973 (void)it; // Suppress warning of unused variable under release build
974 assert(it == vmap.end() ||
975 (it->second.isAddr() &&
976 it->second.getAddrs().equals(AddressValue(NullMemAddr))));
977 }
978}
979
981{
982 const ICFGNode* node = gep->getICFGNode();
984 AddressValue gepAddrs = getGepObjAddrs(SVFUtil::cast<ValVar>(gep->getRHSVar()), offsetPair);
985 updateAbsValue(gep->getLHSVar(), gepAddrs, node);
986}
987
989{
990 const ICFGNode* node = select->getICFGNode();
991 const AbstractValue& condVal = getAbsValue(select->getCondition(), node);
992 const AbstractValue& tVal = getAbsValue(select->getTrueValue(), node);
993 const AbstractValue& fVal = getAbsValue(select->getFalseValue(), node);
995 if (condVal.getInterval().is_numeral())
996 {
998 }
999 else
1000 {
1001 resVal = tVal;
1002 resVal.join_with(fVal);
1003 }
1004 updateAbsValue(select->getRes(), resVal, node);
1005}
1006
1008{
1009 const ICFGNode* icfgNode = phi->getICFGNode();
1011 for (u32_t i = 0; i < phi->getOpVarNum(); i++)
1012 {
1013 const ICFGNode* opICFGNode = phi->getOpICFGNode(i);
1015 {
1017 const AbstractValue& opVal = getAbsValue(phi->getOpVar(i), opICFGNode);
1019 if (edge)
1020 {
1021 const IntraCFGEdge* intraEdge = SVFUtil::cast<IntraCFGEdge>(edge);
1022 if (intraEdge->getCondition())
1023 {
1025 rhs.join_with(opVal);
1026 }
1027 else
1028 rhs.join_with(opVal);
1029 }
1030 else
1031 {
1032 rhs.join_with(opVal);
1033 }
1034 }
1035 }
1036 updateAbsValue(phi->getRes(), rhs, icfgNode);
1037}
1038
1039
1043{
1044 const ICFGNode* node = callPE->getICFGNode();
1045 const SVFVar* res = callPE->getRes();
1047 for (u32_t i = 0; i < callPE->getOpVarNum(); i++)
1048 {
1049 const ICFGNode* opICFGNode = callPE->getOpCallICFGNode(i);
1051 {
1052 const AbstractValue& opVal = getAbsValue(callPE->getOpVar(i), opICFGNode);
1053 rhs.join_with(opVal);
1054 }
1055 }
1056 updateAbsValue(res, rhs, node);
1057}
1058
1060{
1061 const ICFGNode* node = retPE->getICFGNode();
1062 const AbstractValue& rhsVal = getAbsValue(retPE->getRHSVar(), node);
1063 updateAbsValue(retPE->getLHSVar(), rhsVal, node);
1064}
1065
1066
1068{
1069 const ICFGNode* node = addr->getICFGNode();
1070 // initObjVar mutates _varToAbsVal/_addrToAbsVal directly, so we need
1071 // mutable access; route via the manager.
1072 AbstractState& as = getAbsState(node);
1073 as.initObjVar(SVFUtil::cast<ObjVar>(addr->getRHSVar()));
1074 // AddrStmt: lhs(ValVar) = &rhs(ObjVar).
1075 // as[rhsId] stores the ObjVar's virtual address in _varToVal,
1076 // NOT the object contents. So we must use as[] directly for ObjVar.
1077 u32_t rhsId = addr->getRHSVarID();
1078 if (addr->getRHSVar()->getType()->getKind() == SVFType::SVFIntegerTy)
1079 as[rhsId].getInterval().meet_with(utils->getRangeLimitFromType(addr->getRHSVar()->getType()));
1080 // LHS is a ValVar (pointer), write through the API
1081 updateAbsValue(addr->getLHSVar(), as[rhsId], node);
1082}
1083
1084
1086{
1087 const ICFGNode* node = binary->getICFGNode();
1088 // Treat bottom (uninitialized) operands as top for soundness
1089 const AbstractValue& op0Val = getAbsValue(binary->getOpVar(0), node);
1090 const AbstractValue& op1Val = getAbsValue(binary->getOpVar(1), node);
1091 IntervalValue lhs = op0Val.getInterval().isBottom() ? IntervalValue::top() : op0Val.getInterval();
1092 IntervalValue rhs = op1Val.getInterval().isBottom() ? IntervalValue::top() : op1Val.getInterval();
1094 switch (binary->getOpcode())
1095 {
1096 case BinaryOPStmt::Add:
1097 case BinaryOPStmt::FAdd:
1098 resVal = (lhs + rhs);
1099 break;
1100 case BinaryOPStmt::Sub:
1101 case BinaryOPStmt::FSub:
1102 resVal = (lhs - rhs);
1103 break;
1104 case BinaryOPStmt::Mul:
1105 case BinaryOPStmt::FMul:
1106 resVal = (lhs * rhs);
1107 break;
1108 case BinaryOPStmt::SDiv:
1109 case BinaryOPStmt::FDiv:
1110 case BinaryOPStmt::UDiv:
1111 resVal = (lhs / rhs);
1112 break;
1113 case BinaryOPStmt::SRem:
1114 case BinaryOPStmt::FRem:
1115 case BinaryOPStmt::URem:
1116 resVal = (lhs % rhs);
1117 break;
1118 case BinaryOPStmt::Xor:
1119 resVal = (lhs ^ rhs);
1120 break;
1121 case BinaryOPStmt::And:
1122 resVal = (lhs & rhs);
1123 break;
1124 case BinaryOPStmt::Or:
1125 resVal = (lhs | rhs);
1126 break;
1127 case BinaryOPStmt::AShr:
1128 resVal = (lhs >> rhs);
1129 break;
1130 case BinaryOPStmt::Shl:
1131 resVal = (lhs << rhs);
1132 break;
1133 case BinaryOPStmt::LShr:
1134 resVal = (lhs >> rhs);
1135 break;
1136 default:
1137 assert(false && "undefined binary: ");
1138 }
1139 updateAbsValue(binary->getRes(), resVal, node);
1140}
1141
1146 u32_t predicate, const AddressValue& lhs, const AddressValue& rhs) const
1147{
1149 predicate <= CmpStmt::LAST_ICMP_PREDICATE &&
1150 "pointer comparison must use an ICMP predicate");
1151
1152 const bool lhsTargetKnown =
1153 !lhs.isBottom() && !lhs.contains(BlackHoleObjAddr);
1154 const bool rhsTargetKnown =
1155 !rhs.isBottom() && !rhs.contains(BlackHoleObjAddr);
1157 const bool targetsMayBeEqual = lhs.hasIntersect(rhs);
1158 const bool targetsMustBeEqual =
1159 targetsMayBeEqual && lhs.size() == 1 && rhs.size() == 1;
1160
1162 if (hasUnknownTarget)
1163 {
1164 // Case 1: an unknown target may equal or differ from the other target.
1166 }
1167 else if (!targetsMayBeEqual)
1168 {
1169 // Case 2: known disjoint target sets are definitely unequal.
1171 }
1172 else if (targetsMustBeEqual)
1173 {
1174 // Case 3: intersecting single-target sets contain the same target.
1176 }
1177 else
1178 {
1179 // Case 4: intersecting sets with multiple choices may be equal.
1181 }
1182
1184 if (predicate == CmpStmt::ICMP_EQ)
1185 result = equality;
1186 else if (predicate == CmpStmt::ICMP_NE)
1188 return result;
1189}
1190
1192 u32_t predicate, const IntervalValue& lhs, const IntervalValue& rhs) const
1193{
1195 switch (predicate)
1196 {
1197 case CmpStmt::ICMP_EQ:
1198 case CmpStmt::FCMP_OEQ:
1199 case CmpStmt::FCMP_UEQ:
1200 result = (lhs == rhs);
1201 break;
1202 case CmpStmt::ICMP_NE:
1203 case CmpStmt::FCMP_ONE:
1204 case CmpStmt::FCMP_UNE:
1205 result = (lhs != rhs);
1206 break;
1207 case CmpStmt::ICMP_UGT:
1208 case CmpStmt::ICMP_SGT:
1209 case CmpStmt::FCMP_OGT:
1210 case CmpStmt::FCMP_UGT:
1211 result = (lhs > rhs);
1212 break;
1213 case CmpStmt::ICMP_UGE:
1214 case CmpStmt::ICMP_SGE:
1215 case CmpStmt::FCMP_OGE:
1216 case CmpStmt::FCMP_UGE:
1217 result = (lhs >= rhs);
1218 break;
1219 case CmpStmt::ICMP_ULT:
1220 case CmpStmt::ICMP_SLT:
1221 case CmpStmt::FCMP_OLT:
1222 case CmpStmt::FCMP_ULT:
1223 result = (lhs < rhs);
1224 break;
1225 case CmpStmt::ICMP_ULE:
1226 case CmpStmt::ICMP_SLE:
1227 case CmpStmt::FCMP_OLE:
1228 case CmpStmt::FCMP_ULE:
1229 result = (lhs <= rhs);
1230 break;
1232 result = IntervalValue(0, 0);
1233 break;
1234 case CmpStmt::FCMP_TRUE:
1235 result = IntervalValue(1, 1);
1236 break;
1237 case CmpStmt::FCMP_ORD:
1238 case CmpStmt::FCMP_UNO:
1239 // Keep both outcomes because the interval domain does not track NaN.
1240 result = IntervalValue(0, 1);
1241 break;
1242 default:
1243 assert(false && "undefined compare: ");
1244 }
1245 return result;
1246}
1247
1249{
1250 const ICFGNode* node = cmp->getICFGNode();
1251 const AbstractValue& lhsValue = getAbsValue(cmp->getOpVar(0), node);
1252 const AbstractValue& rhsValue = getAbsValue(cmp->getOpVar(1), node);
1253 const bool pointerCmp = cmp->getOpVar(0)->getType()->isPointerTy();
1254 assert(pointerCmp == cmp->getOpVar(1)->getType()->isPointerTy() &&
1255 "CmpStmt operands must belong to the same value domain");
1256
1258 if (pointerCmp)
1259 {
1260 result = evaluatePointerCmp(cmp->getPredicate(), lhsValue.getAddrs(),
1261 rhsValue.getAddrs());
1262 }
1263 else
1264 {
1265 const IntervalValue lhs = lhsValue.isInterval()
1266 ? lhsValue.getInterval()
1268 const IntervalValue rhs = rhsValue.isInterval()
1269 ? rhsValue.getInterval()
1271 result = evaluateIntervalCmp(cmp->getPredicate(), lhs, rhs);
1272 }
1273 updateAbsValue(cmp->getRes(), result, node);
1274}
1275
1277{
1278 const ICFGNode* node = load->getICFGNode();
1280 loadValue(SVFUtil::cast<ValVar>(load->getRHSVar()), node);
1281 updateAbsValue(load->getLHSVar(), loaded, node);
1282}
1283
1285{
1286 const ICFGNode* node = store->getICFGNode();
1287 AbstractValue val = getAbsValue(store->getRHSVar(), node);
1288 storeValue(SVFUtil::cast<ValVar>(store->getLHSVar()), val, node);
1289}
1290
1292{
1293 const ICFGNode* node = copy->getICFGNode();
1294 const SVFVar* lhsVar = copy->getLHSVar();
1295 const SVFVar* rhsVar = copy->getRHSVar();
1296
1297 auto getZExtValue = [&](const SVFVar* var)
1298 {
1299 const SVFType* type = var->getType();
1300 if (SVFUtil::isa<SVFIntegerType>(type))
1301 {
1302 u32_t bits = type->getByteSize() * 8;
1303 const AbstractValue& val = getAbsValue(var, node);
1304 if (val.getInterval().is_numeral())
1305 {
1306 if (bits == 8)
1307 {
1308 int8_t signed_i8_value = val.getInterval().getIntNumeral();
1311 }
1312 else if (bits == 16)
1313 {
1314 s16_t signed_i16_value = val.getInterval().getIntNumeral();
1317 }
1318 else if (bits == 32)
1319 {
1320 s32_t signed_i32_value = val.getInterval().getIntNumeral();
1323 }
1324 else if (bits == 64)
1325 {
1326 s64_t signed_i64_value = val.getInterval().getIntNumeral();
1328 }
1329 else
1330 assert(false && "cannot support int type other than u8/16/32/64");
1331 }
1332 else
1333 {
1334 return IntervalValue::top();
1335 }
1336 }
1337 return IntervalValue::top();
1338 };
1339
1340 auto getTruncValue = [&](const SVFVar* var, const SVFType* dstType)
1341 {
1342 const IntervalValue& itv = getAbsValue(var, node).getInterval();
1343 if(itv.isBottom()) return itv;
1345 s64_t int_ub = itv.ub().getIntNumeral();
1346 u32_t dst_bits = dstType->getByteSize() * 8;
1347 if (dst_bits == 8)
1348 {
1349 int8_t s8_lb = static_cast<int8_t>(int_lb);
1350 int8_t s8_ub = static_cast<int8_t>(int_ub);
1351 if (s8_lb > s8_ub)
1353 return IntervalValue(s8_lb, s8_ub);
1354 }
1355 else if (dst_bits == 16)
1356 {
1357 s16_t s16_lb = static_cast<s16_t>(int_lb);
1358 s16_t s16_ub = static_cast<s16_t>(int_ub);
1359 if (s16_lb > s16_ub)
1361 return IntervalValue(s16_lb, s16_ub);
1362 }
1363 else if (dst_bits == 32)
1364 {
1365 s32_t s32_lb = static_cast<s32_t>(int_lb);
1366 s32_t s32_ub = static_cast<s32_t>(int_ub);
1367 if (s32_lb > s32_ub)
1369 return IntervalValue(s32_lb, s32_ub);
1370 }
1371 else
1372 {
1373 assert(false && "cannot support dst int type other than u8/16/32");
1374 abort();
1375 }
1376 };
1377
1378 const AbstractValue& rhsVal = getAbsValue(rhsVar, node);
1379
1380 if (copy->getCopyKind() == CopyStmt::COPYVAL)
1381 {
1383 }
1384 else if (copy->getCopyKind() == CopyStmt::ZEXT)
1385 {
1386 updateAbsValue(lhsVar, getZExtValue(rhsVar), node);
1387 }
1388 else if (copy->getCopyKind() == CopyStmt::SEXT)
1389 {
1390 updateAbsValue(lhsVar, rhsVal.getInterval(), node);
1391 }
1392 else if (copy->getCopyKind() == CopyStmt::FPTOSI)
1393 {
1394 updateAbsValue(lhsVar, rhsVal.getInterval(), node);
1395 }
1396 else if (copy->getCopyKind() == CopyStmt::FPTOUI)
1397 {
1398 updateAbsValue(lhsVar, rhsVal.getInterval(), node);
1399 }
1400 else if (copy->getCopyKind() == CopyStmt::SITOFP)
1401 {
1402 updateAbsValue(lhsVar, rhsVal.getInterval(), node);
1403 }
1404 else if (copy->getCopyKind() == CopyStmt::UITOFP)
1405 {
1406 updateAbsValue(lhsVar, rhsVal.getInterval(), node);
1407 }
1408 else if (copy->getCopyKind() == CopyStmt::TRUNC)
1409 {
1410 updateAbsValue(lhsVar, getTruncValue(rhsVar, lhsVar->getType()), node);
1411 }
1412 else if (copy->getCopyKind() == CopyStmt::FPTRUNC)
1413 {
1414 updateAbsValue(lhsVar, rhsVal.getInterval(), node);
1415 }
1416 else if (copy->getCopyKind() == CopyStmt::INTTOPTR)
1417 {
1418 //insert nullptr
1419 }
1420 else if (copy->getCopyKind() == CopyStmt::PTRTOINT)
1421 {
1423 }
1424 else if (copy->getCopyKind() == CopyStmt::BITCAST)
1425 {
1426 if (rhsVal.isAddr())
1428 }
1429 else
1430 assert(false && "undefined copy kind");
1431}
static const LoadStmt * findBackingLoad(const SVFVar *var)
static IntervalValue computeCmpConstraint(s32_t predicate, s64_t succ, bool isLHS, const IntervalValue &self, const IntervalValue &other)
#define NullMemAddr
#define BlackHoleObjAddr
newitem type
Definition cJSON.cpp:2739
copy
Definition cJSON.cpp:414
void finializeStat()
Definition AEStat.cpp:44
u32_t & getBlockTrace()
Definition AEStat.h:70
void performStat() override
Definition AEStat.cpp:120
u32_t & getICFGNodeTrace()
Definition AEStat.h:78
void countStateSize()
Definition AEStat.cpp:31
const Map< const FunObjVar *, const ICFGWTO * > & getFuncToWTO() const
Accessors for WTO data.
Definition AEWTO.h:72
CallGraph * getCallGraph() const
Definition AEWTO.h:60
CallGraphSCC * getCallGraphSCC() const
Definition AEWTO.h:64
void initWTO()
Build WTO for each function using call graph SCC.
Definition AEWTO.cpp:51
Handles external API calls and manages abstract states.
Definition AbsExtAPI.h:49
void collectCheckPoint()
void handleExtAPI(const CallICFGNode *call)
Handles an external API call.
void checkPointAllSet()
IntervalValue getRangeLimitFromType(const SVFType *type)
Gets the range limit from a type.
void handleFunction(const ICFGNode *funEntry, const CallICFGNode *caller)
Handle a function body via worklist-driven WTO traversal starting from funEntry.
void updateStateOnCall(const CallPE *callPE)
const FunObjVar * getCallee(const CallICFGNode *callNode)
Get callee function: directly for direct calls, via pointer analysis for indirect calls.
AbstractState & getAbsState(const ICFGNode *node)
void updateStateOnStore(const StoreStmt *store)
virtual void handleFunCall(const CallICFGNode *callNode)
void analyzeFromAllProgEntries()
Analyze all entry points (functions without callers)
void updateStateOnGep(const GepStmt *gep)
bool isCmpBranchEdgeFeasible(const IntraCFGEdge *edge, AbstractState &as)
Returns true if the cmp-conditional branch is feasible.
virtual bool isExtCall(const CallICFGNode *callNode)
void updateStateOnPhi(const PhiStmt *phi)
bool handleICFGNode(const ICFGNode *node)
Handle an ICFG node: execute statements; return true if state changed.
std::vector< std::unique_ptr< AEDetector > > detectors
virtual AbstractValue loadValue(const ValVar *pointer, const ICFGNode *node)
Read memory through the pointer's address targets.
virtual void handleExtCall(const CallICFGNode *callNode)
bool isBranchEdgeFeasible(const IntraCFGEdge *edge, AbstractState &as)
AddressValue getGepObjAddrs(const ValVar *pointer, IntervalValue offset)
IntervalValue getGepElementIndex(const GepStmt *gep)
virtual void joinStates(AbstractState &dst, const AbstractState &src)
bool applyBranchRefinement(const IntraCFGEdge *edge, AbstractState &as)
virtual bool mergeStatesFromPredecessors(const ICFGNode *node)
void updateStateOnSelect(const SelectStmt *select)
virtual void handleSVFStatement(const SVFStmt *stmt)
Dispatch an SVF statement (Addr/Binary/Cmp/Load/Store/Copy/Gep/Select/Phi/Call/Ret) to its handler.
bool skipRecursiveCall(const CallICFGNode *callNode)
Skip recursive callsites (within SCC); entry calls from outside SCC are not skipped.
IntervalValue evaluateIntervalCmp(u32_t predicate, const IntervalValue &lhs, const IntervalValue &rhs) const
SVFIR * svfir
Data and helpers reachable from SparseAbstractInterpretation.
virtual void handleLoopOrRecursion(const ICFGCycleWTO *cycle, const CallICFGNode *caller)
Handle a WTO cycle (loop or recursive function) using widening/narrowing iteration.
void updateStateOnAddr(const AddrStmt *addr)
virtual ~AbstractInterpretation()
Destructor.
virtual const AbstractValue & getAbsValue(const ValVar *var, const ICFGNode *node)
bool isSwitchBranchEdgeFeasible(const IntraCFGEdge *edge, const IntervalValue &input) const
Check whether any input value can take this switch edge; do not refine it.
virtual void handleCallSite(const ICFGNode *node)
Handle a call site node: dispatch to ext-call, direct-call, or indirect-call handling.
void updateStateOnRet(const RetPE *retPE)
IntervalValue evaluatePointerCmp(u32_t predicate, const AddressValue &lhs, const AddressValue &rhs) const
bool hasAbsState(const ICFGNode *node)
void updateStateOnCopy(const CopyStmt *copy)
FIFOWorkList< const FunObjVar * > collectProgEntryFuns()
Get all entry point functions (functions without callers)
bool isSwitchDefaultEdge(const IntraCFGEdge *edge) const
void updateStateOnLoad(const LoadStmt *load)
void updateStateOnBinary(const BinaryOPStmt *binary)
Map< const ICFGNode *, AbstractState > abstractTrace
per-node trace; owned here
static AbstractInterpretation & getAEInstance()
virtual void updateAbsValue(const ValVar *var, const AbstractValue &val, const ICFGNode *node)
Set< const ICFGNode * > allAnalyzedNodes
virtual void storeValue(const ValVar *pointer, const AbstractValue &val, const ICFGNode *node)
const SVFVar * getSVFVar(NodeID varId) const
Retrieve SVFVar given its ID; asserts if no such variable exists.
void updateStateOnCmp(const CmpStmt *cmp)
virtual void updateAbsState(const ICFGNode *node, const AbstractState &state)
const VarToAbsValMap & getVarToVal() const
get var2val map
static bool isNullOrBlackHoleAddr(u32_t addr)
Whether addr has no concrete backing memory object.
bool isInterval() const
IntervalValue & getInterval()
AddressValue & getAddrs()
bool isAddr() const
u32_t size() const
AddrSet::const_iterator begin() const
s64_t getIntNumeral() const
const FunObjVar * getFunction() const
Get function of this call node.
Definition CallGraph.h:191
bool hasIndCSCallees(const CallICFGNode *cs) const
Definition CallGraph.h:335
const FunctionSet & getIndCSCallees(const CallICFGNode *cs) const
Definition CallGraph.h:339
const CallICFGNode * getOpCallICFGNode(u32_t op_idx) const
Return the CallICFGNode of the i-th operand.
@ ICMP_SGT
signed greater than
@ FCMP_UEQ
1 0 0 1 True if unordered or equal
@ FCMP_ONE
0 1 1 0 True if ordered and operands are unequal
@ ICMP_UGE
unsigned greater or equal
@ FCMP_UGT
1 0 1 0 True if unordered or greater than
@ ICMP_ULE
unsigned less or equal
@ FCMP_OGE
0 0 1 1 True if ordered and greater than or equal
@ FCMP_OLT
0 1 0 0 True if ordered and less than
@ FCMP_OGT
0 0 1 0 True if ordered and greater than
@ ICMP_NE
not equal
@ FCMP_TRUE
1 1 1 1 Always true (always folded)
@ ICMP_ULT
unsigned less than
@ FCMP_ULE
1 1 0 1 True if unordered, less than, or equal
@ ICMP_SLT
signed less than
@ ICMP_UGT
unsigned greater than
@ FCMP_OEQ
0 0 0 1 True if ordered and equal
@ FCMP_ORD
0 1 1 1 True if ordered (no nans)
@ FCMP_OLE
0 1 0 1 True if ordered and less than or equal
@ FCMP_FALSE
0 0 0 0 Always false (always folded)
@ FCMP_ULT
1 1 0 0 True if unordered or less than
@ FCMP_UNO
1 0 0 0 True if unordered: isnan(X) | isnan(Y)
@ FCMP_UGE
1 0 1 1 True if unordered, greater than, or equal
@ ICMP_SGE
signed greater or equal
@ FCMP_UNE
1 1 1 0 True if unordered or not equal
@ ICMP_SLE
signed less or equal
bool empty() const
Definition WorkList.h:161
bool isDeclaration() const
NodeType * getSrcNode() const
iterator begin()
Iterators.
NodeType * getGNode(NodeID id) const
Get a node.
const GEdgeSetTy & getInEdges() const
const SVFStmtList & getSVFStmts() const
Definition ICFGNode.h:116
ICFGEdge * getICFGEdge(const ICFGNode *src, const ICFGNode *dst, ICFGEdge::ICFGEdgeK kind)
Get a SVFG edge according to src and dst.
Definition ICFG.cpp:312
void updateCallGraph(CallGraph *callgraph)
update ICFG for indirect calls
Definition ICFG.cpp:428
FunEntryICFGNode * getFunEntryICFGNode(const FunObjVar *fun)
Add a function entry node.
Definition ICFG.cpp:243
GlobalICFGNode * getGlobalICFGNode() const
Definition ICFG.h:244
NodeID getBlkPtr() const
Definition IRGraph.h:259
void meet_with(const IntervalValue &other)
Return a intersected IntervalValue.
static BoundedInt minus_infinity()
Get minus infinity -inf.
const BoundedInt & ub() const
Return the upper bound.
bool isBottom() const
bool is_zero() const
Return true if the IntervalValue is [0, 0].
static BoundedInt plus_infinity()
Get plus infinity +inf.
static IntervalValue top()
Create the IntervalValue [-inf, +inf].
const BoundedInt & lb() const
Return the lower bound.
const ValVar * getLHSVar() const
const ValVar * getRHSVar() const
const ValVar * getRes() const
Result SVFVar.
const ValVar * getOpVar(u32_t pos) const
Operand SVFVars.
u32_t getOpVarNum() const
static const OptionMap< u32_t > HandleRecur
recursion handling mode, Default: TOP
Definition Options.h:241
static const OptionMap< u32_t > AESparsity
Definition Options.h:237
static const OptionMap< u32_t > AEFunEntry
Definition Options.h:238
static const Option< bool > PStat
Definition Options.h:116
const ValVar * getRHSVar() const
const ValVar * getLHSVar() const
ICFG * getICFG() const
Definition SVFIR.h:232
const CallSiteToFunPtrMap & getIndirectCallsites() const
Add/get indirect callsites.
Definition SVFIR.h:454
const SVFVar * getSVFVar(NodeID id) const
ObjVar/GepObjVar/BaseObjVar.
Definition SVFIR.h:136
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 endClk()
Definition SVFStat.h:66
virtual void startClk()
Definition SVFStat.h:61
ICFGNode * getICFGNode() const
u32_t getByteSize() const
Definition SVFType.h:287
NodeID getId() const
Get ID.
Definition SVFValue.h:158
const ValVar * getRHSVar() const
const ValVar * getLHSVar() const
bool isProgEntryFunction(const FunObjVar *)
Program entry function e.g. main.
Definition SVFUtil.cpp:531
std::string errMsg(const std::string &msg)
Print error message by converting a string into red string output.
Definition SVFUtil.cpp:98
std::ostream & errs()
Overwrite llvm::errs()
Definition SVFUtil.h:64
bool isExtCall(const FunObjVar *fun)
Definition SVFUtil.cpp:526
for isBitcode
Definition BasicTypes.h:70
unsigned long long u64_t
Definition GeneralType.h:69
u32_t NodeID
Definition GeneralType.h:76
signed short s16_t
Definition GeneralType.h:74
unsigned short u16_t
Definition GeneralType.h:73
WTONode< ICFG > ICFGSingletonWTO
Definition ICFGWTO.h:48
llvm::IRBuilder IRBuilder
Definition BasicTypes.h:76
signed s32_t
Definition GeneralType.h:68
unsigned u32_t
Definition GeneralType.h:67
signed long long s64_t
Definition GeneralType.h:70
WTOComponent< ICFG > ICFGWTOComp
Definition ICFGWTO.h:47