Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
155 changes: 93 additions & 62 deletions svf/include/AE/Svfexe/AEDetector.h
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,27 @@ class AEDetector

/**
* @brief Pure virtual function for detecting issues within a node.
* @param as Reference to the abstract state.
* @param as Reference to the abstract state interface.
* @param node Pointer to the ICFG node.
* @note This is the legacy node-level detection method, kept for backward compatibility.
*/
virtual void detect(AbstractState& as, const ICFGNode* node) = 0;

/**
* @brief Check for issues in a single statement.
*
* This method is called during statement processing to detect issues
* in the same loop as state updates, eliminating redundant traversals.
* Subclasses should override this to implement statement-level detection.
*
* @param stmt Pointer to the SVF statement to check.
* @param as Reference to the abstract state interface.
*/
virtual void checkStatement(const SVFStmt* stmt, AbstractState& as)
{
// Default implementation does nothing - subclasses override as needed
}

/**
* @brief Pure virtual function for handling stub external API calls. (e.g. UNSAFE_BUFACCESS)
* @param call Pointer to the ext call ICFG node.
Expand Down Expand Up @@ -135,6 +151,7 @@ class AEException : public std::exception
class BufOverflowDetector : public AEDetector
{
friend class AbstractInterpretation;

public:
/**
* @brief Constructor initializes the detector kind to BUF_OVERFLOW and sets up external API buffer overflow rules.
Expand All @@ -160,71 +177,36 @@ class BufOverflowDetector : public AEDetector
return detector->getKind() == AEDetector::BUF_OVERFLOW;
}

/**
* @brief Updates the offset of a GEP object from its base.
* @param as Reference to the abstract state.
* @param gepAddrs Address value for GEP.
* @param objAddrs Address value for the object.
* @param offset The interval value of the offset.
*/
void updateGepObjOffsetFromBase(AbstractState& as,
AddressValue gepAddrs,
AddressValue objAddrs,
IntervalValue offset);

/**
* @brief Detect buffer overflow issues within a node.
* @param as Reference to the abstract state.
* @param as Reference to the abstract state interface.
* @param node Pointer to the ICFG node.
* @note This is the legacy node-level detection, kept for external API handling.
*/
void detect(AbstractState& as, const ICFGNode*);

void detect(AbstractState& as, const ICFGNode*) override;

/**
* @brief Handles external API calls related to buffer overflow detection.
* @param call Pointer to the call ICFG node.
* @brief Check for buffer overflow in a single statement.
*
* This method performs buffer overflow detection for a single GEP statement
* in the same loop as state updates, eliminating redundant traversals.
*
* @param stmt Pointer to the SVF statement to check.
* @param as Reference to the abstract state interface.
*/
void handleStubFunctions(const CallICFGNode*);
void checkStatement(const SVFStmt* stmt, AbstractState& as) override;

/**
* @brief Adds an offset to a GEP object.
* @param obj Pointer to the GEP object.
* @param offset The interval value of the offset.
* @brief Handles external API calls related to buffer overflow detection.
* @param call Pointer to the call ICFG node.
*/
void addToGepObjOffsetFromBase(const GepObjVar* obj, const IntervalValue& offset)
{
gepObjOffsetFromBase[obj] = offset;
}
void handleStubFunctions(const CallICFGNode*) override;

/**
* @brief Checks if a GEP object has an associated offset.
* @param obj Pointer to the GEP object.
* @return True if the GEP object has an offset, false otherwise.
*/
bool hasGepObjOffsetFromBase(const GepObjVar* obj) const
{
return gepObjOffsetFromBase.find(obj) != gepObjOffsetFromBase.end();
}

/**
* @brief Retrieves the offset of a GEP object from its base.
* @param obj Pointer to the GEP object.
* @return The interval value of the offset.
*/
IntervalValue getGepObjOffsetFromBase(const GepObjVar* obj) const
{
if (hasGepObjOffsetFromBase(obj))
return gepObjOffsetFromBase.at(obj);
else
{
assert(false && "GepObjVar not found in gepObjOffsetFromBase");
abort();
}
}

/**
* @brief Retrieves the access offset for a given object and GEP statement.
* @param as Reference to the abstract state.
* @param as Reference to the abstract state interface.
* @param objId The ID of the object.
* @param gep Pointer to the GEP statement.
* @return The interval value of the access offset.
Expand Down Expand Up @@ -268,7 +250,7 @@ class BufOverflowDetector : public AEDetector
/**
* @brief Reports all detected buffer overflow bugs.
*/
void reportBug()
void reportBug() override
{
if (!nodeToBugInfo.empty())
{
Expand All @@ -282,21 +264,69 @@ class BufOverflowDetector : public AEDetector
}
}

/**
* @brief Updates the offset of a GEP object from its base.
* @param as Reference to the abstract state interface.
* @param gepAddrs Address value for GEP.
* @param objAddrs Address value for the object.
* @param offset The interval value of the offset.
*/
void updateGepObjOffsetFromBase(AbstractState& as,
AddressValue gepAddrs,
AddressValue objAddrs,
IntervalValue offset);

/**
* @brief Adds an offset to a GEP object.
* @param obj Pointer to the GEP object.
* @param offset The interval value of the offset.
*/
void addToGepObjOffsetFromBase(const GepObjVar* obj, const IntervalValue& offset)
{
gepObjOffsetFromBase[obj] = offset;
}

/**
* @brief Checks if a GEP object has an associated offset.
* @param obj Pointer to the GEP object.
* @return True if the GEP object has an offset, false otherwise.
*/
bool hasGepObjOffsetFromBase(const GepObjVar* obj) const
{
return gepObjOffsetFromBase.find(obj) != gepObjOffsetFromBase.end();
}

