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 // TODO: we cannot find right SVFVar for NullPtr, so we use init[NullPtr]
245 // directly. Same for BlkPtr below.
247
248 // Global Node, we just need to handle addr, load, store, copy and gep
249 for (const SVFStmt *stmt: node->getSVFStmts())
250 {
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
280 if (const IntraCFGEdge* intraCfgEdge = SVFUtil::dyn_cast<IntraCFGEdge>(edge))
281 {
282 if (intraCfgEdge->getCondition())
283 {
286 {
289 hasFeasiblePred = true;
290 }
291 }
292 else
293 {
295 hasFeasiblePred = true;
296 }
297 }
298 else if (SVFUtil::isa<CallCFGEdge>(edge))
299 {
301 hasFeasiblePred = true;
302 }
303 else if (SVFUtil::isa<RetCFGEdge>(edge))
304 {
305 switch (Options::HandleRecur())
306 {
307 case TOP:
309 hasFeasiblePred = true;
310 break;
311 case WIDEN_ONLY:
312 case WIDEN_NARROW:
313 {
314 const RetICFGNode* returnSite = SVFUtil::dyn_cast<RetICFGNode>(node);
315 const CallICFGNode* callSite = returnSite->getCallICFGNode();
317 {
319 hasFeasiblePred = true;
320 }
321 break;
322 }
323 }
324 }
325 }
326
327 if (!hasFeasiblePred)
328 return false;
329
330 updateAbsState(node, merged);
331
332 return true;
333}
334
345static const LoadStmt* findBackingLoad(const SVFVar* var)
346{
347 if (var->getInEdges().empty())
348 return nullptr;
349 SVFStmt* inStmt = *var->getInEdges().begin();
350 if (const LoadStmt* ls = SVFUtil::dyn_cast<LoadStmt>(inStmt))
351 return ls;
352 if (const CopyStmt* cs = SVFUtil::dyn_cast<CopyStmt>(inStmt))
353 {
354 const SVFVar* src = cs->getRHSVar();
355 if (!src->getInEdges().empty())
356 return SVFUtil::dyn_cast<LoadStmt>(*src->getInEdges().begin());
357 }
358 return nullptr;
359}
360
375 bool isLHS, const IntervalValue& self,
376 const IntervalValue& other)
377{
378 // Normalize: always reason from the LHS perspective.
379 // If we are the RHS operand, swap the predicate direction.
380 if (!isLHS)
381 {
382 // a > b from b's perspective: b < a
383 static const Map<s32_t, s32_t> swapPred =
384 {
407 };
408 auto it = swapPred.find(predicate);
409 if (it == swapPred.end()) return IntervalValue::top();
410 predicate = it->second;
411 }
412
413 // If false branch, negate the predicate.
414 if (succ == 0)
415 {
416 static const Map<s32_t, s32_t> negPred =
417 {
440 };
441 auto it = negPred.find(predicate);
442 if (it == negPred.end()) return IntervalValue::top();
443 predicate = it->second;
444 }
445
446 // Now compute the constraint on LHS given: LHS <predicate> other
448 switch (predicate)
449 {
450 case CmpStmt::ICMP_EQ:
454 break;
455 case CmpStmt::ICMP_NE:
460 return IntervalValue::top(); // no useful narrowing
466 break;
472 break;
478 break;
484 break;
485 default:
486 return IntervalValue::top();
487 }
488 return result;
489}
490
493{
494 const ICFGNode* pred = edge->getSrcNode();
495 s64_t succ = edge->getSuccessorCondValue();
496 const CmpStmt* cmpStmt = SVFUtil::cast<CmpStmt>(
497 *edge->getCondition()->getInEdges().begin());
498
499 if (cmpStmt->getOpVarID(0) == IRGraph::NullPtr ||
500 cmpStmt->getOpVarID(1) == IRGraph::NullPtr)
501 return true;
502
504 {
505 getAbsValue(cmpStmt->getOpVar(0), pred),
506 getAbsValue(cmpStmt->getOpVar(1), pred)
507 };
508
509 const bool hasIntervalCmp = opVal[0].isInterval() && opVal[1].isInterval();
510 if (!hasIntervalCmp && (opVal[0].isAddr() || opVal[1].isAddr()))
511 return true;
512
513 // Feasibility check: cmp result must be compatible with branch successor
516 if (resVal.isBottom())
517 return false;
518
519 return true;
520}
521
524{
525 const ICFGNode* pred = edge->getSrcNode();
526 s64_t succ = edge->getSuccessorCondValue();
527 const SVFVar* var = edge->getCondition();
528
530 IntervalValue switch_cond = condVal.getInterval();
532 if (switch_cond.isBottom())
533 return false;
534 return true;
535}
536
539{
540 const SVFVar* cond = edge->getCondition();
541 const ICFGNode* pred = edge->getSrcNode();
542 const ICFGNode* succNode = edge->getDstNode();
543 s64_t succ = edge->getSuccessorCondValue();
544
545 assert(!cond->getInEdges().empty() &&
546 "branch condition has no defining edge?");
547 const SVFStmt* condDef = *cond->getInEdges().begin();
548
549 if (const CmpStmt* cmpStmt = SVFUtil::dyn_cast<CmpStmt>(condDef))
550 {
551 s32_t predicate = cmpStmt->getPredicate();
552
553 if (cmpStmt->getOpVarID(0) == IRGraph::NullPtr ||
554 cmpStmt->getOpVarID(1) == IRGraph::NullPtr)
555 {
556 // p == NULL / p != NULL: no interval obj to refine.
557 }
558 else
559 {
560 AbstractValue opVal[2] = {getAbsValue(cmpStmt->getOpVar(0), pred),
561 getAbsValue(cmpStmt->getOpVar(1), pred)
562 };
563
564 const bool hasIntervalCmp =
565 opVal[0].isInterval() && opVal[1].isInterval();
566 if (!hasIntervalCmp && (opVal[0].isAddr() || opVal[1].isAddr()))
567 {
568 // Pointer-valued cmp: branch feasibility only.
569 }
570 else
571 {
572 for (int i = 0; i < 2; i++)
573 {
574 const int other = 1 - i;
575 const LoadStmt* load =
576 findBackingLoad(cmpStmt->getOpVar(i));
577
578 if (opVal[i].getInterval().is_numeral())
579 {
580 // Example: in x < 5, operand 5 is not refined.
581 }
582 else if (!opVal[other].getInterval().is_numeral())
583 {
584 // Example: x < y, neither side has a fixed bound.
585 }
586 else if (!load)
587 {
588 // Example: cmp uses a computed temporary, not load p.
589 }
590 else
591 {
593 predicate, succ, i == 0, opVal[i].getInterval(),
594 opVal[other].getInterval());
595
596 if (narrowed.isTop())
597 {
598 // != and unsupported predicates reach here.
599 }
600 else
601 {
602 const ICFGNode* loadIcfg = load->getICFGNode();
603 const AbstractValue& ptrVal =
605 if (!ptrVal.isAddr())
606 {
607 // Cannot map load p back to concrete ObjVars.
608 }
609 else
610 {
611 for (const auto& addr : ptrVal.getAddrs())
612 {
613 NodeID objId = as.getIDFromAddr(addr);
616 }
617 }
618 }
619 }
620 }
621 }
622 }
623 }
624 else
625 {
626 const SVFVar* var = cond;
627
629 IntervalValue switch_cond = condVal.getInterval();
631 if (switch_cond.isBottom())
632 {
633 // This case label is not reachable from cond's interval.
634 }
635 else
636 {
637 as[var->getId()] = AbstractValue(switch_cond);
638
640 for (SVFStmt* stmt : var->getInEdges())
641 stmtList.push(stmt);
642 while (!stmtList.empty())
643 {
644 const SVFStmt* stmt = stmtList.pop();
645 const LoadStmt* load = SVFUtil::dyn_cast<LoadStmt>(stmt);
646 if (!load)
647 {
648 // Skip non-load definitions of the switch condition.
649 }
650 else
651 {
652 const ICFGNode* loadIcfg = load->getICFGNode();
653 const AbstractValue& ptrVal =
655 if (!ptrVal.isAddr())
656 {
657 // Cannot map load p back to concrete ObjVars.
658 }
659 else
660 {
661 for (const auto& addr : ptrVal.getAddrs())
662 {
663 NodeID objId = as.getIDFromAddr(addr);
666 }
667 }
668 }
669 }
670 }
671 }
672}
673
676 const ICFGNode* loadIcfg, const ICFGNode* /*succ*/)
677{
678 // Default (dense / semi-sparse): MEET narrowed onto obj's current
679 // value, store back into the local `as`. Caller's joinStates
680 // propagates `as` into `merged`, then `updateAbsState(succ, merged)`
681 // commits it to trace[succ].
682 //
683 // We can't go through the polymorphic updateAbsValue here: `as` is
684 // a transient per-edge predState copy that lives outside
685 // abstractTrace, so it has no node id. Writing via `updateAbsValue`
686 // with `succ` as the node would land in trace[succ] but get
687 // clobbered by the subsequent `updateAbsState(succ, merged)`; with
688 // `loadIcfg` it would corrupt the obj's authoritative value at its
689 // load site. AbstractState::store on the transient `as` is the
690 // only sound primitive — and recordBranchRefinement itself is the
691 // virtual customisation point (FullSparse routes to
692 // refinementTrace instead of touching `as`).
693 const ObjVar* objVar = SVFUtil::dyn_cast<ObjVar>(svfir->getGNode(objId));
695 {
697 if (cur.isInterval())
698 {
702 as.store(addr, AbstractValue(itv));
703 }
704 }
705}
706
709{
710 const SVFVar* cmpVar = edge->getCondition();
711 assert(!cmpVar->getInEdges().empty() && "branch condition has no defining edge?");
712 if (SVFUtil::isa<CmpStmt>(*cmpVar->getInEdges().begin()))
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 {
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 assert(it == vmap.end() ||
974 (!it->second.isInterval() && !it->second.isAddr()));
975 }
976}
977
979{
980 const ICFGNode* node = gep->getICFGNode();
982 AddressValue gepAddrs = getGepObjAddrs(SVFUtil::cast<ValVar>(gep->getRHSVar()), offsetPair);
983 updateAbsValue(gep->getLHSVar(), gepAddrs, node);
984}
985
987{
988 const ICFGNode* node = select->getICFGNode();
989 const AbstractValue& condVal = getAbsValue(select->getCondition(), node);
990 const AbstractValue& tVal = getAbsValue(select->getTrueValue(), node);
991 const AbstractValue& fVal = getAbsValue(select->getFalseValue(), node);
993 if (condVal.getInterval().is_numeral())
994 {
996 }
997 else
998 {
999 resVal = tVal;
1000 resVal.join_with(fVal);
1001 }
1002 updateAbsValue(select->getRes(), resVal, node);
1003}
1004
1006{
1007 const ICFGNode* icfgNode = phi->getICFGNode();
1009 for (u32_t i = 0; i < phi->getOpVarNum(); i++)
1010 {
1011 const ICFGNode* opICFGNode = phi->getOpICFGNode(i);
1013 {
1015 const AbstractValue& opVal = getAbsValue(phi->getOpVar(i), opICFGNode);
1017 if (edge)
1018 {
1019 const IntraCFGEdge* intraEdge = SVFUtil::cast<IntraCFGEdge>(edge);
1020 if (intraEdge->getCondition())
1021 {
1023 rhs.join_with(opVal);
1024 }
1025 else
1026 rhs.join_with(opVal);
1027 }
1028 else
1029 {
1030 rhs.join_with(opVal);
1031 }
1032 }
1033 }
1034 updateAbsValue(phi->getRes(), rhs, icfgNode);
1035}
1036
1037
1041{
1042 const ICFGNode* node = callPE->getICFGNode();
1043 const SVFVar* res = callPE->getRes();
1045 for (u32_t i = 0; i < callPE->getOpVarNum(); i++)
1046 {
1047 const ICFGNode* opICFGNode = callPE->getOpCallICFGNode(i);
1049 {
1050 const AbstractValue& opVal = getAbsValue(callPE->getOpVar(i), opICFGNode);
1051 rhs.join_with(opVal);
1052 }
1053 }
1054 updateAbsValue(res, rhs, node);
1055}
1056
1058{
1059 const ICFGNode* node = retPE->getICFGNode();
1060 const AbstractValue& rhsVal = getAbsValue(retPE->getRHSVar(), node);
1061 updateAbsValue(retPE->getLHSVar(), rhsVal, node);
1062}
1063
1064
1066{
1067 const ICFGNode* node = addr->getICFGNode();
1068 // initObjVar mutates _varToAbsVal/_addrToAbsVal directly, so we need
1069 // mutable access; route via the manager.
1070 AbstractState& as = getAbsState(node);
1071 as.initObjVar(SVFUtil::cast<ObjVar>(addr->getRHSVar()));
1072 // AddrStmt: lhs(ValVar) = &rhs(ObjVar).
1073 // as[rhsId] stores the ObjVar's virtual address in _varToVal,
1074 // NOT the object contents. So we must use as[] directly for ObjVar.
1075 u32_t rhsId = addr->getRHSVarID();
1076 if (addr->getRHSVar()->getType()->getKind() == SVFType::SVFIntegerTy)
1077 as[rhsId].getInterval().meet_with(utils->getRangeLimitFromType(addr->getRHSVar()->getType()));
1078 // LHS is a ValVar (pointer), write through the API
1079 updateAbsValue(addr->getLHSVar(), as[rhsId], node);
1080}
1081
1082
1084{
1085 const ICFGNode* node = binary->getICFGNode();
1086 // Treat bottom (uninitialized) operands as top for soundness
1087 const AbstractValue& op0Val = getAbsValue(binary->getOpVar(0), node);
1088 const AbstractValue& op1Val = getAbsValue(binary->getOpVar(1), node);
1089 IntervalValue lhs = op0Val.getInterval().isBottom() ? IntervalValue::top() : op0Val.getInterval();
1090 IntervalValue rhs = op1Val.getInterval().isBottom() ? IntervalValue::top() : op1Val.getInterval();
1092 switch (binary->getOpcode())
1093 {
1094 case BinaryOPStmt::Add:
1095 case BinaryOPStmt::FAdd:
1096 resVal = (lhs + rhs);
1097 break;
1098 case BinaryOPStmt::Sub:
1099 case BinaryOPStmt::FSub:
1100 resVal = (lhs - rhs);
1101 break;
1102 case BinaryOPStmt::Mul:
1103 case BinaryOPStmt::FMul:
1104 resVal = (lhs * rhs);
1105 break;
1106 case BinaryOPStmt::SDiv:
1107 case BinaryOPStmt::FDiv:
1108 case BinaryOPStmt::UDiv:
1109 resVal = (lhs / rhs);
1110 break;
1111 case BinaryOPStmt::SRem:
1112 case BinaryOPStmt::FRem:
1113 case BinaryOPStmt::URem:
1114 resVal = (lhs % rhs);
1115 break;
1116 case BinaryOPStmt::Xor:
1117 resVal = (lhs ^ rhs);
1118 break;
1119 case BinaryOPStmt::And:
1120 resVal = (lhs & rhs);
1121 break;
1122 case BinaryOPStmt::Or:
1123 resVal = (lhs | rhs);
1124 break;
1125 case BinaryOPStmt::AShr:
1126 resVal = (lhs >> rhs);
1127 break;
1128 case BinaryOPStmt::Shl:
1129 resVal = (lhs << rhs);
1130 break;
1131 case BinaryOPStmt::LShr:
1132 resVal = (lhs >> rhs);
1133 break;
1134 default:
1135 assert(false && "undefined binary: ");
1136 }
1137 updateAbsValue(binary->getRes(), resVal, node);
1138}
1139
1141{
1142 const ICFGNode* node = cmp->getICFGNode();
1143 u32_t op0 = cmp->getOpVarID(0);
1144 u32_t op1 = cmp->getOpVarID(1);
1145 const AbstractValue& op0Val = getAbsValue(cmp->getOpVar(0), node);
1146 const AbstractValue& op1Val = getAbsValue(cmp->getOpVar(1), node);
1147
1148 // if it is address
1149 if (op0Val.isAddr() && op1Val.isAddr())
1150 {
1152 const AddressValue& addrOp0 = op0Val.getAddrs();
1153 const AddressValue& addrOp1 = op1Val.getAddrs();
1154 if (addrOp0.equals(addrOp1))
1155 {
1156 resVal = IntervalValue(1, 1);
1157 }
1158 else if (addrOp0.hasIntersect(addrOp1))
1159 {
1160 resVal = IntervalValue(0, 1);
1161 }
1162 else
1163 {
1164 resVal = IntervalValue(0, 0);
1165 }
1166 updateAbsValue(cmp->getRes(), resVal, node);
1167 }
1168 // if op0 or op1 is nullptr, compare abstractValue instead of touching addr or interval
1169 else if (op0 == IRGraph::NullPtr || op1 == IRGraph::NullPtr)
1170 {
1171 IntervalValue resVal = (op0Val.equals(op1Val)) ? IntervalValue(1, 1) : IntervalValue(0, 0);
1172 updateAbsValue(cmp->getRes(), resVal, node);
1173 }
1174 else
1175 {
1176 {
1178 if (op0Val.isInterval() && op1Val.isInterval())
1179 {
1180 // Treat bottom (uninitialized) operands as top for soundness
1181 IntervalValue lhs = op0Val.getInterval().isBottom() ? IntervalValue::top() : op0Val.getInterval(),
1182 rhs = op1Val.getInterval().isBottom() ? IntervalValue::top() : op1Val.getInterval();
1183 // AbstractValue
1184 auto predicate = cmp->getPredicate();
1185 switch (predicate)
1186 {
1187 case CmpStmt::ICMP_EQ:
1188 case CmpStmt::FCMP_OEQ:
1189 case CmpStmt::FCMP_UEQ:
1190 resVal = (lhs == rhs);
1191 // resVal = (lhs.getInterval() == rhs.getInterval());
1192 break;
1193 case CmpStmt::ICMP_NE:
1194 case CmpStmt::FCMP_ONE:
1195 case CmpStmt::FCMP_UNE:
1196 resVal = (lhs != rhs);
1197 break;
1198 case CmpStmt::ICMP_UGT:
1199 case CmpStmt::ICMP_SGT:
1200 case CmpStmt::FCMP_OGT:
1201 case CmpStmt::FCMP_UGT:
1202 resVal = (lhs > rhs);
1203 break;
1204 case CmpStmt::ICMP_UGE:
1205 case CmpStmt::ICMP_SGE:
1206 case CmpStmt::FCMP_OGE:
1207 case CmpStmt::FCMP_UGE:
1208 resVal = (lhs >= rhs);
1209 break;
1210 case CmpStmt::ICMP_ULT:
1211 case CmpStmt::ICMP_SLT:
1212 case CmpStmt::FCMP_OLT:
1213 case CmpStmt::FCMP_ULT:
1214 resVal = (lhs < rhs);
1215 break;
1216 case CmpStmt::ICMP_ULE:
1217 case CmpStmt::ICMP_SLE:
1218 case CmpStmt::FCMP_OLE:
1219 case CmpStmt::FCMP_ULE:
1220 resVal = (lhs <= rhs);
1221 break;
1223 resVal = IntervalValue(0, 0);
1224 break;
1225 case CmpStmt::FCMP_TRUE:
1226 resVal = IntervalValue(1, 1);
1227 break;
1228 case CmpStmt::FCMP_ORD:
1229 case CmpStmt::FCMP_UNO:
1230 // FCMP_ORD: true if both operands are not NaN
1231 // FCMP_UNO: true if either operand is NaN
1232 // Conservatively return [0, 1] since we don't track NaN
1233 resVal = IntervalValue(0, 1);
1234 break;
1235 default:
1236 assert(false && "undefined compare: ");
1237 }
1238 updateAbsValue(cmp->getRes(), resVal, node);
1239 }
1240 else if (op0Val.isAddr() && op1Val.isAddr())
1241 {
1242 const AddressValue& lhs = op0Val.getAddrs();
1243 const AddressValue& rhs = op1Val.getAddrs();
1244 auto predicate = cmp->getPredicate();
1245 switch (predicate)
1246 {
1247 case CmpStmt::ICMP_EQ:
1248 case CmpStmt::FCMP_OEQ:
1249 case CmpStmt::FCMP_UEQ:
1250 {
1251 if (lhs.hasIntersect(rhs))
1252 {
1253 resVal = IntervalValue(0, 1);
1254 }
1255 else if (lhs.empty() && rhs.empty())
1256 {
1257 resVal = IntervalValue(1, 1);
1258 }
1259 else
1260 {
1261 resVal = IntervalValue(0, 0);
1262 }
1263 break;
1264 }
1265 case CmpStmt::ICMP_NE:
1266 case CmpStmt::FCMP_ONE:
1267 case CmpStmt::FCMP_UNE:
1268 {
1269 if (lhs.hasIntersect(rhs))
1270 {
1271 resVal = IntervalValue(0, 1);
1272 }
1273 else if (lhs.empty() && rhs.empty())
1274 {
1275 resVal = IntervalValue(0, 0);
1276 }
1277 else
1278 {
1279 resVal = IntervalValue(1, 1);
1280 }
1281 break;
1282 }
1283 case CmpStmt::ICMP_UGT:
1284 case CmpStmt::ICMP_SGT:
1285 case CmpStmt::FCMP_OGT:
1286 case CmpStmt::FCMP_UGT:
1287 {
1288 if (lhs.size() == 1 && rhs.size() == 1)
1289 {
1290 resVal = IntervalValue(*lhs.begin() > *rhs.begin());
1291 }
1292 else
1293 {
1294 resVal = IntervalValue(0, 1);
1295 }
1296 break;
1297 }
1298 case CmpStmt::ICMP_UGE:
1299 case CmpStmt::ICMP_SGE:
1300 case CmpStmt::FCMP_OGE:
1301 case CmpStmt::FCMP_UGE:
1302 {
1303 if (lhs.size() == 1 && rhs.size() == 1)
1304 {
1305 resVal = IntervalValue(*lhs.begin() >= *rhs.begin());
1306 }
1307 else
1308 {
1309 resVal = IntervalValue(0, 1);
1310 }
1311 break;
1312 }
1313 case CmpStmt::ICMP_ULT:
1314 case CmpStmt::ICMP_SLT:
1315 case CmpStmt::FCMP_OLT:
1316 case CmpStmt::FCMP_ULT:
1317 {
1318 if (lhs.size() == 1 && rhs.size() == 1)
1319 {
1320 resVal = IntervalValue(*lhs.begin() < *rhs.begin());
1321 }
1322 else
1323 {
1324 resVal = IntervalValue(0, 1);
1325 }
1326 break;
1327 }
1328 case CmpStmt::ICMP_ULE:
1329 case CmpStmt::ICMP_SLE:
1330 case CmpStmt::FCMP_OLE:
1331 case CmpStmt::FCMP_ULE:
1332 {
1333 if (lhs.size() == 1 && rhs.size() == 1)
1334 {
1335 resVal = IntervalValue(*lhs.begin() <= *rhs.begin());
1336 }
1337 else
1338 {
1339 resVal = IntervalValue(0, 1);
1340 }
1341 break;
1342 }
1344 resVal = IntervalValue(0, 0);
1345 break;
1346 case CmpStmt::FCMP_TRUE:
1347 resVal = IntervalValue(1, 1);
1348 break;
1349 case CmpStmt::FCMP_ORD:
1350 case CmpStmt::FCMP_UNO:
1351 // FCMP_ORD: true if both operands are not NaN
1352 // FCMP_UNO: true if either operand is NaN
1353 // Conservatively return [0, 1] since we don't track NaN
1354 resVal = IntervalValue(0, 1);
1355 break;
1356 default:
1357 assert(false && "undefined compare: ");
1358 }
1359 updateAbsValue(cmp->getRes(), resVal, node);
1360 }
1361 }
1362 }
1363}
1364
1366{
1367 const ICFGNode* node = load->getICFGNode();
1369 loadValue(SVFUtil::cast<ValVar>(load->getRHSVar()), node);
1370 updateAbsValue(load->getLHSVar(), loaded, node);
1371}
1372
1374{
1375 const ICFGNode* node = store->getICFGNode();
1376 AbstractValue val = getAbsValue(store->getRHSVar(), node);
1377 storeValue(SVFUtil::cast<ValVar>(store->getLHSVar()), val, node);
1378}
1379
1381{
1382 const ICFGNode* node = copy->getICFGNode();
1383 const SVFVar* lhsVar = copy->getLHSVar();
1384 const SVFVar* rhsVar = copy->getRHSVar();
1385
1386 auto getZExtValue = [&](const SVFVar* var)
1387 {
1388 const SVFType* type = var->getType();
1389 if (SVFUtil::isa<SVFIntegerType>(type))
1390 {
1391 u32_t bits = type->getByteSize() * 8;
1392 const AbstractValue& val = getAbsValue(var, node);
1393 if (val.getInterval().is_numeral())
1394 {
1395 if (bits == 8)
1396 {
1397 int8_t signed_i8_value = val.getInterval().getIntNumeral();
1400 }
1401 else if (bits == 16)
1402 {
1403 s16_t signed_i16_value = val.getInterval().getIntNumeral();
1406 }
1407 else if (bits == 32)
1408 {
1409 s32_t signed_i32_value = val.getInterval().getIntNumeral();
1412 }
1413 else if (bits == 64)
1414 {
1415 s64_t signed_i64_value = val.getInterval().getIntNumeral();
1417 }
1418 else
1419 assert(false && "cannot support int type other than u8/16/32/64");
1420 }
1421 else
1422 {
1423 return IntervalValue::top();
1424 }
1425 }
1426 return IntervalValue::top();
1427 };
1428
1429 auto getTruncValue = [&](const SVFVar* var, const SVFType* dstType)
1430 {
1431 const IntervalValue& itv = getAbsValue(var, node).getInterval();
1432 if(itv.isBottom()) return itv;
1434 s64_t int_ub = itv.ub().getIntNumeral();
1435 u32_t dst_bits = dstType->getByteSize() * 8;
1436 if (dst_bits == 8)
1437 {
1438 int8_t s8_lb = static_cast<int8_t>(int_lb);
1439 int8_t s8_ub = static_cast<int8_t>(int_ub);
1440 if (s8_lb > s8_ub)
1442 return IntervalValue(s8_lb, s8_ub);
1443 }
1444 else if (dst_bits == 16)
1445 {
1446 s16_t s16_lb = static_cast<s16_t>(int_lb);
1447 s16_t s16_ub = static_cast<s16_t>(int_ub);
1448 if (s16_lb > s16_ub)
1450 return IntervalValue(s16_lb, s16_ub);
1451 }
1452 else if (dst_bits == 32)
1453 {
1454 s32_t s32_lb = static_cast<s32_t>(int_lb);
1455 s32_t s32_ub = static_cast<s32_t>(int_ub);
1456 if (s32_lb > s32_ub)
1458 return IntervalValue(s32_lb, s32_ub);
1459 }
1460 else
1461 {
1462 assert(false && "cannot support dst int type other than u8/16/32");
1463 abort();
1464 }
1465 };
1466
1467 const AbstractValue& rhsVal = getAbsValue(rhsVar, node);
1468
1469 if (copy->getCopyKind() == CopyStmt::COPYVAL)
1470 {
1472 }
1473 else if (copy->getCopyKind() == CopyStmt::ZEXT)
1474 {
1475 updateAbsValue(lhsVar, getZExtValue(rhsVar), node);
1476 }
1477 else if (copy->getCopyKind() == CopyStmt::SEXT)
1478 {
1479 updateAbsValue(lhsVar, rhsVal.getInterval(), node);
1480 }
1481 else if (copy->getCopyKind() == CopyStmt::FPTOSI)
1482 {
1483 updateAbsValue(lhsVar, rhsVal.getInterval(), node);
1484 }
1485 else if (copy->getCopyKind() == CopyStmt::FPTOUI)
1486 {
1487 updateAbsValue(lhsVar, rhsVal.getInterval(), node);
1488 }
1489 else if (copy->getCopyKind() == CopyStmt::SITOFP)
1490 {
1491 updateAbsValue(lhsVar, rhsVal.getInterval(), node);
1492 }
1493 else if (copy->getCopyKind() == CopyStmt::UITOFP)
1494 {
1495 updateAbsValue(lhsVar, rhsVal.getInterval(), node);
1496 }
1497 else if (copy->getCopyKind() == CopyStmt::TRUNC)
1498 {
1499 updateAbsValue(lhsVar, getTruncValue(rhsVar, lhsVar->getType()), node);
1500 }
1501 else if (copy->getCopyKind() == CopyStmt::FPTRUNC)
1502 {
1503 updateAbsValue(lhsVar, rhsVal.getInterval(), node);
1504 }
1505 else if (copy->getCopyKind() == CopyStmt::INTTOPTR)
1506 {
1507 //insert nullptr
1508 }
1509 else if (copy->getCopyKind() == CopyStmt::PTRTOINT)
1510 {
1512 }
1513 else if (copy->getCopyKind() == CopyStmt::BITCAST)
1514 {
1515 if (rhsVal.isAddr())
1517 }
1518 else
1519 assert(false && "undefined copy kind");
1520}
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 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:43
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 hasAbsValue(const ValVar *var, const ICFGNode *node) const
Side-effect-free existence check.
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)
Virtual so full-sparse can layer the GepObj overlay on top.
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)
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.
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)
virtual void handleCallSite(const ICFGNode *node)
Handle a call site node: dispatch to ext-call, direct-call, or indirect-call handling.
void collectBranchRefinement(const IntraCFGEdge *edge, AbstractState &as)
void updateStateOnRet(const RetPE *retPE)
bool hasAbsState(const ICFGNode *node)
void updateStateOnCopy(const CopyStmt *copy)
FIFOWorkList< const FunObjVar * > collectProgEntryFuns()
Get all entry point functions (functions without callers)
bool isSwitchBranchEdgeFeasible(const IntraCFGEdge *edge, AbstractState &as)
Returns true if the switch branch is feasible.
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 recordBranchRefinement(NodeID objId, const IntervalValue &narrowed, AbstractState &as, const ICFGNode *loadIcfg, const ICFGNode *succ)
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 u32_t getVirtualMemAddress(u32_t idx)
The physical address starts with 0x7f...... + idx.
bool isInterval() const
IntervalValue & getInterval()
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
iterator begin()
Iterators.
NodeType * getGNode(NodeID id) const
Get a node.
const GEdgeSetTy & getInEdges() const
const SVFStmtList & getSVFStmts() const
Definition ICFGNode.h:115
ICFGEdge * getICFGEdge(const ICFGNode *src, const ICFGNode *dst, ICFGEdge::ICFGEdgeK kind)
Get a SVFG edge according to src and dst.
Definition ICFG.cpp:311
void updateCallGraph(CallGraph *callgraph)
update ICFG for indirect calls
Definition ICFG.cpp:427
FunEntryICFGNode * getFunEntryICFGNode(const FunObjVar *fun)
Add a function entry node.
Definition ICFG.cpp:242
GlobalICFGNode * getGlobalICFGNode() const
Definition ICFG.h:244
NodeID getBlkPtr() const
Definition IRGraph.h:255
void meet_with(const IntervalValue &other)
Return a intersected IntervalValue.
static BoundedInt minus_infinity()
Get minus infinity -inf.
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:247
static const OptionMap< u32_t > AESparsity
Definition Options.h:243
static const OptionMap< u32_t > AEFunEntry
Definition Options.h:244
static const Option< bool > PStat
Definition Options.h:116
const ValVar * getRHSVar() const
const ValVar * getLHSVar() const
ICFG * getICFG() const
Definition SVFIR.h:229
const CallSiteToFunPtrMap & getIndirectCallsites() const
Add/get indirect callsites.
Definition SVFIR.h:451
const SVFVar * getSVFVar(NodeID id) const
ObjVar/GepObjVar/BaseObjVar.
Definition SVFIR.h:133
static SVFIR * getPAG(bool buildFromFile=false)
Singleton design here to make sure we only have one instance during any analysis.
Definition SVFIR.h:118
virtual void endClk()
Definition SVFStat.h:63
virtual void startClk()
Definition SVFStat.h:58
ICFGNode * getICFGNode() const
u32_t getByteSize() const
Definition SVFType.h:289
NodeID getId() const
Get ID.
Definition SVFValue.h:163
const ValVar * getRHSVar() const
const ValVar * getLHSVar() const
bool isProgEntryFunction(const FunObjVar *)
Program entry function e.g. main.
Definition SVFUtil.cpp:442
std::string errMsg(const std::string &msg)
Print error message by converting a string into red string output.
Definition SVFUtil.cpp:78
std::ostream & errs()
Overwrite llvm::errs()
Definition SVFUtil.h:58
bool isExtCall(const FunObjVar *fun)
Definition SVFUtil.cpp:437
for isBitcode
Definition BasicTypes.h:70
u32_t NodeID
Definition GeneralType.h:56
signed short s16_t
Definition GeneralType.h:54
unsigned short u16_t
Definition GeneralType.h:53
WTONode< ICFG > ICFGSingletonWTO
Definition ICFGWTO.h:45
llvm::IRBuilder IRBuilder
Definition BasicTypes.h:76
signed s32_t
Definition GeneralType.h:48
unsigned u32_t
Definition GeneralType.h:47
signed long long s64_t
Definition GeneralType.h:50
WTOComponent< ICFG > ICFGWTOComp
Definition ICFGWTO.h:44