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);
49 utils->collectCheckPoint();
50
51 analyse();
52 utils->checkPointAllSet();
53 stat->endClk();
54 stat->finializeStat();
55 if (Options::PStat())
56 stat->performStat();
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();
68 callGraph = preAnalysis->getCallGraph();
69 icfg->updateCallGraph(callGraph);
70 preAnalysis->initWTO();
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.
94 static AbstractInterpretation* instance = []() -> AbstractInterpretation*
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{
124 FIFOWorkList<const FunObjVar*> entryFunctions;
125 const bool mainEntry = Options::AEFunEntry() == AEFunEntryMode::MAIN;
126 Set<NodeID> visitedEntrySCCs;
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 {
156 const CallGraphNode* sccNode = callGraph->getGNode(nodeId);
157 for (auto inEdge : sccNode->getInEdges())
158 {
159 if (!cgSCCNodes.test(inEdge->getSrcID()))
160 {
161 hasExternalCaller = true;
162 break;
163 }
164 }
165 if (hasExternalCaller)
166 break;
167 }
168
169 if (hasExternalCaller)
170 continue;
171
172 visitedEntrySCCs.insert(repNodeId);
173 const FunObjVar* entryFun = fun;
174 for (NodeID nodeId : cgSCCNodes)
175 {
176 const FunObjVar* sccFun = callGraph->getGNode(nodeId)->getFunction();
178 {
179 entryFun = sccFun;
180 break;
181 }
182 }
183 entryFunctions.push(entryFun);
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
220 const ICFGNode* globalNode = icfg->getGlobalICFGNode();
221 while (!entryFunctions.empty())
222 {
223 const FunObjVar* entryFun = entryFunctions.pop();
224 const ICFGNode* funEntry = icfg->getFunEntryICFGNode(entryFun);
225 updateAbsState(funEntry, getAbsState(globalNode));
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].
257 AbstractValue blkPtrValue(IntervalValue::top());
258 blkPtrValue.getAddrs().insert(BlackHoleObjAddr);
259 abstractTrace[node][PAG::getPAG()->getBlkPtr()] = blkPtrValue;
260}
261
269{
270 // Collect all feasible predecessor states, then merge at the end.
271 AbstractState merged;
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 AbstractState predState = getAbsState(pred);
281 bool feasible = false;
282 if (const IntraCFGEdge* intraCfgEdge = SVFUtil::dyn_cast<IntraCFGEdge>(edge))
283 {
284 if (intraCfgEdge->getCondition())
285 {
286 feasible = isBranchEdgeFeasible(intraCfgEdge, predState);
287 if (feasible)
288 applyBranchRefinement(intraCfgEdge, predState);
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();
311 feasible = hasAbsState(callSite);
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
325 joinStates(merged, predState);
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
450 IntervalValue result = self;
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
469 break;
475 break;
481 break;
487 break;
488 default:
489 return IntervalValue::top();
490 }
491 return result;
492}
493
495 AbstractState& as)
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();
507 resVal.meet_with(IntervalValue((s64_t)succ, succ));
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());
532 u64_t matchedCases = 0;
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.
549 if (!isSwitchDefaultEdge(edge))
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
567 AbstractState& as)
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
707 AbstractState& as)
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()))
712 return isCmpBranchEdgeFeasible(edge, as);
713 return isSwitchBranchEdgeFeasible(edge,
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
732 const ICFGNode* globalNode = icfg->getGlobalICFGNode();
733 if (hasAbsState(globalNode))
734 updateAbsState(node, getAbsState(globalNode));
735 else
737 }
738 else
739 {
740 return false; // unreachable node
741 }
742 }
743
744 // Store the previous state for fixpoint detection
745 AbstractState prevState = getAbsState(node);
746
747 stat->getBlockTrace()++;
748 stat->getICFGNodeTrace()++;
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 {
759 handleCallSite(callNode);
760 }
761
762 // Run detectors
763 for (auto& detector: detectors)
764 detector->detect(node);
765 stat->countStateSize();
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()))
803 handleLoopOrRecursion(cycle, caller);
804 }
805 }
806}
807
808
810{
811 if (const CallICFGNode* callNode = SVFUtil::dyn_cast<CallICFGNode>(node))
812 {
813 if (isExtCall(callNode))
814 {
815 handleExtCall(callNode);
816 }
817 else
818 {
819 // Handle both direct and indirect calls uniformly
820 handleFunCall(callNode);
821 }
822 }
823 else
824 assert (false && "it is not call node");
825}
826
828{
829 return SVFUtil::isExtCall(callNode->getCalledFunction());
830}
831
833{
834 utils->handleExtAPI(callNode);
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
849 const auto callsiteMaps = svfir->getIndirectCallsites();
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
858 const AbstractValue& Addrs = getAbsValue(svfir->getSVFVar(call_id), callNode);
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{
878 if (skipRecursiveCall(callNode))
879 return;
880
881 // Direct call: callee is known
882 if (const FunObjVar* callee = callNode->getCalledFunction())
883 {
884 const ICFGNode* calleeEntry = icfg->getFunEntryICFGNode(callee);
885 handleFunction(calleeEntry, callNode);
886 const RetICFGNode* retNode = callNode->getRetICFGNode();
887 updateAbsState(retNode, getAbsState(callNode));
888 return;
889 }
890
891 // Indirect call: use Andersen's call graph to get all resolved callees.
892 const RetICFGNode* retNode = callNode->getRetICFGNode();
893 if (callGraph->hasIndCSCallees(callNode))
894 {
895 const auto& callees = callGraph->getIndCSCallees(callNode);
896 for (const FunObjVar* callee : callees)
897 {
898 if (callee->isDeclaration())
899 continue;
900 const ICFGNode* calleeEntry = icfg->getFunEntryICFGNode(callee);
901 handleFunction(calleeEntry, callNode);
902 }
903 }
904 // Resume return node from caller's state (context-insensitive)
905 updateAbsState(retNode, getAbsState(callNode));
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 {
915 updateStateOnAddr(addr);
916 }
917 else if (const BinaryOPStmt *binary = SVFUtil::dyn_cast<BinaryOPStmt>(stmt))
918 {
919 updateStateOnBinary(binary);
920 }
921 else if (const CmpStmt *cmp = SVFUtil::dyn_cast<CmpStmt>(stmt))
922 {
923 updateStateOnCmp(cmp);
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 {
946 updateStateOnGep(gep);
947 }
948 else if (const SelectStmt *select = SVFUtil::dyn_cast<SelectStmt>(stmt))
949 {
950 updateStateOnSelect(select);
951 }
952 else if (const PhiStmt *phi = SVFUtil::dyn_cast<PhiStmt>(stmt))
953 {
954 updateStateOnPhi(phi);
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();
983 IntervalValue offsetPair = getGepElementIndex(gep);
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);
994 AbstractValue resVal;
995 if (condVal.getInterval().is_numeral())
996 {
997 resVal = condVal.getInterval().is_zero() ? fVal : tVal;
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();
1010 AbstractValue rhs;
1011 for (u32_t i = 0; i < phi->getOpVarNum(); i++)
1012 {
1013 const ICFGNode* opICFGNode = phi->getOpICFGNode(i);
1014 if (hasAbsState(opICFGNode))
1015 {
1016 AbstractState tmpState = getAbsState(opICFGNode);
1017 const AbstractValue& opVal = getAbsValue(phi->getOpVar(i), opICFGNode);
1018 const ICFGEdge* edge = icfg->getICFGEdge(opICFGNode, icfgNode, ICFGEdge::IntraCF);
1019 if (edge)
1020 {
1021 const IntraCFGEdge* intraEdge = SVFUtil::cast<IntraCFGEdge>(edge);
1022 if (intraEdge->getCondition())
1023 {
1024 if (isBranchEdgeFeasible(intraEdge, tmpState))
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();
1046 AbstractValue rhs;
1047 for (u32_t i = 0; i < callPE->getOpVarNum(); i++)
1048 {
1049 const ICFGNode* opICFGNode = callPE->getOpCallICFGNode(i);
1050 if (hasAbsState(opICFGNode))
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);
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();
1093 IntervalValue resVal;
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{
1148 assert(predicate >= CmpStmt::FIRST_ICMP_PREDICATE &&
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);
1156 const bool hasUnknownTarget = !lhsTargetKnown || !rhsTargetKnown;
1157 const bool targetsMayBeEqual = lhs.hasIntersect(rhs);
1158 const bool targetsMustBeEqual =
1159 targetsMayBeEqual && lhs.size() == 1 && rhs.size() == 1;
1160
1161 IntervalValue equality;
1162 if (hasUnknownTarget)
1163 {
1164 // Case 1: an unknown target may equal or differ from the other target.
1165 equality = IntervalValue((s64_t)0, (s64_t)1);
1166 }
1167 else if (!targetsMayBeEqual)
1168 {
1169 // Case 2: known disjoint target sets are definitely unequal.
1170 equality = IntervalValue((s64_t)0);
1171 }
1172 else if (targetsMustBeEqual)
1173 {
1174 // Case 3: intersecting single-target sets contain the same target.
1175 equality = IntervalValue((s64_t)1);
1176 }
1177 else
1178 {
1179 // Case 4: intersecting sets with multiple choices may be equal.
1180 equality = IntervalValue((s64_t)0, (s64_t)1);
1181 }
1182
1183 IntervalValue result((s64_t)0, (s64_t)1);
1184 if (predicate == CmpStmt::ICMP_EQ)
1185 result = equality;
1186 else if (predicate == CmpStmt::ICMP_NE)
1187 result = IntervalValue((s64_t)1) - equality;
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
1257 IntervalValue result;
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();
1279 AbstractValue loaded =
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();
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();
1309 u32_t unsigned_value = static_cast<uint8_t>(signed_i8_value);
1310 return IntervalValue(unsigned_value, unsigned_value);
1311 }
1312 else if (bits == 16)
1313 {
1314 s16_t signed_i16_value = val.getInterval().getIntNumeral();
1315 u32_t unsigned_value = static_cast<u16_t>(signed_i16_value);
1316 return IntervalValue(unsigned_value, unsigned_value);
1317 }
1318 else if (bits == 32)
1319 {
1320 s32_t signed_i32_value = val.getInterval().getIntNumeral();
1321 u32_t unsigned_value = static_cast<u32_t>(signed_i32_value);
1322 return IntervalValue(unsigned_value, unsigned_value);
1323 }
1324 else if (bits == 64)
1325 {
1326 s64_t signed_i64_value = val.getInterval().getIntNumeral();
1327 return IntervalValue((s64_t)signed_i64_value, (s64_t)signed_i64_value);
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;
1344 s64_t int_lb = itv.lb().getIntNumeral();
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)
1352 return utils->getRangeLimitFromType(dstType);
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)
1360 return utils->getRangeLimitFromType(dstType);
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)
1368 return utils->getRangeLimitFromType(dstType);
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 {
1382 updateAbsValue(lhsVar, rhsVal, node);
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 {
1422 updateAbsValue(lhsVar, IntervalValue::top(), node);
1423 }
1424 else if (copy->getCopyKind() == CopyStmt::BITCAST)
1425 {
1426 if (rhsVal.isAddr())
1427 updateAbsValue(lhsVar, rhsVal, node);
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
Handles external API calls and manages abstract states.
Definition AbsExtAPI.h:49
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
u32_t getIDFromAddr(u32_t addr) const
Return the internal index if addr is an address otherwise return the value of idx.
virtual bool inAddrToValTable(u32_t id) const
whether the memory address stores abstract value
static bool isNullOrBlackHoleAddr(u32_t addr)
Whether addr has no concrete backing memory object.
void initObjVar(const ObjVar *objVar)
virtual AbstractValue & load(u32_t addr)
void join_with(const AbstractValue &other)
bool isInterval() const
IntervalValue & getInterval()
AddressValue & getAddrs()
bool isAddr() const
const ObjVar * getRHSVar() const
const ValVar * getLHSVar() const
std::pair< AddressValue::AddrSet::iterator, bool > insert(u32_t id)
bool contains(u32_t id) const
Return true if the AddressValue contains n.
bool hasIntersect(const AddressValue &other) const
bool isBottom() const
bool empty() const
u32_t size() const
AddrSet::const_iterator begin() const
NodeID getRHSVarID() const
u32_t getOpcode() const
s64_t getIntNumeral() const
bool geq(const BoundedInt &rhs) const
bool leq(const BoundedInt &rhs) const
const FunObjVar * getFunction() const
Get function of this call node.
Definition CallGraph.h:191
const FunObjVar * getCalledFunction() const
Definition ICFGNode.h:501
const RetICFGNode * getRetICFGNode() const
Return callsite.
Definition ICFGNode.h:440
const CallICFGNode * getOpCallICFGNode(u32_t op_idx) const
Return the CallICFGNode of the i-th operand.
u32_t getPredicate() const
@ 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 push(const Data &data)
Definition WorkList.h:180
bool empty() const
Definition WorkList.h:161
bool isDeclaration() const
NodeType * getSrcNode() const
NodeType * getDstNode() const
const GEdgeSetTy & getInEdges() const
const ValVar * getRHSVar() const
const ValVar * getLHSVar() const
virtual const FunObjVar * getFun() const
Return the function of this ICFGNode.
Definition ICFGNode.h:75
const SVFStmtList & getSVFStmts() const
Definition ICFGNode.h:116
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.
bool isTop() const
const BoundedInt & ub() const
Return the upper bound.
s64_t getIntNumeral() const
bool is_numeral() const
Return true if the IntervalValue is a number [num, num].
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].
static bool is_infinite(const BoundedInt &e)
const BoundedInt & lb() const
Return the lower bound.
s64_t getSuccessorCondValue() const
Definition ICFGEdge.h:144
const SVFVar * getCondition() const
Definition ICFGEdge.h:139
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 ICFGNode * getOpICFGNode(u32_t op_idx) const
Return the corresponding ICFGNode of this operand.
const CallICFGNode * getCallICFGNode() const
Definition ICFGNode.h:620
const ValVar * getRHSVar() const
const ValVar * getLHSVar() const
static SVFIR * getPAG(bool buildFromFile=false)
Singleton design here to make sure we only have one instance during any analysis.
Definition SVFIR.h:121
ICFGNode * getICFGNode() const
GNodeK getKind() const
Definition SVFType.h:251
bool isPointerTy() const
Definition SVFType.h:292
u32_t getByteSize() const
Definition SVFType.h:287
NodeID getId() const
Get ID.
Definition SVFValue.h:158
virtual const SVFType * getType() const
Definition SVFValue.h:169
const SVFVar * getCondition() const
const ValVar * getTrueValue() const
const ValVar * getFalseValue() const
bool test(unsigned Idx) const
const ValVar * getRHSVar() const
const ValVar * getLHSVar() const
bool isProgEntryFunction(const FunObjVar *)
Program entry function e.g. main.
Definition SVFUtil.cpp:531
std::enable_if_t<!is_simple_type< Y >::value, typename cast_retty< X, const Y >::ret_type > cast(const Y &Val)
Definition Casting.h:360
LLVM_NODISCARD bool isa(const Y &Val)
Definition Casting.h:241
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
LLVM_NODISCARD std::enable_if_t<!is_simple_type< Y >::value, typename cast_retty< X, const Y >::ret_type > dyn_cast(const Y &Val)
Definition Casting.h:405
for isBitcode
Definition BasicTypes.h:70
WTOCycle< ICFG > ICFGCycleWTO
Definition ICFGWTO.h:49
unsigned long long u64_t
Definition GeneralType.h:69
u32_t NodeID
Definition GeneralType.h:76
std::unordered_set< Key, Hash, KeyEqual, Allocator > Set
Definition GeneralType.h:51
signed short s16_t
Definition GeneralType.h:74
unsigned short u16_t
Definition GeneralType.h:73
WTONode< ICFG > ICFGSingletonWTO
Definition ICFGWTO.h:48
std::unordered_map< Key, Value, Hash, KeyEqual, Allocator > Map
Definition GeneralType.h:56
signed s32_t
Definition GeneralType.h:68
SparseBitVector NodeBS
Definition GeneralType.h:82
unsigned u32_t
Definition GeneralType.h:67
signed long long s64_t
Definition GeneralType.h:70
WTOComponent< ICFG > ICFGWTOComp
Definition ICFGWTO.h:47