Static Value-Flow Analysis
Loading...
Searching...
No Matches
Public Member Functions | Protected Member Functions | List of all members
SVF::SemiSparseAbstractInterpretation Class Reference

#include <SparseAbstractInterpretation.h>

Inheritance diagram for SVF::SemiSparseAbstractInterpretation:
SVF::AbstractInterpretation SVF::FullSparseAbstractInterpretation

Public Member Functions

 SemiSparseAbstractInterpretation ()
 
 ~SemiSparseAbstractInterpretation () override=default
 
- Public Member Functions inherited from SVF::AbstractInterpretation
virtual void runOnModule ()
 
virtual ~AbstractInterpretation ()
 Destructor.
 
void analyse ()
 Program entry.
 
void analyzeFromAllProgEntries ()
 Analyze all entry points (functions without callers)
 
FIFOWorkList< const FunObjVar * > collectProgEntryFuns ()
 Get all entry point functions (functions without callers)
 
void addDetector (std::unique_ptr< AEDetector > detector)
 
const SVFVargetSVFVar (NodeID varId) const
 Retrieve SVFVar given its ID; asserts if no such variable exists.
 
AbstractStategetAbsState (const ICFGNode *node)
 
bool hasAbsState (const ICFGNode *node)
 
void getAbsState (const Set< const ValVar * > &vars, AbstractState &result, const ICFGNode *node)
 
void getAbsState (const Set< const ObjVar * > &vars, AbstractState &result, const ICFGNode *node)
 
void getAbsState (const Set< const SVFVar * > &vars, AbstractState &result, const ICFGNode *node)
 
IntervalValue getGepElementIndex (const GepStmt *gep)
 
IntervalValue getGepByteOffset (const GepStmt *gep)
 
AddressValue getGepObjAddrs (const ValVar *pointer, IntervalValue offset)
 
virtual AbstractValue loadValue (const ValVar *pointer, const ICFGNode *node)
 Virtual so full-sparse can layer the GepObj overlay on top.
 
virtual void storeValue (const ValVar *pointer, const AbstractValue &val, const ICFGNode *node)
 
const SVFTypegetPointeeElement (const ObjVar *var, const ICFGNode *node)
 
u32_t getAllocaInstByteSize (const AddrStmt *addr)
 
Map< const ICFGNode *, AbstractState > & getTrace ()
 
AbstractStateoperator[] (const ICFGNode *node)
 

Protected Member Functions

AbstractState getFullCycleHeadState (const ICFGCycleWTO *cycle) override
 
bool widenCycleState (const AbstractState &prev, const AbstractState &cur, const ICFGCycleWTO *cycle) override
 
bool narrowCycleState (const AbstractState &prev, const AbstractState &cur, const ICFGCycleWTO *cycle) override
 
const AbstractValuegetAbsValue (const ValVar *var, const ICFGNode *node) override
 
bool hasAbsValue (const ValVar *var, const ICFGNode *node) const override
 Side-effect-free existence check.
 
void updateAbsValue (const ValVar *var, const AbstractValue &val, const ICFGNode *node) override
 
void updateAbsState (const ICFGNode *node, const AbstractState &state) override
 
void joinStates (AbstractState &dst, const AbstractState &src) override
 
const ICFGNodegetICFGNode (const ValVar *var) const
 
virtual const AbstractValuegetAbsValue (const ValVar *var, const ICFGNode *node)
 
virtual const AbstractValuegetAbsValue (const ObjVar *var, const ICFGNode *node)
 
virtual const AbstractValuegetAbsValue (const SVFVar *var, const ICFGNode *node)
 
virtual bool hasAbsValue (const ValVar *var, const ICFGNode *node) const
 Side-effect-free existence check.
 
virtual bool hasAbsValue (const ObjVar *var, const ICFGNode *node) const
 
virtual bool hasAbsValue (const SVFVar *var, const ICFGNode *node) const
 
virtual void updateAbsValue (const ValVar *var, const AbstractValue &val, const ICFGNode *node)
 
virtual void updateAbsValue (const ObjVar *var, const AbstractValue &val, const ICFGNode *node)
 
virtual void updateAbsValue (const SVFVar *var, const AbstractValue &val, const ICFGNode *node)
 
- Protected Member Functions inherited from SVF::AbstractInterpretation
 AbstractInterpretation ()
 
virtual bool mergeStatesFromPredecessors (const ICFGNode *node)
 
bool isBranchEdgeFeasible (const IntraCFGEdge *edge, AbstractState &as)
 