/**
* @brief Retrieves the offset of a GEP object from its base.
* @param obj Pointer to the GEP object.
* @return The interval value of the offset.
*/
IntervalValue getGepObjOffsetFromBase(const GepObjVar* obj) const
{
if (hasGepObjOffsetFromBase(obj))
return gepObjOffsetFromBase.at(obj);
else
{
assert(false && "GepObjVar not found in gepObjOffsetFromBase");
abort();
}
}

/**
* @brief Initializes external API buffer overflow check rules.
*/
void initExtAPIBufOverflowCheckRules();

/**
* @brief Handles external API calls related to buffer overflow detection.
* @param as Reference to the abstract state.
* @param as Reference to the abstract state interface.
* @param call Pointer to the call ICFG node.
*/
void detectExtAPI(AbstractState& as, const CallICFGNode *call);

/**
* @brief Checks if memory can be safely accessed.
* @param as Reference to the abstract state.
* @param as Reference to the abstract state interface.
* @param value Pointer to the SVF var.
* @param len The interval value representing the length of the memory access.
* @return True if the memory access is safe, false otherwise.
Expand All @@ -306,27 +336,28 @@ class BufOverflowDetector : public AEDetector
private:
/**
* @brief Detects buffer overflow in 'strcat' function calls.
* @param as Reference to the abstract state.
* @param as Reference to the abstract state interface.
* @param call Pointer to the call ICFG node.
* @return True if a buffer overflow is detected, false otherwise.
*/
bool detectStrcat(AbstractState& as, const CallICFGNode *call);

/**
* @brief Detects buffer overflow in 'strcpy' function calls.
* @param as Reference to the abstract state.
* @param as Reference to the abstract state interface.
* @param call Pointer to the call ICFG node.
* @return True if a buffer overflow is detected, false otherwise.
*/
bool detectStrcpy(AbstractState& as, const CallICFGNode *call);

private:
Map<const GepObjVar*, IntervalValue> gepObjOffsetFromBase; ///< Maps GEP objects to their offsets from the base.
Map<const GepObjVar*, IntervalValue> gepObjOffsetFromBase; ///< Maps GEP objects to their offsets from their base.
Map<std::string, std::vector<std::pair<u32_t, u32_t>>> extAPIBufOverflowCheckRules; ///< Rules for checking buffer overflows in external APIs.
Set<std::string> bugLoc; ///< Set of locations where bugs have been reported.
SVFBugReport recoder; ///< Recorder for abstract execution bugs.
Map<const ICFGNode*, std::string> nodeToBugInfo; ///< Maps ICFG nodes to bug information.
};

class NullptrDerefDetector : public AEDetector
{
friend class AbstractInterpretation;
Expand All @@ -345,16 +376,16 @@ class NullptrDerefDetector : public AEDetector

/**
* @brief Detects nullptr dereferences issues within a node.
* @param as Reference to the abstract state.
* @param as Reference to the abstract state interface.
* @param node Pointer to the ICFG node.
*/
void detect(AbstractState& as, const ICFGNode* node);
void detect(AbstractState& as, const ICFGNode* node) override;

/**
* @brief Handles external API calls related to nullptr dereferences.
* @param call Pointer to the call ICFG node.
*/
void handleStubFunctions(const CallICFGNode* call);
void handleStubFunctions(const CallICFGNode* call) override;

/**
* @brief Checks if an Abstract Value is uninitialized.
Expand Down Expand Up @@ -401,7 +432,7 @@ class NullptrDerefDetector : public AEDetector
/**
* @brief Reports all detected nullptr dereference bugs.
*/
void reportBug()
void reportBug() override
{
if (!nodeToBugInfo.empty())
{
Expand All @@ -417,7 +448,7 @@ class NullptrDerefDetector : public AEDetector

/**
* @brief Handle external API calls related to nullptr dereferences.
* @param as Reference to the abstract state.
* @param as Reference to the abstract state interface.
* @param call Pointer to the call ICFG node.
*/
void detectExtAPI(AbstractState& as, const CallICFGNode* call);
Expand Down
23 changes: 23 additions & 0 deletions svf/include/AE/Svfexe/AbstractInterpretation.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,9 @@
#include "AE/Svfexe/AbsExtAPI.h"
#include "Util/SVFBugReport.h"
#include "Util/SVFStat.h"
#include "Util/Options.h"
#include "Graphs/SCC.h"
#include <memory>

namespace SVF
{
Expand Down Expand Up @@ -176,6 +178,27 @@ class AbstractInterpretation
}
}

/*
* @brief Retrieves the abstract value from the trace for a given ICFG node and variable ID.
* @param node Pointer to the ICFG node.
* @param varId ID of the variable.
* @return Abstract value.
* @throws Assertion if no trace exists for the node.
*/
AbstractValue getAbstractValueFromTrace(const ICFGNode* node, NodeID varId)
{
if (abstractTrace.count(node) == 0)
{
assert(false && "No preAbsTrace for this node");
abort();
}
else
{
//TODO: support sparse abstract state
return abstractTrace[node][varId];
}
}

private:
/// Global ICFGNode is handled at the entry of the program,
virtual void handleGlobalNode();
Expand Down
2 changes: 2 additions & 0 deletions svf/include/Util/Options.h
Original file line number Diff line number Diff line change
Expand Up @@ -243,6 +243,8 @@ class Options
static const Option<u32_t> WidenDelay;
/// recursion handling mode, Default: TOP
static const OptionMap<u32_t> HandleRecur;
/// Use sparse abstract state representation (TODO: to implement)
//static const Option<bool> UseSparseState;
/// the max time consumptions (seconds). Default: 4 hours 14400s
static const Option<u32_t> Timeout;
/// bug info output file, Default: output.db
Expand Down
Loading
Loading