AE CPP APIs - SVF-tools/Software-Security-Analysis GitHub Wiki
| API | Introduction |
|---|---|
getNodeID("variable") |
Retrieves the node ID of the specified variable. |
IntervalValue(lower, upper) |
Creates an interval value. |
AbstractValue::getInterval() |
Retrieves the interval value of the abstract state. |
AbstractValue::join_with(value) |
Merges the current value with another value. |
getMemObjAddress("variable") |
Retrieves the memory object address of the specified variable. |
AddressValue(getMemObjAddress("variable")) |
Creates an address value initialized to the memory object address of the specified variable. |
AEState::widening(state) |
Performs widening on the given state. |
AEState::narrowing(state) |
Performs narrowing on the given state. |
AEState::joinWith(state) |
Merges the current state with another state. |
AbstractValue::meet_with(value) |
Performs an intersection operation between the current value and another value. |
getGepObjAddress("variable", offset) |
Retrieves the GEP (GetElementPtr) object address of the specified variable with the given offset. |
AEState::loadValue(varId) |
Loads the abstract value from the variable ID's address. |
AEState::storeValue(varId, val) |
Stores the abstract value at the variable ID's address. |
AEState::printAbstractState() |
Prints the abstract trace for debugging purposes. |
-
Perform widening on the current state with another state.
For example,
void exampleWidening() { AEState as1, as2; NodeID a = getNodeID("a"); as1[a] = IntervalValue(1, 5); // as1: a in [1, 5] as2[a] = IntervalValue(3, 10); // as2: a in [3, 10] AEState widenedState = as1.widening(as2); // widenedState: a in [1, +inf] }
Input:
state(an AEState)Output: Widened state (an AEState)
-
Load and store values associated with a variable ID.
For example,
void exampleLoadValue() { AEState as; NodeID a = getNodeID("a"); NodeID p = getNodeID("p"); NodeID malloc = getNodeID("malloc"); as[p] = AddressValue(getMemObjAddress("malloc")); as.storeValue(p, IntervalValue(42, 42)); // Store 42 at address p AbstractValue loadedValue = as.loadValue(p); std::cout << loadedValue.toString() << std::endl; }
Input:
varId(a NodeID),val(an AbstractValue)Output: Loaded value (an AbstractValue, can be Interval Value or Address Value)
-
Print the abstract trace for debugging purposes.
For example,
void examplePrintAbstractState() { AEState as; NodeID a = getNodeID("a"); NodeID b = getNodeID("b"); as[a] = IntervalValue(1, 5); // a in [1, 5] as[b] = IntervalValue(3, 7); // b in [3, 7] as.printAbstractState(); // Print the abstract trace for debugging }
Input: None
Output: None (prints the abstract trace)
-----------Var and Value-----------
Var2(b) : Value: [3, 7]
Var1(a) : Value: [1, 5]
-----------------------------------------
Naming note. SVF master no longer exposes a separate
AbstractStateManager/AEStateclass. The dense per-ICFGNodetrace and the GEP / load / store / pointer helpers now live onSVF::AbstractInterpretationand are forwarded through methods on Assignment-3'sAbstractExecution(its base class — call them as bare methods, e.g.getGepByteOffset(gep)orloadValue(ptr, node)). The per-nodeSVF::AbstractStatevalue object is still returned bygetAbsStateFromTrace(node)and is what you callwidening/narrowing/joinWith/meetWithon.
The tables below list the SVF C++ APIs the Assignment-3 solution actually
calls. They are grouped by what they operate on (statements, abstract
state, IR queries, harness facade) so you can scan them in the order you
will use them while writing Assignment_3.cpp.
| API | Introduction |
|---|---|
SVFUtil::isa<T>(node) / SVFUtil::dyn_cast<T>(stmt)
|
Type-test / downcast for SVFStmt and ICFGNode subtypes. |
stmt->getICFGNode() |
Containing ICFG node of a statement (use to look up the abstract state with getAbsStateFromTrace). |
AssignStmt::getLHSVar() / getRHSVar()
|
LHS / RHS SVFVar* of CopyStmt, LoadStmt, StoreStmt, GepStmt, PhiStmt, SelectStmt. |
AssignStmt::getLHSVarID() / getRHSVarID()
|
NodeID for the same operands; compare with IRGraph::NullPtr to detect null-pointer operands. |
BinaryOPStmt::getOpcode() |
Returns the opcode (compare against BinaryOPStmt::Add / Sub / Mul / UDiv / SDiv / URem / SRem / And / Or / Xor / Shl / LShr / AShr / ...). |
BinaryOPStmt::getOpVarID(index) / getResID()
|
Operand and result NodeIDs for binary operations. |
CmpStmt::getOpVarID(index) / getResID() / getPredicate()
|
Operands, result, and predicate enum (CmpStmt::ICMP_EQ / ICMP_NE / ICMP_SLT / ...). |
SelectStmt::getTrueValue() / getFalseValue() / getCondition()
|
Operands of a select instruction. |
PhiStmt::getOpVarNum() / getOpVar(index) / getOpICFGNode(index)
|
Number of incoming values, the value at index, and the predecessor ICFG node it came from. |
CallPE::getResID() / getOpVarNum() / getOpVarID(index) / getOpCallICFGNode(index)
|
CallPE is phi-like — the result is the formal parameter, each operand pairs an actual parameter with its call site. |
RetPE::getLHSVarID() / getRHSVarID()
|
Caller-side LHS and callee-side return-value variables for a return-edge statement. |
AddrStmt::getLHSVarID() / getRHSVarID()
|
LHS / RHS of an addr (alloca / global) statement. |
GepStmt::isConstantOffset() / accumulateConstantByteOffset()
|
Quickly classify and read constant byte offsets when the GEP is constant. |
CallICFGNode::getCalledFunction() / getCaller() / getArgument(i) / arg_size() / getRetICFGNode()
|
Static callee, caller FunObjVar*, ith argument ValVar*, argument count, matching return ICFG node. |
RetICFGNode::getActualRet() |
The actual-return SVFVar* used to write nondeterministic return values to TOP. |
IntraCFGEdge::getCondition() / getSuccessorCondValue()
|
Branch condition and successor value used by mergeStatesFromPredecessors to filter infeasible edges. |
ICFGNode::getInEdges() / getOutEdges() / getSVFStmts() / getId() / getFun() / toString()
|
ICFG node iteration. |
ICFG::getGlobalICFGNode() / getFunEntryICFGNode(fun)
|
Get the global initialisation node, or a function's entry node. |
SVFIR::getBaseObject(id) / getGNode(id) / getFunObjVar(name)
|
Resolve NodeID → base object, NodeID → SVFVar*, function name → FunObjVar*. |
BaseObjVar::isConstantByteSize() / getByteSizeOfObj() / isBlackHoleObj()
|
Object metadata used by the buffer-overflow ground-truth and the checker. |
GepObjVar::getConstantFieldIdx() |
Accumulated byte offset of a derived GEP object from its base. |
IRGraph::NullPtr |
The dedicated null-pointer node — compare a NodeID against this to detect null operands. |
| API | Introduction |
|---|---|
IntervalValue(lower, upper) / IntervalValue::top()
|
Construct an interval / get the universal interval. |
IntervalValue::lb() / ub() / is_numeral() / is_zero() / is_infinite() / isBottom() / equals(other)
|
Bounds queries used by the transfer functions and the branch refinement. |
IntervalValue::getIntNumeral() / BoundedInt::getIntNumeral()
|
Concrete integer when the interval is a single value (or when reading a bound). |
AbstractValue::getInterval() / getAddrs() / isInterval() / isAddr()
|
Project an AbstractValue to its interval or address-set view. |
AbstractValue::join_with(other) / meet_with(other) / equals(other)
|
Lattice operations on AbstractValue. |
AddressValue |
Set-of-addresses value; iterate with a range-for to walk each addr. |
AbstractState::widening(other) / narrowing(other) / joinWith(other) / meetWith(other)
|
Lattice operations on the per-node state used by handleICFGCycle. |
AbstractState::isBlackHoleObjAddr(addr) / isNullMem(addr) / isFreedMem(addr)
|
Filter sentinel / null / freed addresses out of AddressValue iteration. |
AbstractState::getIDFromAddr(addr) |
Recover the base-object NodeID from a virtual address (low bits of 0x7f******). |
AbstractState::inVarToValTable(id) / inVarToAddrsTable(id)
|
Whether the state already records a value / address-set for id (use before reading as[id] to avoid creating default entries). |
as[id] |
Read / write the AbstractValue for NodeID id in an AbstractState&. |
AbstractState::printAbstractState() |
Debug-print the entire state. |
Options::WidenDelay() |
Read the configurable widening delay (number of iterations before widening kicks in). |
| API | Introduction |
|---|---|
getAbsStateFromTrace(node) |
Returns the AbstractState& for the ICFG node (lives inside the underlying AbstractInterpretation's trace). |
postAbsTrace() |
Returns the Map<const ICFGNode*, AbstractState>& keyed by ICFG node — use this when you need to read a previously-computed post-state of a different node (e.g. a CallPE reading from its call site). |
getAbsValue(var, node) (overloaded for ValVar*, ObjVar*, SVFVar*) |
Read the AbstractValue of var at node. |
updateAbsValue(var, val, node) |
Write val for var at node. |
loadValue(pointer, node) |
Load through pointer (ValVar*) — replaces the old AEState::loadValue(varId). |
storeValue(pointer, val, node) |
Store val through pointer — replaces the old AEState::storeValue(varId, val). |
getGepObjAddrs(pointer, offset) |
Resolve a ValVar* + IntervalValue offset into the set of derived GEP-object addresses. |
getGepElementIndex(gep) / getGepByteOffset(gep)
|
Element-index / byte-offset of a GepStmt (use the byte version for buffer-bound math). |
getAllocaInstByteSize(addr) |
Byte size of the object created by an AddrStmt (alloca). |
reportBufOverflow(node) / reportNullDeref(node)
|
Record a bug at node; the harness deduplicates by location and kind. |
| API | Introduction |
|---|---|
handleGlobalNode() |
Replay the SVFModule's global ICFG node so global state is initialised before main is entered. |
handleFunction(funEntry) |
Iterate one function's interprocedural WTO; dispatch singletons to handleICFGNode and cycles to handleICFGCycle. |
handleICFGNode(node) |
Merge predecessor states, run the per-statement transfer functions, dispatch call sites via handleCallSite, run the bug checkers; return whether the post-state changed. |
handleICFGCycle(cycle) |
Drive a WTO cycle (loop head or recursive-function entry) to a fixpoint with widening / narrowing. |
handleCallSite(callNode) |
Dispatch a call ICFG node; the harness expects you to forward stub/checkpoint calls to handleStubFunctions / handleCheckpointStubs, model external APIs via updateStateOnExtCall, and inline non-extern callees with the ander->inSameCallGraphSCC recursion skip. |
handleStubFunctions(call) / handleCheckpointStubs(call)
|
Sub-dispatchers for svf_assert / svf_assert_eq and the SAFE_* / UNSAFE_* ground-truth checkpoints (defined in AEHelper.cpp — call them from your handleCallSite). |
isExternalCallForAssignment(func) |
Whether func belongs to the assignment's external-API whitelist (the memory / string family plus mem_insert / str_insert). |
ander->inSameCallGraphSCC(caller, callee) |
Andersen-based SCC check used to skip recursive callsites (the outer WTO cycle drives the recursion). |
getReporter() |
Access the AEReporter instance for advanced bug-reporting needs. |
CallPE joins all of a function's actual parameters at the entry. The result variable is the formal parameter; each operand pairs an actual parameter with its call site.
void AbstractExecution::updateStateOnCall(const CallPE* callPE) {
AbstractState& as = getAbsStateFromTrace(callPE->getICFGNode());
NodeID formal = callPE->getResID();
AbstractValue joined;
for (u32_t i = 0; i < callPE->getOpVarNum(); ++i) {
const ICFGNode* callSite = callPE->getOpCallICFGNode(i);
NodeID actual = callPE->getOpVarID(i);
if (postAbsTrace().count(callSite))
joined.join_with(postAbsTrace()[callSite][actual]);
}
as[formal] = joined;
}AbstractState& as = getAbsStateFromTrace(node); // per-node value object
auto& post = postAbsTrace(); // Map<ICFGNode*, AbstractState>
if (post.count(prevNode))
val.join_with(post[prevNode][someVarId]);AbstractState is a value object (call widening / narrowing / joinWith / meetWith / printAbstractState() on it); postAbsTrace() lets you read another node's post-state by ICFG-node key.
void AbstractExecution::updateStateOnLoad(const LoadStmt* load) {
const ICFGNode* node = load->getICFGNode();
AbstractState& as = getAbsStateFromTrace(node);
as[load->getLHSVarID()] =
this->loadValue(SVFUtil::cast<ValVar>(load->getRHSVar()), node);
}
void AbstractExecution::updateStateOnStore(const StoreStmt* store) {
const ICFGNode* node = store->getICFGNode();
AbstractState& as = getAbsStateFromTrace(node);
AbstractValue val = (store->getRHSVarID() == IRGraph::NullPtr)
? AbstractValue(AddressValue(AbstractState::nullMem()))
: as[store->getRHSVarID()];
this->storeValue(SVFUtil::cast<ValVar>(store->getLHSVar()), val, node);
}void AbstractExecution::updateStateOnGep(const GepStmt* gep) {
const ICFGNode* node = gep->getICFGNode();
AbstractState& as = getAbsStateFromTrace(node);
IntervalValue offset = this->getGepElementIndex(gep);
AddressValue gepAddrs =
this->getGepObjAddrs(SVFUtil::cast<ValVar>(gep->getRHSVar()), offset);
as[gep->getLHSVarID()] = AbstractValue(gepAddrs);
}-
getGepElementIndex(gep)andgetGepByteOffset(gep)returnIntervalValues (element-index vs byte-offset views of the same GEP). -
getGepObjAddrs(pointer, offset)resolves the derived address set; iterate the result and callgetIDFromAddrto walk each base object.
for (const auto& addr : ptrVal.getAddrs()) {
if (AbstractState::isBlackHoleObjAddr(addr) || AbstractState::isNullMem(addr))
continue;
NodeID objId = as.getIDFromAddr(addr);
const BaseObjVar* baseObj = svfir->getBaseObject(objId);
if (!baseObj || !baseObj->isConstantByteSize())
continue;
u32_t size = baseObj->getByteSizeOfObj();
IntervalValue baseOffset(0);
if (auto* gepObj = SVFUtil::dyn_cast<GepObjVar>(svfir->getGNode(objId)))
baseOffset = IntervalValue((s64_t)gepObj->getConstantFieldIdx());
// ... compare baseOffset + accessOffset against size
}The harness's handleCallSite is the entry point for every CallICFGNode. The supplied dispatch table in Assignment_3.cpp recommends:
-
svf_assert/svf_assert_eq→handleStubFunctions(call) -
SAFE_BUFACCESS/UNSAFE_BUFACCESS/SAFE_PTRDEREF/UNSAFE_PTRDEREF→handleCheckpointStubs(call) -
nd/rand→ writeIntervalValue::top()to the actual-return variable onpostAbsTrace()[callNode]. -
SVFUtil::isExtCall(callee)→updateStateOnExtCall(callNode)then run the bug checkers on the call's pointer / length arguments. - Otherwise → skip if
ander->inSameCallGraphSCC(caller, callee), otherwisehandleFunction(svfir->getICFG()->getFunEntryICFGNode(callee))and forwardpostAbsTrace()[callNode]tocallNode->getRetICFGNode().
Recover the internal object ID from a 0x7f****** virtual address.
AbstractState& as = getAbsStateFromTrace(node);
int internalID = as.getIDFromAddr(addr); // strips the 0x7f000000 maskAbstractState& as = getAbsStateFromTrace(icfgNode);
as.printAbstractState();-----------Var and Value-----------
Var4 Value: [5, 5]
Var2 Value: [5, 5]
Var1 Value: {0x7f000005}
0x7f000005 Value: [5, 5]
———————————————————————————————————