void collectBranchRefinement (const IntraCFGEdge *edge, AbstractState &as)
 
virtual void recordBranchRefinement (NodeID objId, const IntervalValue &narrowed, AbstractState &as, const ICFGNode *loadIcfg, const ICFGNode *succ)
 
bool shouldApplyNarrowing (const FunObjVar *fun)
 Check if narrowing should be applied: always for regular loops, mode-dependent for recursion.
 

Additional Inherited Members

- Public Types inherited from SVF::AbstractInterpretation
enum  AESparsity { Dense , SemiSparse , Sparse }
 
enum  HandleRecur { TOP , WIDEN_ONLY , WIDEN_NARROW }
 
enum  AEFunEntryMode { MAIN , NO_MAIN }
 
- Static Public Member Functions inherited from SVF::AbstractInterpretation
static AbstractInterpretationgetAEInstance ()
 
- Protected Attributes inherited from SVF::AbstractInterpretation
SVFIRsvfir {nullptr}
 Data and helpers reachable from SparseAbstractInterpretation.
 
AEWTOpreAnalysis {nullptr}
 
Map< const ICFGNode *, AbstractStateabstractTrace
 per-node trace; owned here
 

Detailed Description

Abstract Interpretation for Options::AESparsity::SemiSparse.

ValVars live at their SVFG-style def-sites: reads pull from there, writes go there, state merges replace only the ObjVar map and skip the ValVar map, and the cycle helpers gather/scatter cycle ValVars around each widening iteration.

Definition at line 43 of file SparseAbstractInterpretation.h.

Constructor & Destructor Documentation

◆ SemiSparseAbstractInterpretation()

SVF::SemiSparseAbstractInterpretation::SemiSparseAbstractInterpretation ( )
inline

Definition at line 46 of file SparseAbstractInterpretation.h.

◆ ~SemiSparseAbstractInterpretation()

SVF::SemiSparseAbstractInterpretation::~SemiSparseAbstractInterpretation ( )
overridedefault

Member Function Documentation

◆ getAbsValue() [1/4]

const AbstractValue & AbstractInterpretation::getAbsValue ( const ObjVar var,
const ICFGNode node 
)
protectedvirtual

Reimplemented from SVF::AbstractInterpretation.

Definition at line 143 of file AbstractStateManager.cpp.

91{
94 return as.load(addr);
95}
unsigned u32_t
Definition CommandLine.h:18
AbstractState & getAbsState(const ICFGNode *node)
static u32_t getVirtualMemAddress(u32_t idx)
The physical address starts with 0x7f...... + idx.
llvm::IRBuilder IRBuilder
Definition BasicTypes.h:76

◆ getAbsValue() [2/4]

const AbstractValue & AbstractInterpretation::getAbsValue ( const SVFVar var,
const ICFGNode node 
)
protectedvirtual

Reimplemented from SVF::AbstractInterpretation.

Definition at line 144 of file AbstractStateManager.cpp.

98{
99 if (const ObjVar* objVar = SVFUtil::dyn_cast<ObjVar>(var))
100 return getAbsValue(objVar, node);
101 if (const ValVar* valVar = SVFUtil::dyn_cast<ValVar>(var))
102 return getAbsValue(valVar, node);
103 assert(false && "Unknown SVFVar kind");
104 abort();
105}
const AbstractValue & getAbsValue(const ValVar *var, const ICFGNode *node) override

◆ getAbsValue() [3/4]

const AbstractValue & AbstractInterpretation::getAbsValue ( const ValVar var,
const ICFGNode node 
)
protectedvirtual

Read a top-level variable's abstract value. Dense base does a direct trace lookup; sparse subclasses override with their own resolution chain (def-site walk, call-result fallback, etc.). All three overloads are virtual so full-sparse can route ObjVar reads through the SVFG.

Dense base: direct trace lookup, with a top sentinel for genuinely missing entries (e.g. function parameters like argc, never written before first read). Sparse subclasses override with a def-site resolution chain.

The "in map" check is a raw map.count — NOT inVarToValTable / inVarToAddrsTable, which gate on isInterval / isAddr. SVF canonically represents uninit and null-pointer shapes as (interval=bottom ∧ addrs=∅); those predicates would falsely report such an entry as "not present", and the top fallback below would then clobber the very signal NullptrDerefDetector::isUninit keys off.

Reimplemented from SVF::AbstractInterpretation.

Definition at line 142 of file AbstractStateManager.cpp.

