AE CPP APIs - SVF-tools/Software-Security-Analysis GitHub Wiki

Essential API Documentation for Labs and Assignments

Lab-Exercise-3

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.

AEState::widening(state)

  • 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)


AEState::loadValue(varId) and AEState::storeValue(varId, val)

  • 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)


AEState::printAbstractState()

  • 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]
-----------------------------------------

Assignment-3

Note on naming: SVF master no longer has a separate AbstractStateManager / AEState class. The dense per-ICFGNode trace and the GEP / load / store / pointer helpers now live on SVF::AbstractInterpretation. Assignment-3's AbstractExecution holds a pointer to that instance under the field name svfStateMgr (see Assignment_3.h), so the wiki uses svfStateMgr->... below where the old wiki said AEState::.... The per-node SVF::AbstractState value object is still returned by getAbsStateFromTrace(node) and is what you call widening / narrowing / joinWith on.

API Introduction
SVFUtil::isa<CallICFGNode>(stmt->getICFGNode()) Checks if the statement's containing ICFG node is a call node.
SVFUtil::dyn_cast<GepStmt>(stmt) Dynamically casts the given statement to a GepStmt type.
AbstractExecution::getAbsStateFromTrace(node) Retrieves the abstract state of the given ICFG node from the trace (returns an AbstractState&).
GepStmt::getLHSVarID() Retrieves the left-hand side variable ID of the GepStmt (inherited from AssignStmt).
GepStmt::getRHSVarID() Retrieves the right-hand side variable ID of the GepStmt (inherited from AssignStmt).
as[id].getAddrs() Retrieves the AddressValue of variable id from an AbstractState as (as[id] returns an AbstractValue, on which getAddrs() lives).
as.getIDFromAddr(addr) Retrieves the internal ID of the given virtual address (method on AbstractState).
svfir->getBaseObject(id)->getByteSizeOfObj() Retrieves the byte size of the base object.
Options::WidenDelay() Retrieves the value of the widen delay option.
as.widening(other) Performs widening on the current AbstractState with another AbstractState.
as.narrowing(other) Performs narrowing on the current AbstractState with another AbstractState.
as.joinWith(other) / as.meetWith(other) Join / meet the current AbstractState with another (in-place).
AbstractExecution::handleICFGNode(ICFGNode*) Handles a singleton WTO (Weak Topological Order) which includes an ICFGNode (defined in Assignment-3's AbstractExecution).
AbstractExecution::handleICFGCycle(ICFGCycleWTO*) Handles WTO cycles, which includes a set of ICFGNodes.
ICFGCycleWTO::head()->getICFGNode() Get the cycle head ICFGNode.
AbstractExecution::mergeStatesFromPredecessors(node, as) Merges states from predecessor ICFGNodes into as (defined on Assignment-3's AbstractExecution).
CopyStmt::getLHSVarID() Retrieves the left-hand side variable ID of the copy statement.
CopyStmt::getRHSVarID() Retrieves the right-hand side variable ID of the copy statement.
BinaryOPStmt::getOpVarID(index) Retrieves the operand variable ID of the binary operation statement.
BinaryOPStmt::getResID() Retrieves the result variable ID of the binary operation statement.
BinaryOPStmt::getOpcode() Retrieves the opcode of the binary operation statement.
CallPE::getResID() Retrieves the formal-parameter variable ID for a phi-like call parameter statement.
CallPE::getOpVarNum() Retrieves the number of actual-parameter operands in a phi-like CallPE.
CallPE::getOpVarID(index) Retrieves the actual-parameter variable ID at index.
CallPE::getOpCallICFGNode(index) Retrieves the call site corresponding to the actual-parameter operand at index.
svfStateMgr->loadValue(pointer, node) Loads the abstract value pointed to by pointer (a ValVar*) at node. Returns an AbstractValue. Replaces the old AEState::loadValue(varId).
svfStateMgr->storeValue(pointer, val, node) Stores val (an AbstractValue) through the pointer at node. Replaces the old AEState::storeValue(varId, val).
LoadStmt::getRHSVarID() Retrieves the right-hand side variable ID of the load statement.
LoadStmt::getLHSVarID() Retrieves the left-hand side variable ID of the load statement.
IntervalValue::getIntNumeral() Returns the integer representation of the interval value.
svfStateMgr->getGepByteOffset(gep) Retrieves the byte offset of the GEP statement. Returns an IntervalValue. Replaces the old AEState::getByteOffset(gep).
svfStateMgr->getGepElementIndex(gep) Retrieves the element index of the GEP statement. Replaces the old AEState::getElementIndex(gep).
svfStateMgr->getGepObjAddrs(pointer, offset) Retrieves the addresses of GEP objects (pointer is a ValVar*, offset is an IntervalValue). Replaces the old AEState::getGepObjAddrs(varID, offset).
AbstractExecution::reportBufOverflow(node) Reports a buffer overflow for a given ICFG node (Assignment-3 only).
AbstractExecution::updateGepObjOffsetFromBase(as, gepAddrs, objAddrs, offset) Updates the GEP object offset from the base on AbstractState as.
AbstractExecution::getAccessOffset(objId, gep) Returns the accessing offset of an object at a GepStmt.
AbstractExecution::updateStateOnExtCall(extCallNode) Handles external calls, checking for buffer overflows, and updates abstract states using memcpy-like APIs via AbsExtAPI::handleMemcpy.
utils->handleMemcpy(dst, src, len, start_idx, extCallNode) Simulates a memcpy operation: copies len bytes from the source variable src (a ValVar*) to the destination variable dst (a ValVar*), starting at offset start_idx, at the CallICFGNode extCallNode. The function automatically determines the element size (for arrays or pointers) and performs element-wise copying, updating the abstract state accordingly. Only objects present in the abstract state are copied. (utils is the AbsExtAPI* member of AbstractExecution.)
utils->getStrlen(strValue, extCallNode) Computes a null-terminated string length from the abstract state managed by svfStateMgr.
bufOverflowHelper.addToGepObjOffsetFromBase(gepObjVar, offset) Adds an offset to the GEP object offset from the base object (on Assignment-3's AbstractExecutionHelper).
bufOverflowHelper.hasGepObjOffsetFromBase(gepObjVar) Checks if there is a GEP object offset from the base object.
bufOverflowHelper.getGepObjOffsetFromBase(gepObjVar) Retrieves the GEP object offset from the base object.
as.printAbstractState() Prints the abstract state of the execution (method on AbstractState).

CallPE::getResID / getOpVarID / getOpCallICFGNode

  • CallPE is phi-like in current SVF: the result is the formal parameter, and each operand is one actual parameter from a specific call site.

    For example,

    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::getIDFromAddr(addr)

  • Retrieve the internal ID associated with a given virtual address.

    For example,

    // Assuming 'addr' is a valid virtual address (0x7f******)
    AbstractState& as = getAbsStateFromTrace(node);
    int internalID = as.getIDFromAddr(addr);
    std::cout << "Internal ID: " << internalID << std::endl;

    Input: addr (an address object starting with 0x7f****), e.g. 0x7f0005

    Output: Internal ID associated with addr (remove the mask of 0x7f0000), e.g. 5 (0x7f0005 remove the mask)


bufOverflowHelper.addToGepObjOffsetFromBase(objVar, offset)

  • Add an offset to the GEP object offset from the base object.

    For example,

    // Assuming 'GepObjVar' is a valid Gep object variable and 'offset' is an integer
    bufOverflowHelper.addToGepObjOffsetFromBase(gepObjVar, offset);

    Input: gepObjVar (a gep object variable), offset (an Interval Value)

    Output: None (operation performed)


bufOverflowHelper.hasGepObjOffsetFromBase(objVar)

  • Check if there is a GEP object offset from the base object.

    For example,

    // Assuming 'objVar' is a valid object variable
    bool hasOffset = bufOverflowHelper.hasGepObjOffsetFromBase(gepObjVar);

    Input: gepObjVar (a gep object variable)

    Output: Boolean indicating if there is a GEP object offset from the base


bufOverflowHelper.getGepObjOffsetFromBase(objVar)

  • Retrieve the GEP object offset from the base object.

    For example,

    // Assuming 'objVar' is a valid object variable
    IntervalValue accessOffset = _bufOverflowHelper.getGepObjOffsetFromBase(objVar);
    std::cout << "GEP object offset from base: " << accessOffset.toString() << std::endl;

    Input: gepObjVar (a gep object variable)

    Output: Interval value representing the GEP object offset from the base


svfir->getBaseObject(id)->getByteSizeOfObj()

  • Get the byte size of a base object given its ID.

    For example,

    // Assuming 'id' is a valid object ID
    u32_t byteSize = svfir->getBaseObject(id)->getByteSizeOfObj();
    std::cout << "Byte size of base object: " << byteSize << std::endl;

    Input: id (an object ID, either GepObj or BaseObj)

    Output: Unsigned integer representing the byte size of the base object


AbstractInterpretation::getGepByteOffset(gep)

  • Retrieve the byte offset (has lower and upper bound) for a given GEP statement. Note: this method now lives on AbstractInterpretation (accessed via svfStateMgr->... in Assignment-3), not on AbstractState — the old AEState::getByteOffset / AbstractStateManager API was removed when the dense AbstractInterpretation was folded in.

    For example,

    // Assuming 'gep' is a valid GepStmt*
    IntervalValue byteOffset = svfStateMgr->getGepByteOffset(gep);
    std::cout << "Byte offset: " << byteOffset.toString() << std::endl;

    Input: gep (a GepStmt*)

    Output: IntervalValue representing the byte offset


AbstractInterpretation::getGepObjAddrs(pointer, offset)

  • Get the addresses of GEP objects given a ValVar* pointer and an offset.

    For example,

    // Assuming 'pointer' is a ValVar* and 'offset' is an IntervalValue
    AddressValue gepObjAddrs = svfStateMgr->getGepObjAddrs(pointer, offset);
    std::cout << "GEP object addresses: ";
    for (const auto& addr : gepObjAddrs) {
        std::cout << "0x" << std::hex << addr << ", ";
    }
    std::cout << std::endl;

    Input: pointer (a ValVar*), offset (an IntervalValue)

    Output: AddressValue containing the addresses of GEP objects


AbstractExecution::updateGepObjOffsetFromBase(gepAddrs, objAddrs, offset)

  • Update the GEP object offset from the base object.

    For example,

    // Assuming 'gepAddrs' and 'objAddrs' are valid address lists and 'offset' is an integer
    AbstractExecution::updateGepObjOffsetFromBase(gepAddrs, objAddrs, offset);

    Input: gepAddrs (list of GEP addresses), objAddrs (list of object addresses), offset (an IntervalValue)

    Output: None (operation performed). For example, for $gepObj = getelementptr $obj, 20. gepAddrs is the addresses of $gepObj, objAddrsis the addresses of $obj, 20 is the offset (if it is concrete value, the lower bound and the upper bound are both equal to 20.)


AbstractExecution::getAccessOffset(objId, gep)

  • Retrieve the access offset for a given object ID and GEP instruction.

    For example,

    // Assuming 'objId' is a valid object ID and 'gep' is a valid GEP instruction
    IntervalValue accessOffset = AbstractExecution::getAccessOffset(objId, gep);
    std::cout << "Access offset: " << accessOffset.toString() << std::endl;

    Input: objId (an object ID), gep (a GEP instruction)

    Output: IntervalValue representing the access offset


AbsExtAPI::handleMemcpy(dst, src, len, start_idx, extCallNode)

  • Simulates a memcpy operation against the abstract state held by the owning AbstractInterpretation: copies len bytes from the source variable src to the destination variable dst, starting at offset start_idx. The function automatically determines the element size (for arrays or pointers) and performs element-wise copying, updating the abstract state accordingly. Only objects present in the abstract state are copied. The current AbstractState is no longer passed in explicitly — handleMemcpy reads/writes it via the owning AbstractInterpretation using extCallNode.

    For example

    // dst is a ValVar*, whose underlying type can be Array or Pointer.
    // src is a ValVar*, whose underlying type can be Array or Pointer.
    // len is an IntervalValue; we copy the lower bound bytes.
    // start_idx is the starting position.
    // extCallNode is the CallICFGNode at which the external memcpy-like call occurs.
    // e.g. in source code,  char dst[10] = {'a','a','a','a','a','a','a','a','a','a'};
    //                       char src[5] = {'1', '2', '3', '4', '\0'};
    // we call handleMemcpy(dst, src, [5, 5], 2, extCallNode);
    // AbstractState should be updated as `dst = {'a', 'a', '1', '2', '3', '4','\0', 'a','a','a'}`
    // in which dst[2] = '1', dst[3] = '2', dst[4] = '3', dst[5] = '4', dst[6] = '\0', and no change occurs in other indices.
    
    utils->handleMemcpy(SVFUtil::cast<ValVar>(dst),
                        SVFUtil::cast<ValVar>(src),
                        len, start_idx, extCallNode);
    

AbsExtAPI::getStrlen(strValue, extCallNode)

  • Computes the length of a null-terminated string starting at strValue using the abstract state associated with extCallNode.

    For example,

    IntervalValue len =
        utils->getStrlen(SVFUtil::cast<ValVar>(extCallNode->getArgument(1)),
                         extCallNode);

    Input: strValue (a ValVar*), extCallNode (the call ICFG node)

    Output: IntervalValue representing the string length


AbstractState::printAbstractState()

  • Print the abstract state at an ICFG node.

    For example,

    AbstractState& as = getAbsStateFromTrace(icfgNode);
    as.printAbstractState();

    Input: None

    Output: Prints the abstract state to the standard output, e.g.

-----------Var and Value-----------
Var4                 Value: [5, 5]
Var2                 Value: [5, 5]
Var1                 Value: {0x7f000005}
0x7f000005           Value: [5, 5]
——————————————---------------------

⚠️ **GitHub.com Fallback** ⚠️