49 utils->collectCheckPoint();
52 utils->checkPointAllSet();
54 stat->finializeStat();
58 detector->reportBug();
127 auto* callGraphSCC =
preAnalysis->getCallGraphSCC();
142 entryFunctions.
push(fun);
148 NodeID repNodeId = callGraphSCC->repNode(cgNode->
getId());
149 if (visitedEntrySCCs.count(repNodeId))
152 const NodeBS& cgSCCNodes = callGraphSCC->subNodes(repNodeId);
153 bool hasExternalCaller =
false;
154 for (
NodeID nodeId : cgSCCNodes)
159 if (!cgSCCNodes.
test(inEdge->getSrcID()))
161 hasExternalCaller =
true;
165 if (hasExternalCaller)
169 if (hasExternalCaller)
172 visitedEntrySCCs.insert(repNodeId);
174 for (
NodeID nodeId : cgSCCNodes)
183 entryFunctions.
push(entryFun);
187 if (mainEntry && entryFunctions.
empty())
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");
195 return entryFunctions;
213 if (entryFunctions.
empty())
215 assert(
false &&
"No entry functions found for analysis");
221 while (!entryFunctions.
empty())
224 const ICFGNode* funEntry =
icfg->getFunEntryICFGNode(entryFun);
272 bool hasFeasiblePred =
false;
276 const ICFGNode* pred = edge->getSrcNode();
281 bool feasible =
false;
284 if (intraCfgEdge->getCondition())
326 hasFeasiblePred =
true;
330 if (!hasFeasiblePred)
357 const SVFVar* src = cs->getRHSVar();
411 auto it = swapPred.find(predicate);
413 predicate = it->second;
444 auto it = negPred.find(predicate);
446 predicate = it->second;
503 "CmpStmt result must be represented by a Boolean interval");
516 enum :
u32_t { DefaultSuccessor = 0 };
519 return branch->getSuccessor(DefaultSuccessor) == edge->
getDstNode();
532 u64_t matchedCases = 0;
533 for (
u32_t i = 1; i < branch->getNumSuccessors(); ++i)
535 const s64_t caseValue = branch->getSuccessorCondValue(i);
536 if (input.
lb().
leq(caseValue) && input.
ub().
geq(caseValue))
541 if (branch->getSuccessor(i) == edge->
getDstNode())
560 const u64_t span =
static_cast<u64_t>(input.
ub().getIntNumeral()) -
561 static_cast<u64_t>(input.
lb().getIntNumeral());
562 return span >= matchedCases;
569 bool feasible =
true;
570 std::vector<std::pair<const LoadStmt*, IntervalValue>> constraints;
578 "branch condition has no defining edge?");
583 s32_t predicate = cmpStmt->getPredicate();
596 const bool hasIntervalCmp =
598 if (!hasIntervalCmp && (opVal[0].isAddr() || opVal[1].isAddr()))
604 for (
int i = 0; i < 2; i++)
606 const int other = 1 - i;
610 if (opVal[i].getInterval().is_numeral())
614 else if (!opVal[other].getInterval().is_numeral())
625 predicate, succ, i == 0, opVal[i].getInterval(),
626 opVal[other].getInterval());
628 if (narrowed.
isTop())
634 constraints.emplace_back(load, narrowed);
652 for (
u32_t i = 1; i < branch->getNumSuccessors(); ++i)
654 if (branch->getSuccessor(i) == edge->
getDstNode())
657 caseValue = branch->getSuccessorCondValue(i);
675 for (
const auto& [load, narrowed] : constraints)
677 const ICFGNode* loadICFG = load->getICFGNode();
710 assert(!cmpVar->
getInEdges().empty() &&
"branch condition has no defining edge?");
747 stat->getBlockTrace()++;
748 stat->getICFGNodeTrace()++;
764 detector->detect(node);
765 stat->countStateSize();
785 assert(it !=
preAnalysis->getFuncToWTO().end() &&
"Missing WTO for function");
790 while (!worklist.
empty())
796 const ICFGNode* node = singleton->getICFGNode();
824 assert (
false &&
"it is not call node");
834 utils->handleExtAPI(callNode);
837 detector->handleStubFunctions(callNode);
849 const auto callsiteMaps =
svfir->getIndirectCallsites();
850 auto it = callsiteMaps.find(callNode);
851 if (it == callsiteMaps.end())
854 NodeID call_id = it->second;
884 const ICFGNode* calleeEntry =
icfg->getFunEntryICFGNode(callee);
893 if (
callGraph->hasIndCSCallees(callNode))
895 const auto& callees =
callGraph->getIndCSCallees(callNode);
898 if (callee->isDeclaration())
900 const ICFGNode* calleeEntry =
icfg->getFunEntryICFGNode(callee);
966 assert(
false &&
"implement this part");
974 assert(it == vmap.end() ||
975 (it->second.isAddr() &&
1098 resVal = (lhs + rhs);
1102 resVal = (lhs - rhs);
1106 resVal = (lhs * rhs);
1111 resVal = (lhs / rhs);
1116 resVal = (lhs % rhs);
1119 resVal = (lhs ^ rhs);
1122 resVal = (lhs & rhs);
1125 resVal = (lhs | rhs);
1128 resVal = (lhs >> rhs);
1131 resVal = (lhs << rhs);
1134 resVal = (lhs >> rhs);
1137 assert(
false &&
"undefined binary: ");
1150 "pointer comparison must use an ICMP predicate");
1152 const bool lhsTargetKnown =
1154 const bool rhsTargetKnown =
1156 const bool hasUnknownTarget = !lhsTargetKnown || !rhsTargetKnown;
1158 const bool targetsMustBeEqual =
1159 targetsMayBeEqual && lhs.
size() == 1 && rhs.
size() == 1;
1162 if (hasUnknownTarget)
1167 else if (!targetsMayBeEqual)
1172 else if (targetsMustBeEqual)
1200 result = (lhs == rhs);
1205 result = (lhs != rhs);
1211 result = (lhs > rhs);
1217 result = (lhs >= rhs);
1223 result = (lhs < rhs);
1229 result = (lhs <= rhs);
1243 assert(
false &&
"undefined compare: ");
1255 "CmpStmt operands must belong to the same value domain");
1297 auto getZExtValue = [&](
const SVFVar* var)
1309 u32_t unsigned_value =
static_cast<uint8_t
>(signed_i8_value);
1312 else if (bits == 16)
1315 u32_t unsigned_value =
static_cast<u16_t>(signed_i16_value);
1318 else if (bits == 32)
1321 u32_t unsigned_value =
static_cast<u32_t>(signed_i32_value);
1324 else if (bits == 64)
1330 assert(
false &&
"cannot support int type other than u8/16/32/64");
1340 auto getTruncValue = [&](
const SVFVar* var,
const SVFType* dstType)
1346 u32_t dst_bits = dstType->getByteSize() * 8;
1349 int8_t s8_lb =
static_cast<int8_t
>(int_lb);
1350 int8_t s8_ub =
static_cast<int8_t
>(int_ub);
1352 return utils->getRangeLimitFromType(dstType);
1355 else if (dst_bits == 16)
1359 if (s16_lb > s16_ub)
1360 return utils->getRangeLimitFromType(dstType);
1363 else if (dst_bits == 32)
1367 if (s32_lb > s32_ub)
1368 return utils->getRangeLimitFromType(dstType);
1373 assert(
false &&
"cannot support dst int type other than u8/16/32");
1430 assert(
false &&
"undefined copy kind");
static const LoadStmt * findBackingLoad(const SVFVar *var)
static IntervalValue computeCmpConstraint(s32_t predicate, s64_t succ, bool isLHS, const IntervalValue &self, const IntervalValue &other)
Handles external API calls and manages abstract states.
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.
void analyse()
Program entry.
virtual void handleGlobalNode()
virtual bool isExtCall(const CallICFGNode *callNode)
virtual void runOnModule()
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)
IntervalValue & getInterval()
AddressValue & getAddrs()
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
AddrSet::const_iterator begin() const
NodeID getRHSVarID() 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.
const FunObjVar * getCalledFunction() const
const RetICFGNode * getRetICFGNode() const
Return callsite.
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
@ 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)
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.
const SVFStmtList & getSVFStmts() const
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.
s64_t getIntNumeral() const
bool is_numeral() const
Return true if the IntervalValue is a number [num, num].
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
const SVFVar * getCondition() const
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
static const OptionMap< u32_t > AESparsity
static const OptionMap< u32_t > AEFunEntry
static const Option< bool > PStat
const ICFGNode * getOpICFGNode(u32_t op_idx) const
Return the corresponding ICFGNode of this operand.
const CallICFGNode * getCallICFGNode() const
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.
ICFGNode * getICFGNode() const
u32_t getByteSize() const
NodeID getId() const
Get ID.
virtual const SVFType * getType() const
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.
std::enable_if_t<!is_simple_type< Y >::value, typename cast_retty< X, const Y >::ret_type > cast(const Y &Val)
LLVM_NODISCARD bool isa(const Y &Val)
std::string errMsg(const std::string &msg)
Print error message by converting a string into red string output.
std::ostream & errs()
Overwrite llvm::errs().
bool isExtCall(const FunObjVar *fun)
LLVM_NODISCARD std::enable_if_t<!is_simple_type< Y >::value, typename cast_retty< X, const Y >::ret_type > dyn_cast(const Y &Val)
WTOCycle< ICFG > ICFGCycleWTO
std::unordered_set< Key, Hash, KeyEqual, Allocator > Set
WTONode< ICFG > ICFGSingletonWTO
std::unordered_map< Key, Value, Hash, KeyEqual, Allocator > Map
WTOComponent< ICFG > ICFGWTOComp