81{
82 u32_t id = var->getId();
84 if (as.getVarToVal().count(id))
85 return as[id];
86 as[id] = IntervalValue::top();
87 return as[id];
88}
Map< const ICFGNode *, AbstractState > abstractTrace
per-node trace; owned here
static IntervalValue top()
Create the IntervalValue [-inf, +inf].

◆ getAbsValue() [4/4]

const AbstractValue & SemiSparseAbstractInterpretation::getAbsValue ( const ValVar var,
const ICFGNode node 
)
overrideprotectedvirtual

Read a top-level variable's abstract value. Dense base does a direct trace lookup; sparse subclasses override with their own resolution chain (def-site walk, call-result fallback, etc.). All three overloads are virtual so full-sparse can route ObjVar reads through the SVFG.

Dense base: direct trace lookup, with a top sentinel for genuinely missing entries (e.g. function parameters like argc, never written before first read). Sparse subclasses override with a def-site resolution chain.

The "in map" check is a raw map.count — NOT inVarToValTable / inVarToAddrsTable, which gate on isInterval / isAddr. SVF canonically represents uninit and null-pointer shapes as (interval=bottom ∧ addrs=∅); those predicates would falsely report such an entry as "not present", and the top fallback below would then clobber the very signal NullptrDerefDetector::isUninit keys off.

Reimplemented from SVF::AbstractInterpretation.

Definition at line 719 of file SparseAbstractInterpretation.cpp.

721{
722 // Read from the var's def-site (where updateAbsValue wrote it).
724}
virtual const AbstractValue & getAbsValue(const ValVar *var, const ICFGNode *node)
const ICFGNode * getICFGNode(const ValVar *var) const

◆ getFullCycleHeadState()

AbstractState SemiSparseAbstractInterpretation::getFullCycleHeadState ( const ICFGCycleWTO cycle)
overrideprotectedvirtual

Build a full cycle-head AbstractState. Dense default: trace[cycle_head] as-is. Semi-sparse subclass: also pull cycle ValVars from def-sites.

Reimplemented from SVF::AbstractInterpretation.

Definition at line 591 of file SparseAbstractInterpretation.cpp.

593{
594 // Start from the dense snapshot (ObjVars + any ValVars that happen to
595 // be cached at cycle_head's trace entry).
597
599 if (valVars.empty())
600 return snap; // no cycle ValVars known: nothing to pull
601
602 // Drop stale ValVar entries and pull each cycle ValVar from its
603 // def-site. ValVars without a genuine stored value are skipped to
604 // avoid getAbsValue's top-fallback contaminating body def-sites on
605 // the subsequent widen/narrow scatter.
606 snap.clearValVars();
607 for (const ValVar* v : valVars)
608 {
609 const ICFGNode* defSite = v->getICFGNode();
610 if (!defSite || !hasAbsValue(v, defSite))
611 continue;
612 snap[v->getId()] = getAbsValue(v, defSite);
613 }
614 return snap;
615}
const Set< const ValVar * > getCycleValVars(const ICFGCycleWTO *cycle) const
Definition AEWTO.h:83
virtual AbstractState getFullCycleHeadState(const ICFGCycleWTO *cycle)
bool hasAbsValue(const ValVar *var, const ICFGNode *node) const override
Side-effect-free existence check.

◆ getICFGNode()

const ICFGNode * SemiSparseAbstractInterpretation::getICFGNode ( const ValVar var) const
protected

Definition at line 687 of file SparseAbstractInterpretation.cpp.

689{
690 // const ValVars are all defined in global node
691 if (!var->getICFGNode())
692 {
693 return svfir->getICFG()->getGlobalICFGNode();
694 }
695 // for return value of callsite, use the ret-site as def-site
696 else if (SVFUtil::isa<CallICFGNode>(var->getICFGNode()) &&
697 SVFUtil::isa<RetValPN>(var))
698 {
699 return SVFUtil::dyn_cast<CallICFGNode>(var->getICFGNode())
700 ->getRetICFGNode();
701 }
702 // for other ValVars, use their def-site as the node to query abstract
703 // value.
704 else
705 {
706 return var->getICFGNode();
707 }
708}
SVFIR * svfir
Data and helpers reachable from SparseAbstractInterpretation.
GlobalICFGNode * getGlobalICFGNode() const
Definition ICFG.h:244
ICFG * getICFG() const
Definition SVFIR.h:229

◆ hasAbsValue() [1/4]

bool AbstractInterpretation::hasAbsValue ( const ObjVar var,
const ICFGNode node 
) const
protectedvirtual

Reimplemented from SVF::AbstractInterpretation.

Definition at line 148 of file AbstractStateManager.cpp.

120{
121 auto it = abstractTrace.find(node);
122 if (it == abstractTrace.end())
123 return false;
124 return it->second.getLocToVal().count(var->getId()) != 0;
125}

◆ hasAbsValue() [2/4]

bool AbstractInterpretation::hasAbsValue ( const SVFVar var,
const ICFGNode node 
) const
protectedvirtual

Reimplemented from SVF::AbstractInterpretation.

Definition at line 149 of file AbstractStateManager.cpp.

128{
129 if (const ObjVar* objVar = SVFUtil::dyn_cast<ObjVar>(var))
130 return hasAbsValue(objVar, node);
131 if (const ValVar* valVar = SVFUtil::dyn_cast<ValVar>(var))
132 return hasAbsValue(valVar, node);
133 return false;
134}

◆ hasAbsValue() [3/4]

bool AbstractInterpretation::hasAbsValue ( const ValVar var,
const ICFGNode node 
) const
protectedvirtual

Side-effect-free existence check.

Dense base: direct existence check at node. Mirrors the simplified getAbsValue lookup — uses raw map.contains rather than inVar*Table predicates, which would falsely report neutral (interval=bottom ∧ addrs=∅) entries as "not present".

Reimplemented from SVF::AbstractInterpretation.

Definition at line 147 of file AbstractStateManager.cpp.

112{
113 auto it = abstractTrace.find(node);
114 if (it == abstractTrace.end())
115 return false;
116 return it->second.getVarToVal().count(var->getId()) != 0;
117}

◆ hasAbsValue() [4/4]

bool SemiSparseAbstractInterpretation::hasAbsValue ( const ValVar var,
const ICFGNode node 
) const
overrideprotectedvirtual

Side-effect-free existence check.

Dense base: direct existence check at node. Mirrors the simplified getAbsValue lookup — uses raw map.contains rather than inVar*Table predicates, which would falsely report neutral (interval=bottom ∧ addrs=∅) entries as "not present".

Reimplemented from SVF::AbstractInterpretation.

Definition at line 726 of file SparseAbstractInterpretation.cpp.

728{
730}
virtual bool hasAbsValue(const ValVar *var, const ICFGNode *node) const
Side-effect-free existence check.

◆ joinStates()

void SemiSparseAbstractInterpretation::joinStates ( AbstractState dst,
const AbstractState src 
)
overrideprotectedvirtual

Join src into dst with sparsity-aware semantics. Dense merges everything; semi-sparse skips ValVars.

Reimplemented from SVF::AbstractInterpretation.

Definition at line 667 of file SparseAbstractInterpretation.cpp.

669{
670 // ValVars live at def-sites in semi-sparse mode; they don't flow
671 // through state merges. Iterate src's ObjVar (_addrToAbsVal) entries
672 // directly and join into dst, leaving dst's ValVar map untouched.
673 // _freedAddrs (used by the null-deref detector) also rides along
674 // ICFG edges — there is no SVFG-level encoding of free events.
675 for (const auto& [id, val] : src.getLocToVal())
676 {
678 if (dst.getLocToVal().count(id))
679 dst.load(addr).join_with(val);
680 else
681 dst.store(addr, val);
682 }
683 for (NodeID a : src.getFreedAddrs())
684 dst.addToFreedAddrs(a);
685}
cJSON * a
Definition cJSON.cpp:2560
const AddrToAbsValMap & getLocToVal() const
get loc2val map
void store(u32_t addr, const AbstractValue &val)
virtual AbstractValue & load(u32_t addr)
void join_with(const AbstractValue &other)
u32_t NodeID
Definition GeneralType.h:56

◆ narrowCycleState()

bool SemiSparseAbstractInterpretation::narrowCycleState ( const AbstractState prev,
const AbstractState cur,
const ICFGCycleWTO cycle 
)
overrideprotectedvirtual

Narrow prev with cur; write the narrowed state back. Returns true when narrowing is disabled or the narrowed state equals prev. Semi-sparse subclass scatters the narrowed ValVars on non-fixpoint.

Reimplemented from SVF::AbstractInterpretation.

Definition at line 635 of file SparseAbstractInterpretation.cpp.

637{
638 // Delegate to base. It returns true on the two non-scatter cases
639 // (narrowing disabled, or narrow fixpoint); we preserve the original
640 // "skip scatter at fixpoint" semantics by bailing early here.
642 if (fixpoint)
643 return true;
644
645 // Non-fixpoint: base wrote the narrowed state to trace. Scatter the
646 // narrowed ValVars back to def-sites.
647 const ICFGNode* cycle_head = cycle->head()->getICFGNode();
649 for (const auto& [id, val] : next.getVarToVal())
651 return false;
652}
item next
Definition cJSON.cpp:2224
newitem prev
Definition cJSON.cpp:2285
virtual bool narrowCycleState(const AbstractState &prev, const AbstractState &cur, const ICFGCycleWTO *cycle)
const SVFVar * getSVFVar(NodeID varId) const
Retrieve SVFVar given its ID; asserts if no such variable exists.
void updateAbsValue(const ValVar *var, const AbstractValue &val, const ICFGNode *node) override

◆ updateAbsState()

void SemiSparseAbstractInterpretation::updateAbsState ( const ICFGNode node,
const AbstractState state 
)
overrideprotectedvirtual

Replace the state at node. Sparse subclasses replace only the ObjVar map (ValVars live at def-sites).

Reimplemented from SVF::AbstractInterpretation.

Definition at line 659 of file SparseAbstractInterpretation.cpp.

661{
662 // Only replace ObjVar state. ValVars live at their def-sites and
663 // must not be overwritten when the predecessor's state is merged in.
664 abstractTrace[node].updateAddrStateOnly(state);
665}

◆ updateAbsValue() [1/4]

void AbstractInterpretation::updateAbsValue ( const ObjVar var,
const AbstractValue val,
const ICFGNode node 
)
protectedvirtual

Reimplemented from SVF::AbstractInterpretation.

Definition at line 154 of file AbstractStateManager.cpp.

142{
145 as.store(addr, val);
146}

◆ updateAbsValue() [2/4]

void AbstractInterpretation::updateAbsValue ( const SVFVar var,
const AbstractValue val,
const ICFGNode node 
)
protectedvirtual

Reimplemented from SVF::AbstractInterpretation.

Definition at line 155 of file AbstractStateManager.cpp.

149{
150 if (const ObjVar* objVar = SVFUtil::dyn_cast<ObjVar>(var))
151 updateAbsValue(objVar, val, node);
152 else if (const ValVar* valVar = SVFUtil::dyn_cast<ValVar>(var))
153 updateAbsValue(valVar, val, node);
154 else
155 assert(false && "Unknown SVFVar kind");
156}

◆ updateAbsValue() [3/4]

void AbstractInterpretation::updateAbsValue ( const ValVar var,
const AbstractValue val,
const ICFGNode node 
)
protectedvirtual

Write a variable's abstract value. Sparse subclasses re-route ValVar writes to the def-site.

Reimplemented from SVF::AbstractInterpretation.

Definition at line 153 of file AbstractStateManager.cpp.

137{
138 abstractTrace[node][var->getId()] = val;
139}

◆ updateAbsValue() [4/4]

void SemiSparseAbstractInterpretation::updateAbsValue ( const ValVar var,
const AbstractValue val,
const ICFGNode node 
)
overrideprotectedvirtual

Write a variable's abstract value. Sparse subclasses re-route ValVar writes to the def-site.

Reimplemented from SVF::AbstractInterpretation.

Definition at line 710 of file SparseAbstractInterpretation.cpp.

713{
714 // Write to the var's def-site so getAbsValue stays consistent.
715 const ICFGNode* defNode = var->getICFGNode();
716 abstractTrace[defNode ? defNode : node][var->getId()] = val;
717}

◆ widenCycleState()

bool SemiSparseAbstractInterpretation::widenCycleState ( const AbstractState prev,
const AbstractState cur,
const ICFGCycleWTO cycle 
)
overrideprotectedvirtual

Widen prev with cur; write the widened state to trace[cycle_head]. Returns true when next == prev (fixpoint). Semi-sparse subclass additionally scatters ValVars to their def-sites.

Reimplemented from SVF::AbstractInterpretation.

Definition at line 617 of file SparseAbstractInterpretation.cpp.

619{
620 // Base widens, writes trace[cycle_head], and returns fixpoint bool.
622
623 // Scatter the widened ValVars back to their def-sites so body nodes
624 // observe the widened values on the next iteration. Matches the
625 // pre-refactor semantics: scatter unconditionally, including at
626 // widening fixpoint (see the narrowing-starts-with-stale-body issue
627 // fixed by always writing widened state back).
628 const ICFGNode* cycle_head = cycle->head()->getICFGNode();
630 for (const auto& [id, val] : next.getVarToVal())
632 return fixpoint;
633}
virtual bool widenCycleState(const AbstractState &prev, const AbstractState &cur, const ICFGCycleWTO *cycle)

The documentation for this class was generated from the following files: