From 42e07eb51a427c9ab9e495cf0bdc1ed91817b8fb Mon Sep 17 00:00:00 2001 From: bjjwwang Date: Sun, 18 Jan 2026 21:11:59 +1100 Subject: [PATCH 1/9] refactor AE --- svf/include/AE/Core/AbstractState.h | 75 +++++---- svf/include/AE/Core/AbstractValue.h | 6 +- svf/include/AE/Core/IAbstractState.h | 152 ++++++++++++++++++ svf/include/AE/Svfexe/AEDetector.h | 51 +++--- .../AE/Svfexe/AbstractInterpretation.h | 30 +++- svf/include/Util/Options.h | 2 + svf/lib/AE/Core/AbstractState.cpp | 49 ++++-- svf/lib/AE/Svfexe/AEDetector.cpp | 41 ++--- svf/lib/AE/Svfexe/AbstractInterpretation.cpp | 38 ++--- svf/lib/Util/Options.cpp | 2 + 10 files changed, 342 insertions(+), 104 deletions(-) create mode 100644 svf/include/AE/Core/IAbstractState.h diff --git a/svf/include/AE/Core/AbstractState.h b/svf/include/AE/Core/AbstractState.h index 847fcfad5..e7035140f 100644 --- a/svf/include/AE/Core/AbstractState.h +++ b/svf/include/AE/Core/AbstractState.h @@ -48,6 +48,7 @@ #include "AE/Core/AbstractValue.h" #include "AE/Core/IntervalValue.h" +#include "AE/Core/IAbstractState.h" #include "SVFIR/SVFVariables.h" #include "Util/Z3Expr.h" @@ -55,7 +56,7 @@ namespace SVF { -class AbstractState +class AbstractState : public IAbstractState { friend class SVFIR2AbsState; friend class RelationSolver; @@ -82,21 +83,21 @@ class AbstractState virtual ~AbstractState() = default; // getGepObjAddrs - AddressValue getGepObjAddrs(u32_t pointer, IntervalValue offset); + AddressValue getGepObjAddrs(u32_t pointer, IntervalValue offset) override; // initObjVar - void initObjVar(ObjVar* objVar); + void initObjVar(ObjVar* objVar) override; // getElementIndex - IntervalValue getElementIndex(const GepStmt* gep); + IntervalValue getElementIndex(const GepStmt* gep) override; // getByteOffset - IntervalValue getByteOffset(const GepStmt* gep); + IntervalValue getByteOffset(const GepStmt* gep) override; // printAbstractState // loadValue - AbstractValue loadValue(NodeID varId); + AbstractValue loadValue(NodeID varId) override; // storeValue - void storeValue(NodeID varId, AbstractValue val); + void storeValue(NodeID varId, AbstractValue val) override; - u32_t getAllocaInstByteSize(const AddrStmt *addr); + u32_t getAllocaInstByteSize(const AddrStmt *addr) override; /// The physical address starts with 0x7f...... + idx @@ -112,7 +113,7 @@ class AbstractState } /// Return the internal index if addr is an address otherwise return the value of idx - inline u32_t getIDFromAddr(u32_t addr) + inline u32_t getIDFromAddr(u32_t addr) override { return _freedAddrs.count(addr) ? AddressValue::getInternalID(InvalidMemAddr) : AddressValue::getInternalID(addr); } @@ -202,19 +203,19 @@ class AbstractState /// get abstract value of variable - inline virtual AbstractValue &operator[](u32_t varId) + inline AbstractValue &operator[](u32_t varId) override { return _varToAbsVal[varId]; } /// get abstract value of variable - inline virtual const AbstractValue &operator[](u32_t varId) const + inline const AbstractValue &operator[](u32_t varId) const override { return _varToAbsVal.at(varId); } /// whether the variable is in varToAddrs table - inline bool inVarToAddrsTable(u32_t id) const + inline bool inVarToAddrsTable(u32_t id) const override { if (_varToAbsVal.find(id)!= _varToAbsVal.end()) { @@ -227,7 +228,7 @@ class AbstractState } /// whether the variable is in varToVal table - inline virtual bool inVarToValTable(u32_t id) const + inline bool inVarToValTable(u32_t id) const override { if (_varToAbsVal.find(id) != _varToAbsVal.end()) { @@ -240,7 +241,7 @@ class AbstractState } /// whether the memory address stores memory addresses - inline bool inAddrToAddrsTable(u32_t id) const + inline bool inAddrToAddrsTable(u32_t id) const override { if (_addrToAbsVal.find(id)!= _addrToAbsVal.end()) { @@ -253,7 +254,7 @@ class AbstractState } /// whether the memory address stores abstract value - inline virtual bool inAddrToValTable(u32_t id) const + inline bool inAddrToValTable(u32_t id) const override { if (_addrToAbsVal.find(id) != _addrToAbsVal.end()) { @@ -279,24 +280,42 @@ class AbstractState public: - /// domain widen with other, and return the widened domain - AbstractState widening(const AbstractState&other); + /// domain widen with other, and return the widened domain (interface version) + std::unique_ptr widening(const IAbstractState& other) const override; - /// domain narrow with other, and return the narrowed domain - AbstractState narrowing(const AbstractState&other); + /// domain narrow with other, and return the narrowed domain (interface version) + std::unique_ptr narrowing(const IAbstractState& other) const override; + + /// Concrete widening that returns AbstractState (for internal use and backward compatibility) + AbstractState wideningConcrete(const AbstractState& other) const; + + /// Concrete narrowing that returns AbstractState (for internal use and backward compatibility) + AbstractState narrowingConcrete(const AbstractState& other) const; /// domain join with other, important! other widen this. - void joinWith(const AbstractState&other); + void joinWith(const IAbstractState& other) override; /// domain meet with other, important! other widen this. - void meetWith(const AbstractState&other); + void meetWith(const IAbstractState& other) override; + + /// Clone this abstract state + std::unique_ptr clone() const override + { + return std::make_unique(*this); + } + + /// Get state type name + const char* getStateName() const override + { + return "DenseAbstractState"; + } - void addToFreedAddrs(NodeID addr) + void addToFreedAddrs(NodeID addr) override { _freedAddrs.insert(addr); } - bool isFreedMem(u32_t addr) const + bool isFreedMem(u32_t addr) const override { return _freedAddrs.find(addr) != _freedAddrs.end(); } @@ -309,13 +328,13 @@ class AbstractState * we can set arr[0]='c', arr[1]='c', arr[2]='\0' * @param call callnode of memset like api */ - const SVFType* getPointeeElement(NodeID id); + const SVFType* getPointeeElement(NodeID id) override; u32_t hash() const; public: - inline void store(u32_t addr, const AbstractValue &val) + inline void store(u32_t addr, const AbstractValue &val) override { assert(isVirtualMemAddress(addr) && "not virtual address?"); u32_t objId = getIDFromAddr(addr); @@ -323,7 +342,7 @@ class AbstractState _addrToAbsVal[objId] = val; } - inline virtual AbstractValue &load(u32_t addr) + inline AbstractValue &load(u32_t addr) override { assert(isVirtualMemAddress(addr) && "not virtual address?"); u32_t objId = getIDFromAddr(addr); @@ -331,14 +350,14 @@ class AbstractState } - void printAbstractState() const; + void printAbstractState() const override; std::string toString() const { return ""; } - bool equals(const AbstractState&other) const; + bool equals(const IAbstractState& other) const override; static bool eqVarToValMap(const VarToAbsValMap&lhs, const VarToAbsValMap&rhs) diff --git a/svf/include/AE/Core/AbstractValue.h b/svf/include/AE/Core/AbstractValue.h index 1430d37c1..87e5e9909 100644 --- a/svf/include/AE/Core/AbstractValue.h +++ b/svf/include/AE/Core/AbstractValue.h @@ -24,6 +24,9 @@ // Xiao Cheng, Jiawei Wang and Yulei Sui. Precise Sparse Abstract Execution via Cross-Domain Interaction. // 46th International Conference on Software Engineering. (ICSE24) +#ifndef SVF_ABSTRACTVALUE_H +#define SVF_ABSTRACTVALUE_H + #include "AE/Core/IntervalValue.h" #include "AE/Core/AddressValue.h" #include "Util/SVFUtil.h" @@ -154,4 +157,5 @@ class AbstractValue return "<" + interval.toString() + ", " + addrs.toString() + ">"; } }; -} \ No newline at end of file +} +#endif // SVF_ABSTRACTVALUE_H diff --git a/svf/include/AE/Core/IAbstractState.h b/svf/include/AE/Core/IAbstractState.h new file mode 100644 index 000000000..f9a28ea45 --- /dev/null +++ b/svf/include/AE/Core/IAbstractState.h @@ -0,0 +1,152 @@ +//===- IAbstractState.h -- Abstract State Interface -------------------------// +// +// SVF: Static Value-Flow Analysis +// +// Copyright (C) <2013-2022> +// + +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU Affero General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. + +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU Affero General Public License for more details. + +// You should have received a copy of the GNU Affero General Public License +// along with this program. If not, see . +// +//===----------------------------------------------------------------------===// +/* + * IAbstractState.h + * + * Interface for abstract state to support runtime polymorphism. + * This enables switching between different abstract state implementations + * (e.g., dense vs sparse) at runtime via factory pattern. + * + */ + +#ifndef SVF_IABSTRACTSTATE_H +#define SVF_IABSTRACTSTATE_H + +#include "AE/Core/AbstractValue.h" +#include "AE/Core/IntervalValue.h" +#include "SVFIR/SVFVariables.h" +#include + +namespace SVF +{ + +// Forward declarations +class GepStmt; +class AddrStmt; + +/// Abstract interface for abstract state implementations +/// This interface enables runtime polymorphism for different state representations +/// (e.g., DenseAbstractState, SparseAbstractState) +class IAbstractState +{ +public: + virtual ~IAbstractState() = default; + + //============= Core Domain Operations =============// + + /// Domain join with other state (modifies this state) + virtual void joinWith(const IAbstractState& other) = 0; + + /// Domain meet with other state (modifies this state) + virtual void meetWith(const IAbstractState& other) = 0; + + /// Check equality with another state + virtual bool equals(const IAbstractState& other) const = 0; + + /// Widening operation - returns new widened state + virtual std::unique_ptr widening(const IAbstractState& other) const = 0; + + /// Narrowing operation - returns new narrowed state + virtual std::unique_ptr narrowing(const IAbstractState& other) const = 0; + + /// Clone this state + virtual std::unique_ptr clone() const = 0; + + //============= Variable Access Operations =============// + + /// Get abstract value of variable (mutable) + virtual AbstractValue& operator[](u32_t varId) = 0; + + /// Get abstract value of variable (const) + virtual const AbstractValue& operator[](u32_t varId) const = 0; + + /// Check if variable is in var-to-val table (interval value) + virtual bool inVarToValTable(u32_t id) const = 0; + + /// Check if variable is in var-to-addrs table (address value) + virtual bool inVarToAddrsTable(u32_t id) const = 0; + + /// Check if memory address stores interval value + virtual bool inAddrToValTable(u32_t id) const = 0; + + /// Check if memory address stores address value + virtual bool inAddrToAddrsTable(u32_t id) const = 0; + + //============= Memory Operations =============// + + /// Load value from addresses pointed by varId + virtual AbstractValue loadValue(NodeID varId) = 0; + + /// Store value to addresses pointed by varId + virtual void storeValue(NodeID varId, AbstractValue val) = 0; + + /// Store value to a specific memory address + virtual void store(u32_t addr, const AbstractValue& val) = 0; + + /// Load value from a specific memory address + virtual AbstractValue& load(u32_t addr) = 0; + + //============= GEP Operations =============// + + /// Get element index for GEP statement + virtual IntervalValue getElementIndex(const GepStmt* gep) = 0; + + /// Get byte offset for GEP statement + virtual IntervalValue getByteOffset(const GepStmt* gep) = 0; + + /// Get GEP object addresses given pointer and offset + virtual AddressValue getGepObjAddrs(u32_t pointer, IntervalValue offset) = 0; + + //============= Utility Operations =============// + + /// Get internal ID from virtual memory address + virtual u32_t getIDFromAddr(u32_t addr) = 0; + + /// Initialize object variable + virtual void initObjVar(ObjVar* objVar) = 0; + + /// Get byte size of alloca instruction + virtual u32_t getAllocaInstByteSize(const AddrStmt* addr) = 0; + + /// Get pointee element type + virtual const SVFType* getPointeeElement(NodeID id) = 0; + + /// Add address to freed addresses set + virtual void addToFreedAddrs(NodeID addr) = 0; + + /// Check if address is freed + virtual bool isFreedMem(u32_t addr) const = 0; + + /// Print abstract state for debugging + virtual void printAbstractState() const = 0; + + /// Get state type name for identification + virtual const char* getStateName() const = 0; + + //============= Static Address Utilities =============// + // Note: These remain static in AbstractState for backward compatibility + // and can be called via AbstractState::isNullMem, etc. +}; + +} // namespace SVF + +#endif // SVF_IABSTRACTSTATE_H diff --git a/svf/include/AE/Svfexe/AEDetector.h b/svf/include/AE/Svfexe/AEDetector.h index 425844cfe..4f9bd9374 100644 --- a/svf/include/AE/Svfexe/AEDetector.h +++ b/svf/include/AE/Svfexe/AEDetector.h @@ -27,6 +27,7 @@ // #pragma once #include +#include #include #include "Util/SVFBugReport.h" @@ -72,10 +73,10 @@ 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. */ - virtual void detect(AbstractState& as, const ICFGNode* node) = 0; + virtual void detect(IAbstractState& as, const ICFGNode* node) = 0; /** * @brief Pure virtual function for handling stub external API calls. (e.g. UNSAFE_BUFACCESS) @@ -162,29 +163,29 @@ class BufOverflowDetector : public AEDetector /** * @brief Updates the offset of a GEP object from its base. - * @param as Reference to the abstract state. + * @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, + void updateGepObjOffsetFromBase(IAbstractState& 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. */ - void detect(AbstractState& as, const ICFGNode*); + void detect(IAbstractState& as, const ICFGNode*) override; /** * @brief Handles external API calls related to buffer overflow detection. * @param call Pointer to the call ICFG node. */ - void handleStubFunctions(const CallICFGNode*); + void handleStubFunctions(const CallICFGNode*) override; /** * @brief Adds an offset to a GEP object. @@ -224,12 +225,12 @@ class BufOverflowDetector : public AEDetector /** * @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. */ - IntervalValue getAccessOffset(AbstractState& as, NodeID objId, const GepStmt* gep); + IntervalValue getAccessOffset(IAbstractState& as, NodeID objId, const GepStmt* gep); /** * @brief Adds a bug to the reporter based on an exception. @@ -268,7 +269,7 @@ class BufOverflowDetector : public AEDetector /** * @brief Reports all detected buffer overflow bugs. */ - void reportBug() + void reportBug() override { if (!nodeToBugInfo.empty()) { @@ -289,36 +290,36 @@ class BufOverflowDetector : public AEDetector /** * @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); + void detectExtAPI(IAbstractState& 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. */ - bool canSafelyAccessMemory(AbstractState& as, const SVFVar *value, const IntervalValue &len); + bool canSafelyAccessMemory(IAbstractState& as, const SVFVar *value, const IntervalValue &len); 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); + bool detectStrcat(IAbstractState& 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); + bool detectStrcpy(IAbstractState& as, const CallICFGNode *call); private: Map gepObjOffsetFromBase; ///< Maps GEP objects to their offsets from the base. @@ -345,16 +346,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(IAbstractState& 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. @@ -401,7 +402,7 @@ class NullptrDerefDetector : public AEDetector /** * @brief Reports all detected nullptr dereference bugs. */ - void reportBug() + void reportBug() override { if (!nodeToBugInfo.empty()) { @@ -417,10 +418,10 @@ 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); + void detectExtAPI(IAbstractState& as, const CallICFGNode* call); /** @@ -433,7 +434,7 @@ class NullptrDerefDetector : public AEDetector return !v.isAddr() && !v.isInterval(); } - bool canSafelyDerefPtr(AbstractState& as, const SVFVar* ptr); + bool canSafelyDerefPtr(IAbstractState& as, const SVFVar* ptr); private: Set bugLoc; ///< Set of locations where bugs have been reported. diff --git a/svf/include/AE/Svfexe/AbstractInterpretation.h b/svf/include/AE/Svfexe/AbstractInterpretation.h index 53a76becf..ad14dbbe6 100644 --- a/svf/include/AE/Svfexe/AbstractInterpretation.h +++ b/svf/include/AE/Svfexe/AbstractInterpretation.h @@ -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 namespace SVF { @@ -163,7 +165,21 @@ class AbstractInterpretation * @return Reference to the abstract state. * @throws Assertion if no trace exists for the node. */ - AbstractState& getAbsStateFromTrace(const ICFGNode* node) + IAbstractState& getAbsStateFromTrace(const ICFGNode* node) + { + if (abstractTrace.count(node) == 0) + { + assert(false && "No preAbsTrace for this node"); + abort(); + } + else + { + return abstractTrace[node]; + } + } + + /// Concrete access to abstract state from trace (for internal use) + AbstractState& getConcreteAbsStateFromTrace(const ICFGNode* node) { if (abstractTrace.count(node) == 0) { @@ -306,6 +322,18 @@ class AbstractInterpretation return abstractTrace.count(node) != 0; } + /// Factory method to create abstract state based on CLI option + /// Currently returns DenseAbstractState; will support SparseAbstractState in the future + std::unique_ptr createState() + { + if (Options::UseSparseState()) + { + // TODO: Return SparseAbstractState when implemented + assert(false && "SparseAbstractState not implemented yet. Use -use-sparse=false"); + } + return std::make_unique(); + } + AbsExtAPI* getUtils() { return utils; diff --git a/svf/include/Util/Options.h b/svf/include/Util/Options.h index 0fa17910d..946251aa0 100644 --- a/svf/include/Util/Options.h +++ b/svf/include/Util/Options.h @@ -243,6 +243,8 @@ class Options static const Option WidenDelay; /// recursion handling mode, Default: TOP static const OptionMap HandleRecur; + /// Use sparse abstract state representation (experimental) + static const Option UseSparseState; /// the max time consumptions (seconds). Default: 4 hours 14400s static const Option Timeout; /// bug info output file, Default: output.db diff --git a/svf/lib/AE/Core/AbstractState.cpp b/svf/lib/AE/Core/AbstractState.cpp index d31f111a3..b4515a81a 100644 --- a/svf/lib/AE/Core/AbstractState.cpp +++ b/svf/lib/AE/Core/AbstractState.cpp @@ -30,13 +30,19 @@ #include "AE/Core/AbstractState.h" #include "Util/SVFUtil.h" #include "Util/Options.h" +#include using namespace SVF; using namespace SVFUtil; -bool AbstractState::equals(const AbstractState&other) const +bool AbstractState::equals(const IAbstractState& other) const { - return *this == other; + const AbstractState* otherState = dynamic_cast(&other); + if (!otherState) + { + return false; // Different state types are never equal + } + return *this == *otherState; } u32_t AbstractState::hash() const @@ -56,7 +62,7 @@ u32_t AbstractState::hash() const return pairH({h, h2}); } -AbstractState AbstractState::widening(const AbstractState& other) +AbstractState AbstractState::wideningConcrete(const AbstractState& other) const { // widen interval AbstractState es = *this; @@ -77,7 +83,14 @@ AbstractState AbstractState::widening(const AbstractState& other) return es; } -AbstractState AbstractState::narrowing(const AbstractState& other) +std::unique_ptr AbstractState::widening(const IAbstractState& other) const +{ + const AbstractState* otherState = dynamic_cast(&other); + assert(otherState && "Type mismatch in widening: expected AbstractState"); + return std::make_unique(wideningConcrete(*otherState)); +} + +AbstractState AbstractState::narrowingConcrete(const AbstractState& other) const { AbstractState es = *this; for (auto it = es._varToAbsVal.begin(); it != es._varToAbsVal.end(); ++it) @@ -95,13 +108,22 @@ AbstractState AbstractState::narrowing(const AbstractState& other) it->second.getInterval().narrow_with(other._addrToAbsVal.at(key).getInterval()); } return es; +} +std::unique_ptr AbstractState::narrowing(const IAbstractState& other) const +{ + const AbstractState* otherState = dynamic_cast(&other); + assert(otherState && "Type mismatch in narrowing: expected AbstractState"); + return std::make_unique(narrowingConcrete(*otherState)); } /// domain join with other, important! other widen this. -void AbstractState::joinWith(const AbstractState& other) +void AbstractState::joinWith(const IAbstractState& other) { - for (auto it = other._varToAbsVal.begin(); it != other._varToAbsVal.end(); ++it) + const AbstractState* otherState = dynamic_cast(&other); + assert(otherState && "Type mismatch in joinWith: expected AbstractState"); + + for (auto it = otherState->_varToAbsVal.begin(); it != otherState->_varToAbsVal.end(); ++it) { auto key = it->first; auto oit = _varToAbsVal.find(key); @@ -114,7 +136,7 @@ void AbstractState::joinWith(const AbstractState& other) _varToAbsVal.emplace(key, it->second); } } - for (auto it = other._addrToAbsVal.begin(); it != other._addrToAbsVal.end(); ++it) + for (auto it = otherState->_addrToAbsVal.begin(); it != otherState->_addrToAbsVal.end(); ++it) { auto key = it->first; auto oit = _addrToAbsVal.find(key); @@ -127,13 +149,16 @@ void AbstractState::joinWith(const AbstractState& other) _addrToAbsVal.emplace(key, it->second); } } - _freedAddrs.insert(other._freedAddrs.begin(), other._freedAddrs.end()); + _freedAddrs.insert(otherState->_freedAddrs.begin(), otherState->_freedAddrs.end()); } /// domain meet with other, important! other widen this. -void AbstractState::meetWith(const AbstractState& other) +void AbstractState::meetWith(const IAbstractState& other) { - for (auto it = other._varToAbsVal.begin(); it != other._varToAbsVal.end(); ++it) + const AbstractState* otherState = dynamic_cast(&other); + assert(otherState && "Type mismatch in meetWith: expected AbstractState"); + + for (auto it = otherState->_varToAbsVal.begin(); it != otherState->_varToAbsVal.end(); ++it) { auto key = it->first; auto oit = _varToAbsVal.find(key); @@ -142,7 +167,7 @@ void AbstractState::meetWith(const AbstractState& other) oit->second.meet_with(it->second); } } - for (auto it = other._addrToAbsVal.begin(); it != other._addrToAbsVal.end(); ++it) + for (auto it = otherState->_addrToAbsVal.begin(); it != otherState->_addrToAbsVal.end(); ++it) { auto key = it->first; auto oit = _addrToAbsVal.find(key); @@ -153,7 +178,7 @@ void AbstractState::meetWith(const AbstractState& other) } Set intersection; std::set_intersection(_freedAddrs.begin(), _freedAddrs.end(), - other._freedAddrs.begin(), other._freedAddrs.end(), + otherState->_freedAddrs.begin(), otherState->_freedAddrs.end(), std::inserter(intersection, intersection.begin())); _freedAddrs = std::move(intersection); } diff --git a/svf/lib/AE/Svfexe/AEDetector.cpp b/svf/lib/AE/Svfexe/AEDetector.cpp index ae9d0bb3c..e9231024f 100644 --- a/svf/lib/AE/Svfexe/AEDetector.cpp +++ b/svf/lib/AE/Svfexe/AEDetector.cpp @@ -42,7 +42,7 @@ using namespace SVF; * @param as Reference to the abstract state. * @param node Pointer to the ICFG node. */ -void BufOverflowDetector::detect(AbstractState& as, const ICFGNode* node) +void BufOverflowDetector::detect(IAbstractState& as, const ICFGNode* node) { if (!SVFUtil::isa(node)) { @@ -122,7 +122,7 @@ void BufOverflowDetector::handleStubFunctions(const SVF::CallICFGNode* callNode) AbstractInterpretation::getAEInstance().checkpoints.erase(callNode); if (callNode->arg_size() < 2) return; - AbstractState& as = + IAbstractState& as = AbstractInterpretation::getAEInstance().getAbsStateFromTrace( callNode); u32_t size_id = callNode->getArgument(1)->getId(); @@ -152,7 +152,7 @@ void BufOverflowDetector::handleStubFunctions(const SVF::CallICFGNode* callNode) // void UNSAFE_BUFACCESS(void* data, int size); AbstractInterpretation::getAEInstance().checkpoints.erase(callNode); if (callNode->arg_size() < 2) return; - AbstractState&as = AbstractInterpretation::getAEInstance().getAbsStateFromTrace(callNode); + IAbstractState& as = AbstractInterpretation::getAEInstance().getAbsStateFromTrace(callNode); u32_t size_id = callNode->getArgument(1)->getId(); IntervalValue val = as[size_id].getInterval(); if (val.isBottom()) @@ -216,7 +216,7 @@ void BufOverflowDetector::initExtAPIBufOverflowCheckRules() * @param as Reference to the abstract state. * @param call Pointer to the call ICFG node. */ -void BufOverflowDetector::detectExtAPI(AbstractState& as, +void BufOverflowDetector::detectExtAPI(IAbstractState& as, const CallICFGNode* call) { assert(call->getCalledFunction() && "FunObjVar* is nullptr"); @@ -310,7 +310,7 @@ void BufOverflowDetector::detectExtAPI(AbstractState& as, * @param gep Pointer to the GEP statement. * @return The interval value of the access offset. */ -IntervalValue BufOverflowDetector::getAccessOffset(SVF::AbstractState& as, SVF::NodeID objId, const SVF::GepStmt* gep) +IntervalValue BufOverflowDetector::getAccessOffset(SVF::IAbstractState& as, SVF::NodeID objId, const SVF::GepStmt* gep) { SVFIR* svfir = PAG::getPAG(); auto obj = svfir->getGNode(objId); @@ -344,7 +344,7 @@ IntervalValue BufOverflowDetector::getAccessOffset(SVF::AbstractState& as, SVF:: * @param objAddrs The addresses of the base objects. * @param offset The interval value of the offset. */ -void BufOverflowDetector::updateGepObjOffsetFromBase(AbstractState& as, SVF::AddressValue gepAddrs, SVF::AddressValue objAddrs, SVF::IntervalValue offset) +void BufOverflowDetector::updateGepObjOffsetFromBase(IAbstractState& as, SVF::AddressValue gepAddrs, SVF::AddressValue objAddrs, SVF::IntervalValue offset) { SVFIR* svfir = PAG::getPAG(); @@ -415,11 +415,13 @@ void BufOverflowDetector::updateGepObjOffsetFromBase(AbstractState& as, SVF::Add * @param call Pointer to the call ICFG node. * @return True if the memory access is safe, false otherwise. */ -bool BufOverflowDetector::detectStrcpy(AbstractState& as, const CallICFGNode *call) +bool BufOverflowDetector::detectStrcpy(IAbstractState& as, const CallICFGNode *call) { const SVFVar* arg0Val = call->getArgument(0); const SVFVar* arg1Val = call->getArgument(1); - IntervalValue strLen = AbstractInterpretation::getAEInstance().getUtils()->getStrlen(as, arg1Val); + // Cast to AbstractState for AbsExtAPI compatibility (will be refactored in Phase 4) + AbstractState& concreteAs = dynamic_cast(as); + IntervalValue strLen = AbstractInterpretation::getAEInstance().getUtils()->getStrlen(concreteAs, arg1Val); return canSafelyAccessMemory(as, arg0Val, strLen); } @@ -433,17 +435,20 @@ bool BufOverflowDetector::detectStrcpy(AbstractState& as, const CallICFGNode *ca * @param call Pointer to the call ICFG node. * @return True if the memory access is safe, false otherwise. */ -bool BufOverflowDetector::detectStrcat(AbstractState& as, const CallICFGNode *call) +bool BufOverflowDetector::detectStrcat(IAbstractState& as, const CallICFGNode *call) { const std::vector strcatGroup = {"__strcat_chk", "strcat", "__wcscat_chk", "wcscat"}; const std::vector strncatGroup = {"__strncat_chk", "strncat", "__wcsncat_chk", "wcsncat"}; + // Cast to AbstractState for AbsExtAPI compatibility (will be refactored in Phase 4) + AbstractState& concreteAs = dynamic_cast(as); + if (std::find(strcatGroup.begin(), strcatGroup.end(), call->getCalledFunction()->getName()) != strcatGroup.end()) { const SVFVar* arg0Val = call->getArgument(0); const SVFVar* arg1Val = call->getArgument(1); - IntervalValue strLen0 = AbstractInterpretation::getAEInstance().getUtils()->getStrlen(as, arg0Val); - IntervalValue strLen1 = AbstractInterpretation::getAEInstance().getUtils()->getStrlen(as, arg1Val); + IntervalValue strLen0 = AbstractInterpretation::getAEInstance().getUtils()->getStrlen(concreteAs, arg0Val); + IntervalValue strLen1 = AbstractInterpretation::getAEInstance().getUtils()->getStrlen(concreteAs, arg1Val); IntervalValue totalLen = strLen0 + strLen1; return canSafelyAccessMemory(as, arg0Val, totalLen); } @@ -452,7 +457,7 @@ bool BufOverflowDetector::detectStrcat(AbstractState& as, const CallICFGNode *ca const SVFVar* arg0Val = call->getArgument(0); const SVFVar* arg2Val = call->getArgument(2); IntervalValue arg2Num = as[arg2Val->getId()].getInterval(); - IntervalValue strLen0 = AbstractInterpretation::getAEInstance().getUtils()->getStrlen(as, arg0Val); + IntervalValue strLen0 = AbstractInterpretation::getAEInstance().getUtils()->getStrlen(concreteAs, arg0Val); IntervalValue totalLen = strLen0 + arg2Num; return canSafelyAccessMemory(as, arg0Val, totalLen); } @@ -474,7 +479,7 @@ bool BufOverflowDetector::detectStrcat(AbstractState& as, const CallICFGNode *ca * @param len The interval value representing the length of the memory access. * @return True if the memory access is safe, false otherwise. */ -bool BufOverflowDetector::canSafelyAccessMemory(AbstractState& as, const SVF::SVFVar* value, const SVF::IntervalValue& len) +bool BufOverflowDetector::canSafelyAccessMemory(IAbstractState& as, const SVF::SVFVar* value, const SVF::IntervalValue& len) { SVFIR* svfir = PAG::getPAG(); NodeID value_id = value->getId(); @@ -523,7 +528,7 @@ bool BufOverflowDetector::canSafelyAccessMemory(AbstractState& as, const SVF::SV return true; } -void NullptrDerefDetector::detect(AbstractState& as, const ICFGNode* node) +void NullptrDerefDetector::detect(IAbstractState& as, const ICFGNode* node) { if (SVFUtil::isa(node)) { @@ -575,7 +580,7 @@ void NullptrDerefDetector::handleStubFunctions(const CallICFGNode* callNode) AbstractInterpretation::getAEInstance().checkpoints.erase(callNode); if (callNode->arg_size() < 1) return; - AbstractState& as = AbstractInterpretation::getAEInstance().getAbsStateFromTrace(callNode); + IAbstractState& as = AbstractInterpretation::getAEInstance().getAbsStateFromTrace(callNode); const SVFVar* arg0Val = callNode->getArgument(0); // opt may directly dereference a null pointer and call UNSAFE_LOAD(null) @@ -598,7 +603,7 @@ void NullptrDerefDetector::handleStubFunctions(const CallICFGNode* callNode) // void SAFE_LOAD(void* ptr); AbstractInterpretation::getAEInstance().checkpoints.erase(callNode); if (callNode->arg_size() < 1) return; - AbstractState&as = AbstractInterpretation::getAEInstance().getAbsStateFromTrace(callNode); + IAbstractState& as = AbstractInterpretation::getAEInstance().getAbsStateFromTrace(callNode); const SVFVar* arg0Val = callNode->getArgument(0); // opt may directly dereference a null pointer and call UNSAFE_LOAD(null)ols bool isSafe = canSafelyDerefPtr(as, arg0Val) && arg0Val->getId() != 0; @@ -617,7 +622,7 @@ void NullptrDerefDetector::handleStubFunctions(const CallICFGNode* callNode) } } -void NullptrDerefDetector::detectExtAPI(AbstractState& as, const CallICFGNode* call) +void NullptrDerefDetector::detectExtAPI(IAbstractState& as, const CallICFGNode* call) { assert(call->getCalledFunction() && "FunObjVar* is nullptr"); // get ext type @@ -676,7 +681,7 @@ void NullptrDerefDetector::detectExtAPI(AbstractState& as, const CallICFGNode* c } -bool NullptrDerefDetector::canSafelyDerefPtr(AbstractState& as, const SVFVar* value) +bool NullptrDerefDetector::canSafelyDerefPtr(IAbstractState& as, const SVFVar* value) { NodeID value_id = value->getId(); AbstractValue AbsVal = as[value_id]; diff --git a/svf/lib/AE/Svfexe/AbstractInterpretation.cpp b/svf/lib/AE/Svfexe/AbstractInterpretation.cpp index b3aed674f..c7a1cd44f 100644 --- a/svf/lib/AE/Svfexe/AbstractInterpretation.cpp +++ b/svf/lib/AE/Svfexe/AbstractInterpretation.cpp @@ -664,7 +664,7 @@ bool AbstractInterpretation::isRecursiveCall(const CallICFGNode *callNode) void AbstractInterpretation::recursiveCallPass(const CallICFGNode *callNode) { - AbstractState& as = getAbsStateFromTrace(callNode); + AbstractState& as = getConcreteAbsStateFromTrace(callNode); SkipRecursiveCall(callNode); const RetICFGNode *retNode = callNode->getRetICFGNode(); if (retNode->getSVFStmts().size() > 0) @@ -698,7 +698,7 @@ bool AbstractInterpretation::isDirectCall(const CallICFGNode *callNode) } void AbstractInterpretation::directCallFunPass(const CallICFGNode *callNode) { - AbstractState& as = getAbsStateFromTrace(callNode); + AbstractState& as = getConcreteAbsStateFromTrace(callNode); abstractTrace[callNode] = as; @@ -739,7 +739,7 @@ bool AbstractInterpretation::isIndirectCall(const CallICFGNode *callNode) void AbstractInterpretation::indirectCallFunPass(const CallICFGNode *callNode) { - AbstractState& as = getAbsStateFromTrace(callNode); + AbstractState& as = getConcreteAbsStateFromTrace(callNode); const auto callsiteMaps = svfir->getIndirectCallsites(); NodeID call_id = callsiteMaps.at(callNode); if (!as.inVarToAddrsTable(call_id)) @@ -800,7 +800,7 @@ void AbstractInterpretation::handleCycleWTO(const ICFGCycleWTO*cycle) } // Widening - abstractTrace[cycle_head] = prev_head_state.widening(cur_head_state); + abstractTrace[cycle_head] = prev_head_state.wideningConcrete(cur_head_state); if (abstractTrace[cycle_head] == prev_head_state) { @@ -822,7 +822,7 @@ void AbstractInterpretation::handleCycleWTO(const ICFGCycleWTO*cycle) else if (Options::HandleRecur() == WIDEN_NARROW) { // Widening's fixpoint reached in the widening phase, switch to narrowing - abstractTrace[cycle_head] = prev_head_state.narrowing(cur_head_state); + abstractTrace[cycle_head] = prev_head_state.narrowingConcrete(cur_head_state); if (abstractTrace[cycle_head] == prev_head_state) { // Narrowing's fixpoint reached in the narrowing phase, exit loop @@ -840,7 +840,7 @@ void AbstractInterpretation::handleCycleWTO(const ICFGCycleWTO*cycle) else { // Widening's fixpoint reached in the widening phase, switch to narrowing - abstractTrace[cycle_head] = prev_head_state.narrowing(cur_head_state); + abstractTrace[cycle_head] = prev_head_state.narrowingConcrete(cur_head_state); if (abstractTrace[cycle_head] == prev_head_state) { // Narrowing's fixpoint reached in the narrowing phase, exit loop @@ -922,7 +922,7 @@ void AbstractInterpretation::handleSVFStatement(const SVFStmt *stmt) void AbstractInterpretation::SkipRecursiveCall(const CallICFGNode *callNode) { - AbstractState& as = getAbsStateFromTrace(callNode); + AbstractState& as = getConcreteAbsStateFromTrace(callNode); const RetICFGNode *retNode = callNode->getRetICFGNode(); if (retNode->getSVFStmts().size() > 0) { @@ -1121,7 +1121,7 @@ void AbstractInterpretation::checkPointAllSet() void AbstractInterpretation::updateStateOnGep(const GepStmt *gep) { - AbstractState& as = getAbsStateFromTrace(gep->getICFGNode()); + AbstractState& as = getConcreteAbsStateFromTrace(gep->getICFGNode()); u32_t rhs = gep->getRHSVarID(); u32_t lhs = gep->getLHSVarID(); IntervalValue offsetPair = as.getElementIndex(gep); @@ -1137,7 +1137,7 @@ void AbstractInterpretation::updateStateOnGep(const GepStmt *gep) void AbstractInterpretation::updateStateOnSelect(const SelectStmt *select) { - AbstractState& as = getAbsStateFromTrace(select->getICFGNode()); + AbstractState& as = getConcreteAbsStateFromTrace(select->getICFGNode()); u32_t res = select->getResID(); u32_t tval = select->getTrueValue()->getId(); u32_t fval = select->getFalseValue()->getId(); @@ -1156,7 +1156,7 @@ void AbstractInterpretation::updateStateOnSelect(const SelectStmt *select) void AbstractInterpretation::updateStateOnPhi(const PhiStmt *phi) { const ICFGNode* icfgNode = phi->getICFGNode(); - AbstractState& as = getAbsStateFromTrace(icfgNode); + AbstractState& as = getConcreteAbsStateFromTrace(icfgNode); u32_t res = phi->getResID(); AbstractValue rhs; for (u32_t i = 0; i < phi->getOpVarNum(); i++) @@ -1166,7 +1166,7 @@ void AbstractInterpretation::updateStateOnPhi(const PhiStmt *phi) if (hasAbsStateFromTrace(opICFGNode)) { AbstractState tmpEs = abstractTrace[opICFGNode]; - AbstractState& opAs = getAbsStateFromTrace(opICFGNode); + AbstractState& opAs = getConcreteAbsStateFromTrace(opICFGNode); const ICFGEdge* edge = icfg->getICFGEdge(opICFGNode, icfgNode, ICFGEdge::IntraCF); // if IntraEdge, check the condition, if it is feasible, join the value // if IntraEdge but not conditional edge, join the value @@ -1194,7 +1194,7 @@ void AbstractInterpretation::updateStateOnPhi(const PhiStmt *phi) void AbstractInterpretation::updateStateOnCall(const CallPE *callPE) { - AbstractState& as = getAbsStateFromTrace(callPE->getICFGNode()); + AbstractState& as = getConcreteAbsStateFromTrace(callPE->getICFGNode()); NodeID lhs = callPE->getLHSVarID(); NodeID rhs = callPE->getRHSVarID(); as[lhs] = as[rhs]; @@ -1202,7 +1202,7 @@ void AbstractInterpretation::updateStateOnCall(const CallPE *callPE) void AbstractInterpretation::updateStateOnRet(const RetPE *retPE) { - AbstractState& as = getAbsStateFromTrace(retPE->getICFGNode()); + AbstractState& as = getConcreteAbsStateFromTrace(retPE->getICFGNode()); NodeID lhs = retPE->getLHSVarID(); NodeID rhs = retPE->getRHSVarID(); as[lhs] = as[rhs]; @@ -1211,7 +1211,7 @@ void AbstractInterpretation::updateStateOnRet(const RetPE *retPE) void AbstractInterpretation::updateStateOnAddr(const AddrStmt *addr) { - AbstractState& as = getAbsStateFromTrace(addr->getICFGNode()); + AbstractState& as = getConcreteAbsStateFromTrace(addr->getICFGNode()); as.initObjVar(SVFUtil::cast(addr->getRHSVar())); if (addr->getRHSVar()->getType()->getKind() == SVFType::SVFIntegerTy) as[addr->getRHSVarID()].getInterval().meet_with(utils->getRangeLimitFromType(addr->getRHSVar()->getType())); @@ -1225,7 +1225,7 @@ void AbstractInterpretation::updateStateOnBinary(const BinaryOPStmt *binary) /// You are only required to handle integer predicates, including Add, FAdd, Sub, FSub, Mul, FMul, SDiv, FDiv, UDiv, /// SRem, FRem, URem, Xor, And, Or, AShr, Shl, LShr const ICFGNode* node = binary->getICFGNode(); - AbstractState& as = getAbsStateFromTrace(node); + AbstractState& as = getConcreteAbsStateFromTrace(node); u32_t op0 = binary->getOpVarID(0); u32_t op1 = binary->getOpVarID(1); u32_t res = binary->getResID(); @@ -1283,7 +1283,7 @@ void AbstractInterpretation::updateStateOnBinary(const BinaryOPStmt *binary) void AbstractInterpretation::updateStateOnCmp(const CmpStmt *cmp) { - AbstractState& as = getAbsStateFromTrace(cmp->getICFGNode()); + AbstractState& as = getConcreteAbsStateFromTrace(cmp->getICFGNode()); u32_t op0 = cmp->getOpVarID(0); u32_t op1 = cmp->getOpVarID(1); // if it is address @@ -1498,7 +1498,7 @@ void AbstractInterpretation::updateStateOnCmp(const CmpStmt *cmp) void AbstractInterpretation::updateStateOnLoad(const LoadStmt *load) { - AbstractState& as = getAbsStateFromTrace(load->getICFGNode()); + AbstractState& as = getConcreteAbsStateFromTrace(load->getICFGNode()); u32_t rhs = load->getRHSVarID(); u32_t lhs = load->getLHSVarID(); as[lhs] = as.loadValue(rhs); @@ -1506,7 +1506,7 @@ void AbstractInterpretation::updateStateOnLoad(const LoadStmt *load) void AbstractInterpretation::updateStateOnStore(const StoreStmt *store) { - AbstractState& as = getAbsStateFromTrace(store->getICFGNode()); + AbstractState& as = getConcreteAbsStateFromTrace(store->getICFGNode()); u32_t rhs = store->getRHSVarID(); u32_t lhs = store->getLHSVarID(); as.storeValue(lhs, as[rhs]); @@ -1610,7 +1610,7 @@ void AbstractInterpretation::updateStateOnCopy(const CopyStmt *copy) } }; - AbstractState& as = getAbsStateFromTrace(copy->getICFGNode()); + AbstractState& as = getConcreteAbsStateFromTrace(copy->getICFGNode()); u32_t lhs = copy->getLHSVarID(); u32_t rhs = copy->getRHSVarID(); diff --git a/svf/lib/Util/Options.cpp b/svf/lib/Util/Options.cpp index a783ce4e9..2db5f0d2d 100644 --- a/svf/lib/Util/Options.cpp +++ b/svf/lib/Util/Options.cpp @@ -802,6 +802,8 @@ const OptionMap Options::HandleRecur( } } ); +const Option Options::UseSparseState( + "use-sparse", "Use sparse abstract state representation (experimental)", false); const Option Options::Timeout( "timeout", "time out (seconds), set -1 (no timeout), default 14400s",14400); const Option Options::OutputName( From ad99f64cd1076f615aab1de7f157fb1d1a9a0237 Mon Sep 17 00:00:00 2001 From: bjjwwang Date: Sun, 18 Jan 2026 21:34:42 +1100 Subject: [PATCH 2/9] rename concrete to dense --- svf/include/AE/Core/AbstractState.h | 8 ++-- .../AE/Svfexe/AbstractInterpretation.h | 4 +- svf/lib/AE/Core/AbstractState.cpp | 8 ++-- svf/lib/AE/Svfexe/AEDetector.cpp | 16 ++++---- svf/lib/AE/Svfexe/AbstractInterpretation.cpp | 38 +++++++++---------- 5 files changed, 37 insertions(+), 37 deletions(-) diff --git a/svf/include/AE/Core/AbstractState.h b/svf/include/AE/Core/AbstractState.h index e7035140f..38b6b65fe 100644 --- a/svf/include/AE/Core/AbstractState.h +++ b/svf/include/AE/Core/AbstractState.h @@ -286,11 +286,11 @@ class AbstractState : public IAbstractState /// domain narrow with other, and return the narrowed domain (interface version) std::unique_ptr narrowing(const IAbstractState& other) const override; - /// Concrete widening that returns AbstractState (for internal use and backward compatibility) - AbstractState wideningConcrete(const AbstractState& other) const; + /// Dense widening that returns AbstractState (for internal use and backward compatibility) + AbstractState wideningDense(const AbstractState& other) const; - /// Concrete narrowing that returns AbstractState (for internal use and backward compatibility) - AbstractState narrowingConcrete(const AbstractState& other) const; + /// Dense narrowing that returns AbstractState (for internal use and backward compatibility) + AbstractState narrowingDense(const AbstractState& other) const; /// domain join with other, important! other widen this. void joinWith(const IAbstractState& other) override; diff --git a/svf/include/AE/Svfexe/AbstractInterpretation.h b/svf/include/AE/Svfexe/AbstractInterpretation.h index ad14dbbe6..0b6d65b53 100644 --- a/svf/include/AE/Svfexe/AbstractInterpretation.h +++ b/svf/include/AE/Svfexe/AbstractInterpretation.h @@ -178,8 +178,8 @@ class AbstractInterpretation } } - /// Concrete access to abstract state from trace (for internal use) - AbstractState& getConcreteAbsStateFromTrace(const ICFGNode* node) + /// Dense state access from trace (for internal use when AbstractState is needed) + AbstractState& getDenseAbsStateFromTrace(const ICFGNode* node) { if (abstractTrace.count(node) == 0) { diff --git a/svf/lib/AE/Core/AbstractState.cpp b/svf/lib/AE/Core/AbstractState.cpp index b4515a81a..4739c8e90 100644 --- a/svf/lib/AE/Core/AbstractState.cpp +++ b/svf/lib/AE/Core/AbstractState.cpp @@ -62,7 +62,7 @@ u32_t AbstractState::hash() const return pairH({h, h2}); } -AbstractState AbstractState::wideningConcrete(const AbstractState& other) const +AbstractState AbstractState::wideningDense(const AbstractState& other) const { // widen interval AbstractState es = *this; @@ -87,10 +87,10 @@ std::unique_ptr AbstractState::widening(const IAbstractState& ot { const AbstractState* otherState = dynamic_cast(&other); assert(otherState && "Type mismatch in widening: expected AbstractState"); - return std::make_unique(wideningConcrete(*otherState)); + return std::make_unique(wideningDense(*otherState)); } -AbstractState AbstractState::narrowingConcrete(const AbstractState& other) const +AbstractState AbstractState::narrowingDense(const AbstractState& other) const { AbstractState es = *this; for (auto it = es._varToAbsVal.begin(); it != es._varToAbsVal.end(); ++it) @@ -114,7 +114,7 @@ std::unique_ptr AbstractState::narrowing(const IAbstractState& o { const AbstractState* otherState = dynamic_cast(&other); assert(otherState && "Type mismatch in narrowing: expected AbstractState"); - return std::make_unique(narrowingConcrete(*otherState)); + return std::make_unique(narrowingDense(*otherState)); } /// domain join with other, important! other widen this. diff --git a/svf/lib/AE/Svfexe/AEDetector.cpp b/svf/lib/AE/Svfexe/AEDetector.cpp index e9231024f..bb834b21a 100644 --- a/svf/lib/AE/Svfexe/AEDetector.cpp +++ b/svf/lib/AE/Svfexe/AEDetector.cpp @@ -419,9 +419,9 @@ bool BufOverflowDetector::detectStrcpy(IAbstractState& as, const CallICFGNode *c { const SVFVar* arg0Val = call->getArgument(0); const SVFVar* arg1Val = call->getArgument(1); - // Cast to AbstractState for AbsExtAPI compatibility (will be refactored in Phase 4) - AbstractState& concreteAs = dynamic_cast(as); - IntervalValue strLen = AbstractInterpretation::getAEInstance().getUtils()->getStrlen(concreteAs, arg1Val); + // Cast to dense AbstractState for AbsExtAPI compatibility + AbstractState& denseAs = dynamic_cast(as); + IntervalValue strLen = AbstractInterpretation::getAEInstance().getUtils()->getStrlen(denseAs, arg1Val); return canSafelyAccessMemory(as, arg0Val, strLen); } @@ -440,15 +440,15 @@ bool BufOverflowDetector::detectStrcat(IAbstractState& as, const CallICFGNode *c const std::vector strcatGroup = {"__strcat_chk", "strcat", "__wcscat_chk", "wcscat"}; const std::vector strncatGroup = {"__strncat_chk", "strncat", "__wcsncat_chk", "wcsncat"}; - // Cast to AbstractState for AbsExtAPI compatibility (will be refactored in Phase 4) - AbstractState& concreteAs = dynamic_cast(as); + // Cast to dense AbstractState for AbsExtAPI compatibility + AbstractState& denseAs = dynamic_cast(as); if (std::find(strcatGroup.begin(), strcatGroup.end(), call->getCalledFunction()->getName()) != strcatGroup.end()) { const SVFVar* arg0Val = call->getArgument(0); const SVFVar* arg1Val = call->getArgument(1); - IntervalValue strLen0 = AbstractInterpretation::getAEInstance().getUtils()->getStrlen(concreteAs, arg0Val); - IntervalValue strLen1 = AbstractInterpretation::getAEInstance().getUtils()->getStrlen(concreteAs, arg1Val); + IntervalValue strLen0 = AbstractInterpretation::getAEInstance().getUtils()->getStrlen(denseAs, arg0Val); + IntervalValue strLen1 = AbstractInterpretation::getAEInstance().getUtils()->getStrlen(denseAs, arg1Val); IntervalValue totalLen = strLen0 + strLen1; return canSafelyAccessMemory(as, arg0Val, totalLen); } @@ -457,7 +457,7 @@ bool BufOverflowDetector::detectStrcat(IAbstractState& as, const CallICFGNode *c const SVFVar* arg0Val = call->getArgument(0); const SVFVar* arg2Val = call->getArgument(2); IntervalValue arg2Num = as[arg2Val->getId()].getInterval(); - IntervalValue strLen0 = AbstractInterpretation::getAEInstance().getUtils()->getStrlen(concreteAs, arg0Val); + IntervalValue strLen0 = AbstractInterpretation::getAEInstance().getUtils()->getStrlen(denseAs, arg0Val); IntervalValue totalLen = strLen0 + arg2Num; return canSafelyAccessMemory(as, arg0Val, totalLen); } diff --git a/svf/lib/AE/Svfexe/AbstractInterpretation.cpp b/svf/lib/AE/Svfexe/AbstractInterpretation.cpp index c7a1cd44f..a15c3da68 100644 --- a/svf/lib/AE/Svfexe/AbstractInterpretation.cpp +++ b/svf/lib/AE/Svfexe/AbstractInterpretation.cpp @@ -664,7 +664,7 @@ bool AbstractInterpretation::isRecursiveCall(const CallICFGNode *callNode) void AbstractInterpretation::recursiveCallPass(const CallICFGNode *callNode) { - AbstractState& as = getConcreteAbsStateFromTrace(callNode); + AbstractState& as = getDenseAbsStateFromTrace(callNode); SkipRecursiveCall(callNode); const RetICFGNode *retNode = callNode->getRetICFGNode(); if (retNode->getSVFStmts().size() > 0) @@ -698,7 +698,7 @@ bool AbstractInterpretation::isDirectCall(const CallICFGNode *callNode) } void AbstractInterpretation::directCallFunPass(const CallICFGNode *callNode) { - AbstractState& as = getConcreteAbsStateFromTrace(callNode); + AbstractState& as = getDenseAbsStateFromTrace(callNode); abstractTrace[callNode] = as; @@ -739,7 +739,7 @@ bool AbstractInterpretation::isIndirectCall(const CallICFGNode *callNode) void AbstractInterpretation::indirectCallFunPass(const CallICFGNode *callNode) { - AbstractState& as = getConcreteAbsStateFromTrace(callNode); + AbstractState& as = getDenseAbsStateFromTrace(callNode); const auto callsiteMaps = svfir->getIndirectCallsites(); NodeID call_id = callsiteMaps.at(callNode); if (!as.inVarToAddrsTable(call_id)) @@ -800,7 +800,7 @@ void AbstractInterpretation::handleCycleWTO(const ICFGCycleWTO*cycle) } // Widening - abstractTrace[cycle_head] = prev_head_state.wideningConcrete(cur_head_state); + abstractTrace[cycle_head] = prev_head_state.wideningDense(cur_head_state); if (abstractTrace[cycle_head] == prev_head_state) { @@ -822,7 +822,7 @@ void AbstractInterpretation::handleCycleWTO(const ICFGCycleWTO*cycle) else if (Options::HandleRecur() == WIDEN_NARROW) { // Widening's fixpoint reached in the widening phase, switch to narrowing - abstractTrace[cycle_head] = prev_head_state.narrowingConcrete(cur_head_state); + abstractTrace[cycle_head] = prev_head_state.narrowingDense(cur_head_state); if (abstractTrace[cycle_head] == prev_head_state) { // Narrowing's fixpoint reached in the narrowing phase, exit loop @@ -840,7 +840,7 @@ void AbstractInterpretation::handleCycleWTO(const ICFGCycleWTO*cycle) else { // Widening's fixpoint reached in the widening phase, switch to narrowing - abstractTrace[cycle_head] = prev_head_state.narrowingConcrete(cur_head_state); + abstractTrace[cycle_head] = prev_head_state.narrowingDense(cur_head_state); if (abstractTrace[cycle_head] == prev_head_state) { // Narrowing's fixpoint reached in the narrowing phase, exit loop @@ -922,7 +922,7 @@ void AbstractInterpretation::handleSVFStatement(const SVFStmt *stmt) void AbstractInterpretation::SkipRecursiveCall(const CallICFGNode *callNode) { - AbstractState& as = getConcreteAbsStateFromTrace(callNode); + AbstractState& as = getDenseAbsStateFromTrace(callNode); const RetICFGNode *retNode = callNode->getRetICFGNode(); if (retNode->getSVFStmts().size() > 0) { @@ -1121,7 +1121,7 @@ void AbstractInterpretation::checkPointAllSet() void AbstractInterpretation::updateStateOnGep(const GepStmt *gep) { - AbstractState& as = getConcreteAbsStateFromTrace(gep->getICFGNode()); + AbstractState& as = getDenseAbsStateFromTrace(gep->getICFGNode()); u32_t rhs = gep->getRHSVarID(); u32_t lhs = gep->getLHSVarID(); IntervalValue offsetPair = as.getElementIndex(gep); @@ -1137,7 +1137,7 @@ void AbstractInterpretation::updateStateOnGep(const GepStmt *gep) void AbstractInterpretation::updateStateOnSelect(const SelectStmt *select) { - AbstractState& as = getConcreteAbsStateFromTrace(select->getICFGNode()); + AbstractState& as = getDenseAbsStateFromTrace(select->getICFGNode()); u32_t res = select->getResID(); u32_t tval = select->getTrueValue()->getId(); u32_t fval = select->getFalseValue()->getId(); @@ -1156,7 +1156,7 @@ void AbstractInterpretation::updateStateOnSelect(const SelectStmt *select) void AbstractInterpretation::updateStateOnPhi(const PhiStmt *phi) { const ICFGNode* icfgNode = phi->getICFGNode(); - AbstractState& as = getConcreteAbsStateFromTrace(icfgNode); + AbstractState& as = getDenseAbsStateFromTrace(icfgNode); u32_t res = phi->getResID(); AbstractValue rhs; for (u32_t i = 0; i < phi->getOpVarNum(); i++) @@ -1166,7 +1166,7 @@ void AbstractInterpretation::updateStateOnPhi(const PhiStmt *phi) if (hasAbsStateFromTrace(opICFGNode)) { AbstractState tmpEs = abstractTrace[opICFGNode]; - AbstractState& opAs = getConcreteAbsStateFromTrace(opICFGNode); + AbstractState& opAs = getDenseAbsStateFromTrace(opICFGNode); const ICFGEdge* edge = icfg->getICFGEdge(opICFGNode, icfgNode, ICFGEdge::IntraCF); // if IntraEdge, check the condition, if it is feasible, join the value // if IntraEdge but not conditional edge, join the value @@ -1194,7 +1194,7 @@ void AbstractInterpretation::updateStateOnPhi(const PhiStmt *phi) void AbstractInterpretation::updateStateOnCall(const CallPE *callPE) { - AbstractState& as = getConcreteAbsStateFromTrace(callPE->getICFGNode()); + AbstractState& as = getDenseAbsStateFromTrace(callPE->getICFGNode()); NodeID lhs = callPE->getLHSVarID(); NodeID rhs = callPE->getRHSVarID(); as[lhs] = as[rhs]; @@ -1202,7 +1202,7 @@ void AbstractInterpretation::updateStateOnCall(const CallPE *callPE) void AbstractInterpretation::updateStateOnRet(const RetPE *retPE) { - AbstractState& as = getConcreteAbsStateFromTrace(retPE->getICFGNode()); + AbstractState& as = getDenseAbsStateFromTrace(retPE->getICFGNode()); NodeID lhs = retPE->getLHSVarID(); NodeID rhs = retPE->getRHSVarID(); as[lhs] = as[rhs]; @@ -1211,7 +1211,7 @@ void AbstractInterpretation::updateStateOnRet(const RetPE *retPE) void AbstractInterpretation::updateStateOnAddr(const AddrStmt *addr) { - AbstractState& as = getConcreteAbsStateFromTrace(addr->getICFGNode()); + AbstractState& as = getDenseAbsStateFromTrace(addr->getICFGNode()); as.initObjVar(SVFUtil::cast(addr->getRHSVar())); if (addr->getRHSVar()->getType()->getKind() == SVFType::SVFIntegerTy) as[addr->getRHSVarID()].getInterval().meet_with(utils->getRangeLimitFromType(addr->getRHSVar()->getType())); @@ -1225,7 +1225,7 @@ void AbstractInterpretation::updateStateOnBinary(const BinaryOPStmt *binary) /// You are only required to handle integer predicates, including Add, FAdd, Sub, FSub, Mul, FMul, SDiv, FDiv, UDiv, /// SRem, FRem, URem, Xor, And, Or, AShr, Shl, LShr const ICFGNode* node = binary->getICFGNode(); - AbstractState& as = getConcreteAbsStateFromTrace(node); + AbstractState& as = getDenseAbsStateFromTrace(node); u32_t op0 = binary->getOpVarID(0); u32_t op1 = binary->getOpVarID(1); u32_t res = binary->getResID(); @@ -1283,7 +1283,7 @@ void AbstractInterpretation::updateStateOnBinary(const BinaryOPStmt *binary) void AbstractInterpretation::updateStateOnCmp(const CmpStmt *cmp) { - AbstractState& as = getConcreteAbsStateFromTrace(cmp->getICFGNode()); + AbstractState& as = getDenseAbsStateFromTrace(cmp->getICFGNode()); u32_t op0 = cmp->getOpVarID(0); u32_t op1 = cmp->getOpVarID(1); // if it is address @@ -1498,7 +1498,7 @@ void AbstractInterpretation::updateStateOnCmp(const CmpStmt *cmp) void AbstractInterpretation::updateStateOnLoad(const LoadStmt *load) { - AbstractState& as = getConcreteAbsStateFromTrace(load->getICFGNode()); + AbstractState& as = getDenseAbsStateFromTrace(load->getICFGNode()); u32_t rhs = load->getRHSVarID(); u32_t lhs = load->getLHSVarID(); as[lhs] = as.loadValue(rhs); @@ -1506,7 +1506,7 @@ void AbstractInterpretation::updateStateOnLoad(const LoadStmt *load) void AbstractInterpretation::updateStateOnStore(const StoreStmt *store) { - AbstractState& as = getConcreteAbsStateFromTrace(store->getICFGNode()); + AbstractState& as = getDenseAbsStateFromTrace(store->getICFGNode()); u32_t rhs = store->getRHSVarID(); u32_t lhs = store->getLHSVarID(); as.storeValue(lhs, as[rhs]); @@ -1610,7 +1610,7 @@ void AbstractInterpretation::updateStateOnCopy(const CopyStmt *copy) } }; - AbstractState& as = getConcreteAbsStateFromTrace(copy->getICFGNode()); + AbstractState& as = getDenseAbsStateFromTrace(copy->getICFGNode()); u32_t lhs = copy->getLHSVarID(); u32_t rhs = copy->getRHSVarID(); From 20fc6e3f471354d63a60eba8fd640e0c8b96bb53 Mon Sep 17 00:00:00 2001 From: bjjwwang Date: Sun, 18 Jan 2026 21:37:50 +1100 Subject: [PATCH 3/9] TODO: implement use-sparse --- svf/include/Util/Options.h | 4 ++-- svf/lib/Util/Options.cpp | 5 +++-- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/svf/include/Util/Options.h b/svf/include/Util/Options.h index 946251aa0..5ce8cfe14 100644 --- a/svf/include/Util/Options.h +++ b/svf/include/Util/Options.h @@ -243,8 +243,8 @@ class Options static const Option WidenDelay; /// recursion handling mode, Default: TOP static const OptionMap HandleRecur; - /// Use sparse abstract state representation (experimental) - static const Option UseSparseState; + /// Use sparse abstract state representation (TODO: to implement) + //static const Option UseSparseState; /// the max time consumptions (seconds). Default: 4 hours 14400s static const Option Timeout; /// bug info output file, Default: output.db diff --git a/svf/lib/Util/Options.cpp b/svf/lib/Util/Options.cpp index 2db5f0d2d..8fe5b265a 100644 --- a/svf/lib/Util/Options.cpp +++ b/svf/lib/Util/Options.cpp @@ -802,8 +802,9 @@ const OptionMap Options::HandleRecur( } } ); -const Option Options::UseSparseState( - "use-sparse", "Use sparse abstract state representation (experimental)", false); +// TODO: to implement +// const Option Options::UseSparseState( +// "use-sparse", "Use sparse abstract state representation (experimental)", false); const Option Options::Timeout( "timeout", "time out (seconds), set -1 (no timeout), default 14400s",14400); const Option Options::OutputName( From 5fce1e961869c3bf602bf986e43fcb41ae529851 Mon Sep 17 00:00:00 2001 From: bjjwwang Date: Sun, 18 Jan 2026 21:46:43 +1100 Subject: [PATCH 4/9] remove option use-sparse temperarily --- svf/include/AE/Svfexe/AbstractInterpretation.h | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/svf/include/AE/Svfexe/AbstractInterpretation.h b/svf/include/AE/Svfexe/AbstractInterpretation.h index 0b6d65b53..76a070295 100644 --- a/svf/include/AE/Svfexe/AbstractInterpretation.h +++ b/svf/include/AE/Svfexe/AbstractInterpretation.h @@ -326,11 +326,7 @@ class AbstractInterpretation /// Currently returns DenseAbstractState; will support SparseAbstractState in the future std::unique_ptr createState() { - if (Options::UseSparseState()) - { - // TODO: Return SparseAbstractState when implemented - assert(false && "SparseAbstractState not implemented yet. Use -use-sparse=false"); - } + // TODO: if (Options::UseSparseState()) return std::make_unique(); } From 630680d994240feea59faa87a4b7df27d99ae782 Mon Sep 17 00:00:00 2001 From: bjjwwang Date: Thu, 22 Jan 2026 23:12:34 +1100 Subject: [PATCH 5/9] remove redundant functions; rename IAbstractState; --- svf-llvm/tools/AE/ae.cpp | 176 +++++----- svf/include/AE/Core/AbstractState.h | 58 ++-- svf/include/AE/Core/AddressValue.h | 2 +- svf/include/AE/Core/IAbstractState.h | 26 +- svf/include/AE/Core/RelationSolver.h | 16 +- svf/include/AE/Svfexe/AEDetector.h | 147 ++++---- svf/include/AE/Svfexe/AbsExtAPI.h | 14 +- .../AE/Svfexe/AbstractInterpretation.h | 18 +- svf/lib/AE/Core/AbstractState.cpp | 70 ++-- svf/lib/AE/Core/RelationSolver.cpp | 44 +-- svf/lib/AE/Svfexe/AEDetector.cpp | 315 ++++++++++-------- svf/lib/AE/Svfexe/AbsExtAPI.cpp | 46 +-- svf/lib/AE/Svfexe/AbstractInterpretation.cpp | 89 +++-- 13 files changed, 545 insertions(+), 476 deletions(-) diff --git a/svf-llvm/tools/AE/ae.cpp b/svf-llvm/tools/AE/ae.cpp index 5df194d2a..d634e7179 100644 --- a/svf-llvm/tools/AE/ae.cpp +++ b/svf-llvm/tools/AE/ae.cpp @@ -68,11 +68,11 @@ class SymblicAbstractionTest outs() << "hello print\n"; } - AbstractState RSY_time(AbstractState& inv, const Z3Expr& phi, + AbstractStateImpl RSY_time(AbstractStateImpl& inv, const Z3Expr& phi, RelationSolver& rs) { auto start_time = std::chrono::high_resolution_clock::now(); - AbstractState resRSY = rs.RSY(inv, phi); + AbstractStateImpl resRSY = rs.RSY(inv, phi); auto end_time = std::chrono::high_resolution_clock::now(); auto duration = std::chrono::duration_cast( end_time - start_time); @@ -80,11 +80,11 @@ class SymblicAbstractionTest << " microseconds\n"; return resRSY; } - AbstractState Bilateral_time(AbstractState& inv, const Z3Expr& phi, + AbstractStateImpl Bilateral_time(AbstractStateImpl& inv, const Z3Expr& phi, RelationSolver& rs) { auto start_time = std::chrono::high_resolution_clock::now(); - AbstractState resBilateral = rs.bilateral(inv, phi); + AbstractStateImpl resBilateral = rs.bilateral(inv, phi); auto end_time = std::chrono::high_resolution_clock::now(); auto duration = std::chrono::duration_cast( end_time - start_time); @@ -92,11 +92,11 @@ class SymblicAbstractionTest << " microseconds\n"; return resBilateral; } - AbstractState BS_time(AbstractState& inv, const Z3Expr& phi, + AbstractStateImpl BS_time(AbstractStateImpl& inv, const Z3Expr& phi, RelationSolver& rs) { auto start_time = std::chrono::high_resolution_clock::now(); - AbstractState resBS = rs.BS(inv, phi); + AbstractStateImpl resBS = rs.BS(inv, phi); auto end_time = std::chrono::high_resolution_clock::now(); auto duration = std::chrono::duration_cast( end_time - start_time); @@ -108,7 +108,7 @@ class SymblicAbstractionTest void testRelExeState1_1() { outs() << sucMsg("\t SUCCESS :") << "test1_1 start\n"; - AbstractState itv; + AbstractStateImpl itv; RelExeState relation; // var0 := [0, 1]; itv[0] = IntervalValue(0, 1); @@ -121,28 +121,28 @@ class SymblicAbstractionTest Set res; relation.extractSubVars(relation[1], res); assert(res == Set({0, 1}) && "inconsistency occurs"); - AbstractState inv = itv.sliceState(res); + AbstractStateImpl inv = itv.sliceState(res); RelationSolver rs; const Z3Expr& relExpr = relation[1]; const Z3Expr& initExpr = rs.gamma_hat(inv); const Z3Expr& phi = (relExpr && initExpr).simplify(); - AbstractState resRSY = rs.RSY(inv, phi); - AbstractState resBilateral = rs.bilateral(inv, phi); - AbstractState resBS = rs.BS(inv, phi); + AbstractStateImpl resRSY = rs.RSY(inv, phi); + AbstractStateImpl resBilateral = rs.bilateral(inv, phi); + AbstractStateImpl resBS = rs.BS(inv, phi); // 0:[0,1] 1:[1,2] assert(resRSY == resBS && resBS == resBilateral && "inconsistency occurs"); for (auto r : resRSY.getVarToVal()) { outs() << r.first << " " << r.second.getInterval() << "\n"; } - AbstractState::VarToAbsValMap intendedRes = {{0, IntervalValue(0, 1)}, {1, IntervalValue(1, 2)}}; - assert(AbstractState::eqVarToValMap(resBS.getVarToVal(), intendedRes) && "inconsistency occurs"); + AbstractStateImpl::VarToAbsValMap intendedRes = {{0, IntervalValue(0, 1)}, {1, IntervalValue(1, 2)}}; + assert(AbstractStateImpl::eqVarToValMap(resBS.getVarToVal(), intendedRes) && "inconsistency occurs"); } void testRelExeState1_2() { outs() << "test1_2 start\n"; - AbstractState itv; + AbstractStateImpl itv; RelExeState relation; // var0 := [0, 1]; relation[0] = getContext().int_const("0"); @@ -156,28 +156,28 @@ class SymblicAbstractionTest Set res; relation.extractSubVars(relation[1], res); assert(res == Set({0, 1}) && "inconsistency occurs"); - AbstractState inv = itv.sliceState(res); + AbstractStateImpl inv = itv.sliceState(res); RelationSolver rs; const Z3Expr& relExpr = relation[1]; const Z3Expr& initExpr = rs.gamma_hat(inv); const Z3Expr& phi = (relExpr && initExpr).simplify(); - AbstractState resRSY = rs.RSY(inv, phi); - AbstractState resBilateral = rs.bilateral(inv, phi); - AbstractState resBS = rs.BS(inv, phi); + AbstractStateImpl resRSY = rs.RSY(inv, phi); + AbstractStateImpl resBilateral = rs.bilateral(inv, phi); + AbstractStateImpl resBS = rs.BS(inv, phi); // 0:[0,1] 1:[0,2] assert(resRSY == resBS && resBS == resBilateral && "inconsistency occurs"); for (auto r : resRSY.getVarToVal()) { outs() << r.first << " " << r.second.getInterval() << "\n"; } - AbstractState::VarToAbsValMap intendedRes = {{0, IntervalValue(0, 1)}, {1, IntervalValue(0, 2)}}; - assert(AbstractState::eqVarToValMap(resBS.getVarToVal(), intendedRes) && "inconsistency occurs"); + AbstractStateImpl::VarToAbsValMap intendedRes = {{0, IntervalValue(0, 1)}, {1, IntervalValue(0, 2)}}; + assert(AbstractStateImpl::eqVarToValMap(resBS.getVarToVal(), intendedRes) && "inconsistency occurs"); } void testRelExeState2_1() { outs() << "test2_1 start\n"; - AbstractState itv; + AbstractStateImpl itv; RelExeState relation; // var0 := [0, 10]; relation[0] = getContext().int_const("0"); @@ -194,14 +194,14 @@ class SymblicAbstractionTest Set res; relation.extractSubVars(relation[2], res); assert(res == Set({0, 1, 2}) && "inconsistency occurs"); - AbstractState inv = itv.sliceState(res); + AbstractStateImpl inv = itv.sliceState(res); RelationSolver rs; const Z3Expr& relExpr = relation[2] && relation[1]; const Z3Expr& initExpr = rs.gamma_hat(inv); const Z3Expr& phi = (relExpr && initExpr).simplify(); - AbstractState resRSY = rs.RSY(inv, phi); - AbstractState resBilateral = rs.bilateral(inv, phi); - AbstractState resBS = rs.BS(inv, phi); + AbstractStateImpl resRSY = rs.RSY(inv, phi); + AbstractStateImpl resBilateral = rs.bilateral(inv, phi); + AbstractStateImpl resBS = rs.BS(inv, phi); // 0:[0,10] 1:[0,10] 2:[0,0] assert(resRSY == resBS && resBS == resBilateral && "inconsistency occurs"); for (auto r : resRSY.getVarToVal()) @@ -209,17 +209,17 @@ class SymblicAbstractionTest outs() << r.first << " " << r.second.getInterval() << "\n"; } // ground truth - AbstractState::VarToAbsValMap intendedRes = {{0, IntervalValue(0, 10)}, + AbstractStateImpl::VarToAbsValMap intendedRes = {{0, IntervalValue(0, 10)}, {1, IntervalValue(0, 10)}, {2, IntervalValue(0, 0)} }; - assert(AbstractState::eqVarToValMap(resBS.getVarToVal(), intendedRes) && "inconsistency occurs"); + assert(AbstractStateImpl::eqVarToValMap(resBS.getVarToVal(), intendedRes) && "inconsistency occurs"); } void testRelExeState2_2() { outs() << "test2_2 start\n"; - AbstractState itv; + AbstractStateImpl itv; RelExeState relation; // var0 := [0, 100]; relation[0] = getContext().int_const("0"); @@ -237,14 +237,14 @@ class SymblicAbstractionTest Set res; relation.extractSubVars(relation[2], res); assert(res == Set({0, 1, 2}) && "inconsistency occurs"); - AbstractState inv = itv.sliceState(res); + AbstractStateImpl inv = itv.sliceState(res); RelationSolver rs; const Z3Expr& relExpr = relation[2] && relation[1]; const Z3Expr& initExpr = rs.gamma_hat(inv); const Z3Expr& phi = (relExpr && initExpr).simplify(); - AbstractState resRSY = rs.RSY(inv, phi); - AbstractState resBilateral = rs.bilateral(inv, phi); - AbstractState resBS = rs.BS(inv, phi); + AbstractStateImpl resRSY = rs.RSY(inv, phi); + AbstractStateImpl resBilateral = rs.bilateral(inv, phi); + AbstractStateImpl resBS = rs.BS(inv, phi); // 0:[0,100] 1:[0,100] 2:[0,0] assert(resRSY == resBS && resBS == resBilateral && "inconsistency occurs"); for (auto r : resRSY.getVarToVal()) @@ -252,17 +252,17 @@ class SymblicAbstractionTest outs() << r.first << " " << r.second.getInterval() << "\n"; } // ground truth - AbstractState::VarToAbsValMap intendedRes = {{0, IntervalValue(0, 100)}, + AbstractStateImpl::VarToAbsValMap intendedRes = {{0, IntervalValue(0, 100)}, {1, IntervalValue(0, 100)}, {2, IntervalValue(0, 0)} }; - assert(AbstractState::eqVarToValMap(resBS.getVarToVal(), intendedRes) && "inconsistency occurs"); + assert(AbstractStateImpl::eqVarToValMap(resBS.getVarToVal(), intendedRes) && "inconsistency occurs"); } void testRelExeState2_3() { outs() << "test2_3 start\n"; - AbstractState itv; + AbstractStateImpl itv; RelExeState relation; // var0 := [0, 1000]; relation[0] = getContext().int_const("0"); @@ -280,14 +280,14 @@ class SymblicAbstractionTest Set res; relation.extractSubVars(relation[2], res); assert(res == Set({0, 1, 2}) && "inconsistency occurs"); - AbstractState inv = itv.sliceState(res); + AbstractStateImpl inv = itv.sliceState(res); RelationSolver rs; const Z3Expr& relExpr = relation[2] && relation[1]; const Z3Expr& initExpr = rs.gamma_hat(inv); const Z3Expr& phi = (relExpr && initExpr).simplify(); - AbstractState resRSY = rs.RSY(inv, phi); - AbstractState resBilateral = rs.bilateral(inv, phi); - AbstractState resBS = rs.BS(inv, phi); + AbstractStateImpl resRSY = rs.RSY(inv, phi); + AbstractStateImpl resBilateral = rs.bilateral(inv, phi); + AbstractStateImpl resBS = rs.BS(inv, phi); // 0:[0,1000] 1:[0,1000] 2:[0,0] assert(resRSY == resBS && resBS == resBilateral && "inconsistency occurs"); for (auto r : resRSY.getVarToVal()) @@ -295,17 +295,17 @@ class SymblicAbstractionTest outs() << r.first << " " << r.second.getInterval() << "\n"; } // ground truth - AbstractState::VarToAbsValMap intendedRes = {{0, IntervalValue(0, 1000)}, + AbstractStateImpl::VarToAbsValMap intendedRes = {{0, IntervalValue(0, 1000)}, {1, IntervalValue(0, 1000)}, {2, IntervalValue(0, 0)} }; - assert(AbstractState::eqVarToValMap(resBS.getVarToVal(), intendedRes) && "inconsistency occurs"); + assert(AbstractStateImpl::eqVarToValMap(resBS.getVarToVal(), intendedRes) && "inconsistency occurs"); } void testRelExeState2_4() { outs() << "test2_4 start\n"; - AbstractState itv; + AbstractStateImpl itv; RelExeState relation; // var0 := [0, 10000]; relation[0] = getContext().int_const("0"); @@ -323,14 +323,14 @@ class SymblicAbstractionTest Set res; relation.extractSubVars(relation[2], res); assert(res == Set({0, 1, 2}) && "inconsistency occurs"); - AbstractState inv = itv.sliceState(res); + AbstractStateImpl inv = itv.sliceState(res); RelationSolver rs; const Z3Expr& relExpr = relation[2] && relation[1]; const Z3Expr& initExpr = rs.gamma_hat(inv); const Z3Expr& phi = (relExpr && initExpr).simplify(); - AbstractState resRSY = RSY_time(inv, phi, rs); - AbstractState resBilateral = Bilateral_time(inv, phi, rs); - AbstractState resBS = BS_time(inv, phi, rs); + AbstractStateImpl resRSY = RSY_time(inv, phi, rs); + AbstractStateImpl resBilateral = Bilateral_time(inv, phi, rs); + AbstractStateImpl resBS = BS_time(inv, phi, rs); // 0:[0,10000] 1:[0,10000] 2:[0,0] assert(resRSY == resBS && resBS == resBilateral && "inconsistency occurs"); for (auto r : resRSY.getVarToVal()) @@ -338,17 +338,17 @@ class SymblicAbstractionTest outs() << r.first << " " << r.second.getInterval() << "\n"; } // ground truth - AbstractState::VarToAbsValMap intendedRes = {{0, IntervalValue(0, 10000)}, + AbstractStateImpl::VarToAbsValMap intendedRes = {{0, IntervalValue(0, 10000)}, {1, IntervalValue(0, 10000)}, {2, IntervalValue(0, 0)} }; - assert(AbstractState::eqVarToValMap(resBS.getVarToVal(), intendedRes) && "inconsistency occurs"); + assert(AbstractStateImpl::eqVarToValMap(resBS.getVarToVal(), intendedRes) && "inconsistency occurs"); } void testRelExeState2_5() { outs() << "test2_5 start\n"; - AbstractState itv; + AbstractStateImpl itv; RelExeState relation; // var0 := [0, 100000]; relation[0] = getContext().int_const("0"); @@ -366,14 +366,14 @@ class SymblicAbstractionTest Set res; relation.extractSubVars(relation[2], res); assert(res == Set({0, 1, 2}) && "inconsistency occurs"); - AbstractState inv = itv.sliceState(res); + AbstractStateImpl inv = itv.sliceState(res); RelationSolver rs; const Z3Expr& relExpr = relation[2] && relation[1]; const Z3Expr& initExpr = rs.gamma_hat(inv); const Z3Expr& phi = (relExpr && initExpr).simplify(); - AbstractState resRSY = RSY_time(inv, phi, rs); - AbstractState resBilateral = Bilateral_time(inv, phi, rs); - AbstractState resBS = BS_time(inv, phi, rs); + AbstractStateImpl resRSY = RSY_time(inv, phi, rs); + AbstractStateImpl resBilateral = Bilateral_time(inv, phi, rs); + AbstractStateImpl resBS = BS_time(inv, phi, rs); // 0:[0,100000] 1:[0,100000] 2:[0,0] assert(resRSY == resBS && resBS == resBilateral && "inconsistency occurs"); for (auto r : resRSY.getVarToVal()) @@ -381,17 +381,17 @@ class SymblicAbstractionTest outs() << r.first << " " << r.second.getInterval() << "\n"; } // ground truth - AbstractState::VarToAbsValMap intendedRes = {{0, IntervalValue(0, 100000)}, + AbstractStateImpl::VarToAbsValMap intendedRes = {{0, IntervalValue(0, 100000)}, {1, IntervalValue(0, 100000)}, {2, IntervalValue(0, 0)} }; - assert(AbstractState::eqVarToValMap(resBS.getVarToVal(), intendedRes) && "inconsistency occurs"); + assert(AbstractStateImpl::eqVarToValMap(resBS.getVarToVal(), intendedRes) && "inconsistency occurs"); } void testRelExeState3_1() { outs() << "test3_1 start\n"; - AbstractState itv; + AbstractStateImpl itv; RelExeState relation; // var0 := [1, 10]; relation[0] = getContext().int_const("0"); @@ -408,14 +408,14 @@ class SymblicAbstractionTest Set res; relation.extractSubVars(relation[2], res); assert(res == Set({0, 1, 2}) && "inconsistency occurs"); - AbstractState inv = itv.sliceState(res); + AbstractStateImpl inv = itv.sliceState(res); RelationSolver rs; const Z3Expr& relExpr = relation[2] && relation[1]; const Z3Expr& initExpr = rs.gamma_hat(inv); const Z3Expr& phi = (relExpr && initExpr).simplify(); - AbstractState resRSY = rs.RSY(inv, phi); - AbstractState resBilateral = rs.bilateral(inv, phi); - AbstractState resBS = rs.BS(inv, phi); + AbstractStateImpl resRSY = rs.RSY(inv, phi); + AbstractStateImpl resBilateral = rs.bilateral(inv, phi); + AbstractStateImpl resBS = rs.BS(inv, phi); // 0:[1,10] 1:[1,10] 2:[1,1] assert(resRSY == resBS && resBS == resBilateral && "inconsistency occurs"); for (auto r : resRSY.getVarToVal()) @@ -423,17 +423,17 @@ class SymblicAbstractionTest outs() << r.first << " " << r.second.getInterval() << "\n"; } // ground truth - AbstractState::VarToAbsValMap intendedRes = {{0, IntervalValue(1, 10)}, + AbstractStateImpl::VarToAbsValMap intendedRes = {{0, IntervalValue(1, 10)}, {1, IntervalValue(1, 10)}, {2, IntervalValue(1, 1)} }; - assert(AbstractState::eqVarToValMap(resBS.getVarToVal(), intendedRes) && "inconsistency occurs"); + assert(AbstractStateImpl::eqVarToValMap(resBS.getVarToVal(), intendedRes) && "inconsistency occurs"); } void testRelExeState3_2() { outs() << "test3_2 start\n"; - AbstractState itv; + AbstractStateImpl itv; RelExeState relation; // var0 := [1, 1000]; relation[0] = getContext().int_const("0"); @@ -450,14 +450,14 @@ class SymblicAbstractionTest Set res; relation.extractSubVars(relation[2], res); assert(res == Set({0, 1, 2}) && "inconsistency occurs"); - AbstractState inv = itv.sliceState(res); + AbstractStateImpl inv = itv.sliceState(res); RelationSolver rs; const Z3Expr& relExpr = relation[2] && relation[1]; const Z3Expr& initExpr = rs.gamma_hat(inv); const Z3Expr& phi = (relExpr && initExpr).simplify(); - AbstractState resRSY = rs.RSY(inv, phi); - AbstractState resBilateral = rs.bilateral(inv, phi); - AbstractState resBS = rs.BS(inv, phi); + AbstractStateImpl resRSY = rs.RSY(inv, phi); + AbstractStateImpl resBilateral = rs.bilateral(inv, phi); + AbstractStateImpl resBS = rs.BS(inv, phi); // 0:[1,1000] 1:[1,1000] 2:[1,1] assert(resRSY == resBS && resBS == resBilateral && "inconsistency occurs"); for (auto r : resRSY.getVarToVal()) @@ -465,17 +465,17 @@ class SymblicAbstractionTest outs() << r.first << " " << r.second.getInterval() << "\n"; } // ground truth - AbstractState::VarToAbsValMap intendedRes = {{0, IntervalValue(1, 1000)}, + AbstractStateImpl::VarToAbsValMap intendedRes = {{0, IntervalValue(1, 1000)}, {1, IntervalValue(1, 1000)}, {2, IntervalValue(1, 1)} }; - assert(AbstractState::eqVarToValMap(resBS.getVarToVal(), intendedRes) && "inconsistency occurs"); + assert(AbstractStateImpl::eqVarToValMap(resBS.getVarToVal(), intendedRes) && "inconsistency occurs"); } void testRelExeState3_3() { outs() << "test3_3 start\n"; - AbstractState itv; + AbstractStateImpl itv; RelExeState relation; // var0 := [1, 10000]; relation[0] = getContext().int_const("0"); @@ -492,14 +492,14 @@ class SymblicAbstractionTest Set res; relation.extractSubVars(relation[2], res); assert(res == Set({0, 1, 2}) && "inconsistency occurs"); - AbstractState inv = itv.sliceState(res); + AbstractStateImpl inv = itv.sliceState(res); RelationSolver rs; const Z3Expr& relExpr = relation[2] && relation[1]; const Z3Expr& initExpr = rs.gamma_hat(inv); const Z3Expr& phi = (relExpr && initExpr).simplify(); - AbstractState resRSY = RSY_time(inv, phi, rs); - AbstractState resBilateral = Bilateral_time(inv, phi, rs); - AbstractState resBS = BS_time(inv, phi, rs); + AbstractStateImpl resRSY = RSY_time(inv, phi, rs); + AbstractStateImpl resBilateral = Bilateral_time(inv, phi, rs); + AbstractStateImpl resBS = BS_time(inv, phi, rs); // 0:[1,10000] 1:[1,10000] 2:[1,1] assert(resRSY == resBS && resBS == resBilateral && "inconsistency occurs"); for (auto r : resRSY.getVarToVal()) @@ -507,7 +507,7 @@ class SymblicAbstractionTest outs() << r.first << " " << r.second.getInterval() << "\n"; } // ground truth - AbstractState::VarToAbsValMap intendedRes = {{0, IntervalValue(1, 10000)}, + AbstractStateImpl::VarToAbsValMap intendedRes = {{0, IntervalValue(1, 10000)}, {1, IntervalValue(1, 10000)}, {2, IntervalValue(1, 1)} }; @@ -516,7 +516,7 @@ class SymblicAbstractionTest void testRelExeState3_4() { outs() << "test3_4 start\n"; - AbstractState itv; + AbstractStateImpl itv; RelExeState relation; // var0 := [1, 100000]; relation[0] = getContext().int_const("0"); @@ -533,14 +533,14 @@ class SymblicAbstractionTest Set res; relation.extractSubVars(relation[2], res); assert(res == Set({0, 1, 2}) && "inconsistency occurs"); - AbstractState inv = itv.sliceState(res); + AbstractStateImpl inv = itv.sliceState(res); RelationSolver rs; const Z3Expr& relExpr = relation[2] && relation[1]; const Z3Expr& initExpr = rs.gamma_hat(inv); const Z3Expr& phi = (relExpr && initExpr).simplify(); - AbstractState resRSY = RSY_time(inv, phi, rs); - AbstractState resBilateral = Bilateral_time(inv, phi, rs); - AbstractState resBS = BS_time(inv, phi, rs); + AbstractStateImpl resRSY = RSY_time(inv, phi, rs); + AbstractStateImpl resBilateral = Bilateral_time(inv, phi, rs); + AbstractStateImpl resBS = BS_time(inv, phi, rs); // 0:[1,100000] 1:[1,100000] 2:[1,1] assert(resRSY == resBS && resBS == resBilateral && "inconsistency occurs"); for (auto r : resRSY.getVarToVal()) @@ -548,17 +548,17 @@ class SymblicAbstractionTest outs() << r.first << " " << r.second.getInterval() << "\n"; } // ground truth - AbstractState::VarToAbsValMap intendedRes = {{0, IntervalValue(1, 100000)}, + AbstractStateImpl::VarToAbsValMap intendedRes = {{0, IntervalValue(1, 100000)}, {1, IntervalValue(1, 100000)}, {2, IntervalValue(1, 1)} }; - assert(AbstractState::eqVarToValMap(resBS.getVarToVal(), intendedRes) && "inconsistency occurs"); + assert(AbstractStateImpl::eqVarToValMap(resBS.getVarToVal(), intendedRes) && "inconsistency occurs"); } void testRelExeState4_1() { outs() << "test4_1 start\n"; - AbstractState itv; + AbstractStateImpl itv; RelExeState relation; // var0 := [0, 10]; relation[0] = getContext().int_const("0"); @@ -575,7 +575,7 @@ class SymblicAbstractionTest Set res; relation.extractSubVars(relation[2], res); assert(res == Set({0, 1, 2}) && "inconsistency occurs"); - AbstractState inv = itv.sliceState(res); + AbstractStateImpl inv = itv.sliceState(res); RelationSolver rs; const Z3Expr& relExpr = relation[2] && relation[1]; const Z3Expr& initExpr = rs.gamma_hat(inv); @@ -584,7 +584,7 @@ class SymblicAbstractionTest outs() << "rsy done\n"; // IntervalExeState resBilateral = rs.bilateral(inv, phi); outs() << "bilateral done\n"; - AbstractState resBS = rs.BS(inv, phi); + AbstractStateImpl resBS = rs.BS(inv, phi); outs() << "bs done\n"; // 0:[0,10] 1:[0,10] 2:[-00,+00] // assert(resRSY == resBS && resBS == resBilateral); @@ -593,11 +593,11 @@ class SymblicAbstractionTest outs() << r.first << " " << r.second.getInterval() << "\n"; } // ground truth - AbstractState::VarToAbsValMap intendedRes = {{0, IntervalValue(0, 10)}, + AbstractStateImpl::VarToAbsValMap intendedRes = {{0, IntervalValue(0, 10)}, {1, IntervalValue(0, 10)}, {2, IntervalValue(0, 10)} }; - assert(AbstractState::eqVarToValMap(resBS.getVarToVal(), intendedRes) && "inconsistency occurs"); + assert(AbstractStateImpl::eqVarToValMap(resBS.getVarToVal(), intendedRes) && "inconsistency occurs"); } void testsValidation() @@ -827,7 +827,7 @@ class AETest void testAbsState() { - AbstractState as; + AbstractStateImpl as; as[1] = IntervalValue(1, 3); as[2] = IntervalValue(2, 7); as[3] = AddressValue(0x7f000007); diff --git a/svf/include/AE/Core/AbstractState.h b/svf/include/AE/Core/AbstractState.h index 38b6b65fe..cd605dd0b 100644 --- a/svf/include/AE/Core/AbstractState.h +++ b/svf/include/AE/Core/AbstractState.h @@ -56,7 +56,7 @@ namespace SVF { -class AbstractState : public IAbstractState +class AbstractStateImpl : public AbstractState { friend class SVFIR2AbsState; friend class RelationSolver; @@ -68,19 +68,19 @@ class AbstractState : public IAbstractState public: /// default constructor - AbstractState() + AbstractStateImpl() { } - AbstractState(VarToAbsValMap&_varToValMap, AddrToAbsValMap&_locToValMap) : _varToAbsVal(_varToValMap), _addrToAbsVal(_locToValMap) {} + AbstractStateImpl(VarToAbsValMap&_varToValMap, AddrToAbsValMap&_locToValMap) : _varToAbsVal(_varToValMap), _addrToAbsVal(_locToValMap) {} /// copy constructor - AbstractState(const AbstractState&rhs) : _freedAddrs(rhs._freedAddrs), _varToAbsVal(rhs.getVarToVal()), _addrToAbsVal(rhs.getLocToVal()) + AbstractStateImpl(const AbstractStateImpl&rhs) : _freedAddrs(rhs._freedAddrs), _varToAbsVal(rhs.getVarToVal()), _addrToAbsVal(rhs.getLocToVal()) { } - virtual ~AbstractState() = default; + virtual ~AbstractStateImpl() = default; // getGepObjAddrs AddressValue getGepObjAddrs(u32_t pointer, IntervalValue offset) override; @@ -118,7 +118,7 @@ class AbstractState : public IAbstractState return _freedAddrs.count(addr) ? AddressValue::getInternalID(InvalidMemAddr) : AddressValue::getInternalID(addr); } - AbstractState&operator=(const AbstractState&rhs) + AbstractStateImpl&operator=(const AbstractStateImpl&rhs) { if (rhs != *this) { @@ -130,14 +130,14 @@ class AbstractState : public IAbstractState } /// move constructor - AbstractState(AbstractState&&rhs) : _varToAbsVal(std::move(rhs._varToAbsVal)), + AbstractStateImpl(AbstractStateImpl&&rhs) : _varToAbsVal(std::move(rhs._varToAbsVal)), _addrToAbsVal(std::move(rhs._addrToAbsVal)) { } /// operator= move constructor - AbstractState&operator=(AbstractState&&rhs) + AbstractStateImpl&operator=(AbstractStateImpl&&rhs) { if (&rhs != this) { @@ -149,9 +149,9 @@ class AbstractState : public IAbstractState } /// Set all value bottom - AbstractState bottom() const + AbstractStateImpl bottom() const { - AbstractState inv = *this; + AbstractStateImpl inv = *this; for (auto &item: inv._varToAbsVal) { if (item.second.isInterval()) @@ -161,9 +161,9 @@ class AbstractState : public IAbstractState } /// Set all value top - AbstractState top() const + AbstractStateImpl top() const { - AbstractState inv = *this; + AbstractStateImpl inv = *this; for (auto &item: inv._varToAbsVal) { if (item.second.isInterval()) @@ -173,9 +173,9 @@ class AbstractState : public IAbstractState } /// Copy some values and return a new IntervalExeState - AbstractState sliceState(Set &sl) + AbstractStateImpl sliceState(Set &sl) { - AbstractState inv; + AbstractStateImpl inv; for (u32_t id: sl) { inv._varToAbsVal[id] = _varToAbsVal[id]; @@ -281,27 +281,27 @@ class AbstractState : public IAbstractState public: /// domain widen with other, and return the widened domain (interface version) - std::unique_ptr widening(const IAbstractState& other) const override; + std::unique_ptr widening(const AbstractState& other) const override; /// domain narrow with other, and return the narrowed domain (interface version) - std::unique_ptr narrowing(const IAbstractState& other) const override; + std::unique_ptr narrowing(const AbstractState& other) const override; - /// Dense widening that returns AbstractState (for internal use and backward compatibility) - AbstractState wideningDense(const AbstractState& other) const; + /// Widening operation - returns widened state + AbstractStateImpl widening(const AbstractStateImpl& other) const; - /// Dense narrowing that returns AbstractState (for internal use and backward compatibility) - AbstractState narrowingDense(const AbstractState& other) const; + /// Narrowing operation - returns narrowed state + AbstractStateImpl narrowing(const AbstractStateImpl& other) const; /// domain join with other, important! other widen this. - void joinWith(const IAbstractState& other) override; + void joinWith(const AbstractState& other) override; /// domain meet with other, important! other widen this. - void meetWith(const IAbstractState& other) override; + void meetWith(const AbstractState& other) override; /// Clone this abstract state - std::unique_ptr clone() const override + std::unique_ptr clone() const override { - return std::make_unique(*this); + return std::make_unique(*this); } /// Get state type name @@ -357,7 +357,7 @@ class AbstractState : public IAbstractState return ""; } - bool equals(const IAbstractState& other) const override; + bool equals(const AbstractState& other) const override; static bool eqVarToValMap(const VarToAbsValMap&lhs, const VarToAbsValMap&rhs) @@ -407,24 +407,24 @@ class AbstractState : public IAbstractState return true; } - bool operator==(const AbstractState&rhs) const + bool operator==(const AbstractStateImpl&rhs) const { return eqVarToValMap(_varToAbsVal, rhs.getVarToVal()) && eqVarToValMap(_addrToAbsVal, rhs.getLocToVal()); } - bool operator!=(const AbstractState&rhs) const + bool operator!=(const AbstractStateImpl&rhs) const { return !(*this == rhs); } - bool operator<(const AbstractState&rhs) const + bool operator<(const AbstractStateImpl&rhs) const { return !(*this >= rhs); } - bool operator>=(const AbstractState&rhs) const + bool operator>=(const AbstractStateImpl&rhs) const { return geqVarToValMap(_varToAbsVal, rhs.getVarToVal()) && geqVarToValMap(_addrToAbsVal, rhs.getLocToVal()); } diff --git a/svf/include/AE/Core/AddressValue.h b/svf/include/AE/Core/AddressValue.h index 7295c186f..4e6b71620 100644 --- a/svf/include/AE/Core/AddressValue.h +++ b/svf/include/AE/Core/AddressValue.h @@ -46,7 +46,7 @@ namespace SVF { class AddressValue { - friend class AbstractState; + friend class AbstractStateImpl; friend class RelExeState; public: typedef Set AddrSet; diff --git a/svf/include/AE/Core/IAbstractState.h b/svf/include/AE/Core/IAbstractState.h index f9a28ea45..fb465ab08 100644 --- a/svf/include/AE/Core/IAbstractState.h +++ b/svf/include/AE/Core/IAbstractState.h @@ -1,4 +1,4 @@ -//===- IAbstractState.h -- Abstract State Interface -------------------------// +//===- AbstractState.h -- Abstract State Interface -------------------------// // // SVF: Static Value-Flow Analysis // @@ -20,7 +20,7 @@ // //===----------------------------------------------------------------------===// /* - * IAbstractState.h + * AbstractState.h * * Interface for abstract state to support runtime polymorphism. * This enables switching between different abstract state implementations @@ -28,8 +28,8 @@ * */ -#ifndef SVF_IABSTRACTSTATE_H -#define SVF_IABSTRACTSTATE_H +#ifndef SVF_ABSTRACTSTATE_H +#define SVF_ABSTRACTSTATE_H #include "AE/Core/AbstractValue.h" #include "AE/Core/IntervalValue.h" @@ -46,30 +46,30 @@ class AddrStmt; /// Abstract interface for abstract state implementations /// This interface enables runtime polymorphism for different state representations /// (e.g., DenseAbstractState, SparseAbstractState) -class IAbstractState +class AbstractState { public: - virtual ~IAbstractState() = default; + virtual ~AbstractState() = default; //============= Core Domain Operations =============// /// Domain join with other state (modifies this state) - virtual void joinWith(const IAbstractState& other) = 0; + virtual void joinWith(const AbstractState& other) = 0; /// Domain meet with other state (modifies this state) - virtual void meetWith(const IAbstractState& other) = 0; + virtual void meetWith(const AbstractState& other) = 0; /// Check equality with another state - virtual bool equals(const IAbstractState& other) const = 0; + virtual bool equals(const AbstractState& other) const = 0; /// Widening operation - returns new widened state - virtual std::unique_ptr widening(const IAbstractState& other) const = 0; + virtual std::unique_ptr widening(const AbstractState& other) const = 0; /// Narrowing operation - returns new narrowed state - virtual std::unique_ptr narrowing(const IAbstractState& other) const = 0; + virtual std::unique_ptr narrowing(const AbstractState& other) const = 0; /// Clone this state - virtual std::unique_ptr clone() const = 0; + virtual std::unique_ptr clone() const = 0; //============= Variable Access Operations =============// @@ -149,4 +149,4 @@ class IAbstractState } // namespace SVF -#endif // SVF_IABSTRACTSTATE_H +#endif // SVF_ABSTRACTSTATE_H diff --git a/svf/include/AE/Core/RelationSolver.h b/svf/include/AE/Core/RelationSolver.h index ac9131eb5..0686eae16 100644 --- a/svf/include/AE/Core/RelationSolver.h +++ b/svf/include/AE/Core/RelationSolver.h @@ -44,17 +44,17 @@ class RelationSolver IntervalESBase (the last element of inputs) for RSY or bilateral solver */ /// Return Z3Expr according to valToValMap - Z3Expr gamma_hat(const AbstractState&exeState) const; + Z3Expr gamma_hat(const AbstractStateImpl&exeState) const; /// Return Z3Expr according to another valToValMap - Z3Expr gamma_hat(const AbstractState&alpha, const AbstractState&exeState) const; + Z3Expr gamma_hat(const AbstractStateImpl&alpha, const AbstractStateImpl&exeState) const; /// Return Z3Expr from a NodeID - Z3Expr gamma_hat(u32_t id, const AbstractState&exeState) const; + Z3Expr gamma_hat(u32_t id, const AbstractStateImpl&exeState) const; - AbstractState abstract_consequence(const AbstractState&lower, const AbstractState&upper, const AbstractState&domain) const; + AbstractStateImpl abstract_consequence(const AbstractStateImpl&lower, const AbstractStateImpl&upper, const AbstractStateImpl&domain) const; - AbstractState beta(const Map &sigma, const AbstractState&exeState) const; + AbstractStateImpl beta(const Map &sigma, const AbstractStateImpl&exeState) const; /// Return Z3 expression lazily based on SVFVar ID @@ -74,13 +74,13 @@ class RelationSolver /* two optional solvers: RSY and bilateral */ - AbstractState bilateral(const AbstractState& domain, const Z3Expr &phi, u32_t descend_check = 0); + AbstractStateImpl bilateral(const AbstractStateImpl& domain, const Z3Expr &phi, u32_t descend_check = 0); - AbstractState RSY(const AbstractState& domain, const Z3Expr &phi); + AbstractStateImpl RSY(const AbstractStateImpl& domain, const Z3Expr &phi); Map BoxedOptSolver(const Z3Expr& phi, Map& ret, Map& low_values, Map& high_values); - AbstractState BS(const AbstractState& domain, const Z3Expr &phi); + AbstractStateImpl BS(const AbstractStateImpl& domain, const Z3Expr &phi); void updateMap(Map& map, u32_t key, const s32_t& value); diff --git a/svf/include/AE/Svfexe/AEDetector.h b/svf/include/AE/Svfexe/AEDetector.h index 4f9bd9374..770c9679c 100644 --- a/svf/include/AE/Svfexe/AEDetector.h +++ b/svf/include/AE/Svfexe/AEDetector.h @@ -75,8 +75,24 @@ class AEDetector * @brief Pure virtual function for detecting issues within a node. * @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(IAbstractState& as, const ICFGNode* node) = 0; + 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) @@ -136,6 +152,10 @@ class AEException : public std::exception class BufOverflowDetector : public AEDetector { friend class AbstractInterpretation; + +private: + Map gepObjOffsetFromBase; ///< Maps GEP objects to their offsets from the base. + public: /** * @brief Constructor initializes the detector kind to BUF_OVERFLOW and sets up external API buffer overflow rules. @@ -161,25 +181,25 @@ 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 interface. - * @param gepAddrs Address value for GEP. - * @param objAddrs Address value for the object. - * @param offset The interval value of the offset. - */ - void updateGepObjOffsetFromBase(IAbstractState& as, - AddressValue gepAddrs, - AddressValue objAddrs, - IntervalValue offset); /** * @brief Detect buffer overflow issues within a node. * @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(IAbstractState& as, const ICFGNode*) override; + void detect(AbstractState& as, const ICFGNode*) override; + /** + * @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 checkStatement(const SVFStmt* stmt, AbstractState& as) override; /** * @brief Handles external API calls related to buffer overflow detection. @@ -187,41 +207,6 @@ class BufOverflowDetector : public AEDetector */ void handleStubFunctions(const CallICFGNode*) override; - /** - * @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 Retrieves the access offset for a given object and GEP statement. @@ -230,7 +215,7 @@ class BufOverflowDetector : public AEDetector * @param gep Pointer to the GEP statement. * @return The interval value of the access offset. */ - IntervalValue getAccessOffset(IAbstractState& as, NodeID objId, const GepStmt* gep); + IntervalValue getAccessOffset(AbstractState& as, NodeID objId, const GepStmt* gep); /** * @brief Adds a bug to the reporter based on an exception. @@ -283,6 +268,54 @@ 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. */ @@ -293,7 +326,7 @@ class BufOverflowDetector : public AEDetector * @param as Reference to the abstract state interface. * @param call Pointer to the call ICFG node. */ - void detectExtAPI(IAbstractState& as, const CallICFGNode *call); + void detectExtAPI(AbstractState& as, const CallICFGNode *call); /** * @brief Checks if memory can be safely accessed. @@ -302,7 +335,7 @@ class BufOverflowDetector : public AEDetector * @param len The interval value representing the length of the memory access. * @return True if the memory access is safe, false otherwise. */ - bool canSafelyAccessMemory(IAbstractState& as, const SVFVar *value, const IntervalValue &len); + bool canSafelyAccessMemory(AbstractState& as, const SVFVar *value, const IntervalValue &len); private: /** @@ -311,7 +344,7 @@ class BufOverflowDetector : public AEDetector * @param call Pointer to the call ICFG node. * @return True if a buffer overflow is detected, false otherwise. */ - bool detectStrcat(IAbstractState& as, const CallICFGNode *call); + bool detectStrcat(AbstractState& as, const CallICFGNode *call); /** * @brief Detects buffer overflow in 'strcpy' function calls. @@ -319,15 +352,15 @@ class BufOverflowDetector : public AEDetector * @param call Pointer to the call ICFG node. * @return True if a buffer overflow is detected, false otherwise. */ - bool detectStrcpy(IAbstractState& as, const CallICFGNode *call); + bool detectStrcpy(AbstractState& as, const CallICFGNode *call); private: - Map gepObjOffsetFromBase; ///< Maps GEP objects to their offsets from the base. Map>> extAPIBufOverflowCheckRules; ///< Rules for checking buffer overflows in external APIs. Set bugLoc; ///< Set of locations where bugs have been reported. SVFBugReport recoder; ///< Recorder for abstract execution bugs. Map nodeToBugInfo; ///< Maps ICFG nodes to bug information. }; + class NullptrDerefDetector : public AEDetector { friend class AbstractInterpretation; @@ -349,7 +382,7 @@ class NullptrDerefDetector : public AEDetector * @param as Reference to the abstract state interface. * @param node Pointer to the ICFG node. */ - void detect(IAbstractState& as, const ICFGNode* node) override; + void detect(AbstractState& as, const ICFGNode* node) override; /** * @brief Handles external API calls related to nullptr dereferences. @@ -421,7 +454,7 @@ class NullptrDerefDetector : public AEDetector * @param as Reference to the abstract state interface. * @param call Pointer to the call ICFG node. */ - void detectExtAPI(IAbstractState& as, const CallICFGNode* call); + void detectExtAPI(AbstractState& as, const CallICFGNode* call); /** @@ -434,7 +467,7 @@ class NullptrDerefDetector : public AEDetector return !v.isAddr() && !v.isInterval(); } - bool canSafelyDerefPtr(IAbstractState& as, const SVFVar* ptr); + bool canSafelyDerefPtr(AbstractState& as, const SVFVar* ptr); private: Set bugLoc; ///< Set of locations where bugs have been reported. diff --git a/svf/include/AE/Svfexe/AbsExtAPI.h b/svf/include/AE/Svfexe/AbsExtAPI.h index b97da7ba5..121c56a49 100644 --- a/svf/include/AE/Svfexe/AbsExtAPI.h +++ b/svf/include/AE/Svfexe/AbsExtAPI.h @@ -53,7 +53,7 @@ class AbsExtAPI * @brief Constructor for AbsExtAPI. * @param abstractTrace Reference to a map of ICFG nodes to abstract states. */ - AbsExtAPI(Map& traces); + AbsExtAPI(Map& traces); /** * @brief Initializes the external function map. @@ -66,7 +66,7 @@ class AbsExtAPI * @param rhs Pointer to the SVF variable representing the string. * @return The string value. */ - std::string strRead(AbstractState& as, const SVFVar* rhs); + std::string strRead(AbstractStateImpl& as, const SVFVar* rhs); /** * @brief Handles an external API call. @@ -86,7 +86,7 @@ class AbsExtAPI * @param strValue Pointer to the SVF variable representing the string. * @return The interval value representing the string length. */ - IntervalValue getStrlen(AbstractState& as, const SVF::SVFVar *strValue); + IntervalValue getStrlen(AbstractStateImpl& as, const SVF::SVFVar *strValue); /** * @brief Handles the strcat API call. @@ -102,7 +102,7 @@ class AbsExtAPI * @param len The interval value representing the length to copy. * @param start_idx The starting index for copying. */ - void handleMemcpy(AbstractState& as, const SVF::SVFVar *dst, const SVF::SVFVar *src, IntervalValue len, u32_t start_idx); + void handleMemcpy(AbstractStateImpl& as, const SVF::SVFVar *dst, const SVF::SVFVar *src, IntervalValue len, u32_t start_idx); /** * @brief Handles the memset API call. @@ -111,7 +111,7 @@ class AbsExtAPI * @param elem The interval value representing the element to set. * @param len The interval value representing the length to set. */ - void handleMemset(AbstractState& as, const SVFVar* dst, IntervalValue elem, IntervalValue len); + void handleMemset(AbstractStateImpl& as, const SVFVar* dst, IntervalValue elem, IntervalValue len); /** * @brief Gets the range limit from a type. @@ -126,12 +126,12 @@ class AbsExtAPI * @return Reference to the abstract state. * @throws Assertion if no trace exists for the node. */ - AbstractState& getAbsStateFromTrace(const ICFGNode* node); + AbstractStateImpl& getAbsStateFromTrace(const ICFGNode* node); protected: SVFIR* svfir; ///< Pointer to the SVF intermediate representation. ICFG* icfg; ///< Pointer to the interprocedural control flow graph. - Map& abstractTrace; ///< Map of ICFG nodes to abstract states. + Map& abstractTrace; ///< Map of ICFG nodes to abstract states. Map> func_map; ///< Map of function names to handlers. }; diff --git a/svf/include/AE/Svfexe/AbstractInterpretation.h b/svf/include/AE/Svfexe/AbstractInterpretation.h index 76a070295..f5cc4e252 100644 --- a/svf/include/AE/Svfexe/AbstractInterpretation.h +++ b/svf/include/AE/Svfexe/AbstractInterpretation.h @@ -165,7 +165,7 @@ class AbstractInterpretation * @return Reference to the abstract state. * @throws Assertion if no trace exists for the node. */ - IAbstractState& getAbsStateFromTrace(const ICFGNode* node) + AbstractState& getAbsStateFromTrace(const ICFGNode* node) { if (abstractTrace.count(node) == 0) { @@ -178,8 +178,8 @@ class AbstractInterpretation } } - /// Dense state access from trace (for internal use when AbstractState is needed) - AbstractState& getDenseAbsStateFromTrace(const ICFGNode* node) + /// Dense state access from trace (for internal use when AbstractStateImpl is needed) + AbstractStateImpl& getDenseAbsStateFromTrace(const ICFGNode* node) { if (abstractTrace.count(node) == 0) { @@ -213,7 +213,7 @@ class AbstractInterpretation * @param intraEdge the edge from CmpStmt to the next node * @return if this edge is feasible */ - bool isBranchFeasible(const IntraCFGEdge* intraEdge, AbstractState& as); + bool isBranchFeasible(const IntraCFGEdge* intraEdge, AbstractStateImpl& as); /** * handle instructions in ICFGSingletonWTO @@ -264,7 +264,7 @@ class AbstractInterpretation * @return if this ICFGNode has preceding execution state */ bool isCmpBranchFeasible(const CmpStmt* cmpStmt, s64_t succ, - AbstractState& as); + AbstractStateImpl& as); /** * Check if this SwitchInst and succ are satisfiable to the execution state. @@ -274,7 +274,7 @@ class AbstractInterpretation * @return if this ICFGNode has preceding execution state */ bool isSwitchBranchFeasible(const SVFVar* var, s64_t succ, - AbstractState& as); + AbstractStateImpl& as); void collectCheckPoint(); @@ -324,10 +324,10 @@ class AbstractInterpretation /// Factory method to create abstract state based on CLI option /// Currently returns DenseAbstractState; will support SparseAbstractState in the future - std::unique_ptr createState() + std::unique_ptr createState() { // TODO: if (Options::UseSparseState()) - return std::make_unique(); + return std::make_unique(); } AbsExtAPI* getUtils() @@ -350,7 +350,7 @@ class AbstractInterpretation // there data should be shared with subclasses Map> func_map; - Map abstractTrace; // abstract states immediately after nodes + Map abstractTrace; // abstract states immediately after nodes std::string moduleName; std::vector> detectors; diff --git a/svf/lib/AE/Core/AbstractState.cpp b/svf/lib/AE/Core/AbstractState.cpp index 4739c8e90..a6c53f822 100644 --- a/svf/lib/AE/Core/AbstractState.cpp +++ b/svf/lib/AE/Core/AbstractState.cpp @@ -35,9 +35,9 @@ using namespace SVF; using namespace SVFUtil; -bool AbstractState::equals(const IAbstractState& other) const +bool AbstractStateImpl::equals(const AbstractState& other) const { - const AbstractState* otherState = dynamic_cast(&other); + const AbstractStateImpl* otherState = dynamic_cast(&other); if (!otherState) { return false; // Different state types are never equal @@ -45,7 +45,7 @@ bool AbstractState::equals(const IAbstractState& other) const return *this == *otherState; } -u32_t AbstractState::hash() const +u32_t AbstractStateImpl::hash() const { size_t h = getVarToVal().size() * 2; Hash hf; @@ -62,10 +62,10 @@ u32_t AbstractState::hash() const return pairH({h, h2}); } -AbstractState AbstractState::wideningDense(const AbstractState& other) const +AbstractStateImpl AbstractStateImpl::widening(const AbstractStateImpl& other) const { // widen interval - AbstractState es = *this; + AbstractStateImpl es = *this; for (auto it = es._varToAbsVal.begin(); it != es._varToAbsVal.end(); ++it) { auto key = it->first; @@ -83,16 +83,16 @@ AbstractState AbstractState::wideningDense(const AbstractState& other) const return es; } -std::unique_ptr AbstractState::widening(const IAbstractState& other) const +std::unique_ptr AbstractStateImpl::widening(const AbstractState& other) const { - const AbstractState* otherState = dynamic_cast(&other); - assert(otherState && "Type mismatch in widening: expected AbstractState"); - return std::make_unique(wideningDense(*otherState)); + const AbstractStateImpl* otherState = dynamic_cast(&other); + assert(otherState && "Type mismatch in widening: expected AbstractStateImpl"); + return std::make_unique(widening(*otherState)); } -AbstractState AbstractState::narrowingDense(const AbstractState& other) const +AbstractStateImpl AbstractStateImpl::narrowing(const AbstractStateImpl& other) const { - AbstractState es = *this; + AbstractStateImpl es = *this; for (auto it = es._varToAbsVal.begin(); it != es._varToAbsVal.end(); ++it) { auto key = it->first; @@ -110,18 +110,18 @@ AbstractState AbstractState::narrowingDense(const AbstractState& other) const return es; } -std::unique_ptr AbstractState::narrowing(const IAbstractState& other) const +std::unique_ptr AbstractStateImpl::narrowing(const AbstractState& other) const { - const AbstractState* otherState = dynamic_cast(&other); - assert(otherState && "Type mismatch in narrowing: expected AbstractState"); - return std::make_unique(narrowingDense(*otherState)); + const AbstractStateImpl* otherState = dynamic_cast(&other); + assert(otherState && "Type mismatch in narrowing: expected AbstractStateImpl"); + return std::make_unique(narrowing(*otherState)); } /// domain join with other, important! other widen this. -void AbstractState::joinWith(const IAbstractState& other) +void AbstractStateImpl::joinWith(const AbstractState& other) { - const AbstractState* otherState = dynamic_cast(&other); - assert(otherState && "Type mismatch in joinWith: expected AbstractState"); + const AbstractStateImpl* otherState = dynamic_cast(&other); + assert(otherState && "Type mismatch in joinWith: expected AbstractStateImpl"); for (auto it = otherState->_varToAbsVal.begin(); it != otherState->_varToAbsVal.end(); ++it) { @@ -153,10 +153,10 @@ void AbstractState::joinWith(const IAbstractState& other) } /// domain meet with other, important! other widen this. -void AbstractState::meetWith(const IAbstractState& other) +void AbstractStateImpl::meetWith(const AbstractState& other) { - const AbstractState* otherState = dynamic_cast(&other); - assert(otherState && "Type mismatch in meetWith: expected AbstractState"); + const AbstractStateImpl* otherState = dynamic_cast(&other); + assert(otherState && "Type mismatch in meetWith: expected AbstractStateImpl"); for (auto it = otherState->_varToAbsVal.begin(); it != otherState->_varToAbsVal.end(); ++it) { @@ -184,7 +184,7 @@ void AbstractState::meetWith(const IAbstractState& other) } // getGepObjAddrs -AddressValue AbstractState::getGepObjAddrs(u32_t pointer, IntervalValue offset) +AddressValue AbstractStateImpl::getGepObjAddrs(u32_t pointer, IntervalValue offset) { AddressValue gepAddrs; APOffset lb = offset.lb().getIntNumeral() < Options::MaxFieldLimit() ? offset.lb().getIntNumeral() @@ -199,15 +199,15 @@ AddressValue AbstractState::getGepObjAddrs(u32_t pointer, IntervalValue offset) s64_t baseObj = getIDFromAddr(addr); assert(SVFUtil::isa(PAG::getPAG()->getGNode(baseObj)) && "Fail to get the base object address!"); NodeID gepObj = PAG::getPAG()->getGepObjVar(baseObj, i); - (*this)[gepObj] = AddressValue(AbstractState::getVirtualMemAddress(gepObj)); - gepAddrs.insert(AbstractState::getVirtualMemAddress(gepObj)); + (*this)[gepObj] = AddressValue(AbstractStateImpl::getVirtualMemAddress(gepObj)); + gepAddrs.insert(AbstractStateImpl::getVirtualMemAddress(gepObj)); } } return gepAddrs; } // initObjVar -void AbstractState::initObjVar(ObjVar* objVar) +void AbstractStateImpl::initObjVar(ObjVar* objVar) { NodeID varId = objVar->getId(); @@ -233,7 +233,7 @@ void AbstractState::initObjVar(ObjVar* objVar) } else if (SVFUtil::isa(objVar)) { - (*this)[varId] = AddressValue(AbstractState::getVirtualMemAddress(varId)); + (*this)[varId] = AddressValue(AbstractStateImpl::getVirtualMemAddress(varId)); } else if (obj->isConstantArray() || obj->isConstantStruct()) { @@ -247,13 +247,13 @@ void AbstractState::initObjVar(ObjVar* objVar) // Handle non-constant memory objects else { - (*this)[varId] = AddressValue(AbstractState::getVirtualMemAddress(varId)); + (*this)[varId] = AddressValue(AbstractStateImpl::getVirtualMemAddress(varId)); } return; } // getElementIndex -IntervalValue AbstractState::getElementIndex(const GepStmt* gep) +IntervalValue AbstractStateImpl::getElementIndex(const GepStmt* gep) { // If the GEP statement has a constant offset, return it directly as the interval value if (gep->isConstantOffset()) @@ -326,7 +326,7 @@ IntervalValue AbstractState::getElementIndex(const GepStmt* gep) return res; } // getByteOffset -IntervalValue AbstractState::getByteOffset(const GepStmt* gep) +IntervalValue AbstractStateImpl::getByteOffset(const GepStmt* gep) { // If the GEP statement has a constant byte offset, return it directly as the interval value if (gep->isConstantOffset()) @@ -393,7 +393,7 @@ IntervalValue AbstractState::getByteOffset(const GepStmt* gep) return res; // Return the resulting byte offset as an IntervalValue. } -AbstractValue AbstractState::loadValue(NodeID varId) +AbstractValue AbstractStateImpl::loadValue(NodeID varId) { AbstractValue res; for (auto addr : (*this)[varId].getAddrs()) @@ -403,7 +403,7 @@ AbstractValue AbstractState::loadValue(NodeID varId) return res; } // storeValue -void AbstractState::storeValue(NodeID varId, AbstractValue val) +void AbstractStateImpl::storeValue(NodeID varId, AbstractValue val) { for (auto addr : (*this)[varId].getAddrs()) { @@ -411,7 +411,7 @@ void AbstractState::storeValue(NodeID varId, AbstractValue val) } } -void AbstractState::printAbstractState() const +void AbstractStateImpl::printAbstractState() const { SVFUtil::outs() << "-----------Var and Value-----------\n"; u32_t fieldWidth = 20; @@ -461,7 +461,7 @@ void AbstractState::printAbstractState() const for (const auto& item: addrToAbsValVec) { std::ostringstream oss; - oss << "0x" << std::hex << AbstractState::getVirtualMemAddress(item.first); + oss << "0x" << std::hex << AbstractStateImpl::getVirtualMemAddress(item.first); SVFUtil::outs() << std::left << std::setw(fieldWidth) << oss.str(); if (item.second.isInterval()) { @@ -493,7 +493,7 @@ void AbstractState::printAbstractState() const SVFUtil::outs() << "-----------------------------------------\n"; } -const SVFType* AbstractState::getPointeeElement(NodeID id) +const SVFType* AbstractStateImpl::getPointeeElement(NodeID id) { SVFIR* svfir = PAG::getPAG(); if (inVarToAddrsTable(id)) @@ -514,7 +514,7 @@ const SVFType* AbstractState::getPointeeElement(NodeID id) return nullptr; } -u32_t AbstractState::getAllocaInstByteSize(const AddrStmt *addr) +u32_t AbstractStateImpl::getAllocaInstByteSize(const AddrStmt *addr) { if (const ObjVar* objvar = SVFUtil::dyn_cast(addr->getRHSVar())) { diff --git a/svf/lib/AE/Core/RelationSolver.cpp b/svf/lib/AE/Core/RelationSolver.cpp index a5cc9dd9d..a0a43e64b 100644 --- a/svf/lib/AE/Core/RelationSolver.cpp +++ b/svf/lib/AE/Core/RelationSolver.cpp @@ -33,19 +33,19 @@ using namespace SVF; using namespace SVFUtil; -AbstractState RelationSolver::bilateral(const AbstractState&domain, const Z3Expr& phi, +AbstractStateImpl RelationSolver::bilateral(const AbstractStateImpl&domain, const Z3Expr& phi, u32_t descend_check) { /// init variables - AbstractState upper = domain.top(); - AbstractState lower = domain.bottom(); + AbstractStateImpl upper = domain.top(); + AbstractStateImpl lower = domain.bottom(); u32_t meets_in_a_row = 0; z3::solver solver = Z3Expr::getSolver(); z3::params p(Z3Expr::getContext()); /// TODO: add option for timeout p.set(":timeout", static_cast(600)); // in milliseconds solver.set(p); - AbstractState consequence; + AbstractStateImpl consequence; /// start processing while (lower != upper) @@ -85,9 +85,9 @@ AbstractState RelationSolver::bilateral(const AbstractState&domain, const Z3Expr } } solver.pop(); - AbstractState newLower = domain.bottom(); + AbstractStateImpl newLower = domain.bottom(); newLower.joinWith(lower); - AbstractState rhs = beta(solution, domain); + AbstractStateImpl rhs = beta(solution, domain); newLower.joinWith(rhs); lower = newLower; meets_in_a_row = 0; @@ -101,7 +101,7 @@ AbstractState RelationSolver::bilateral(const AbstractState&domain, const Z3Expr if (solver.reason_unknown() == "timeout") return upper; } - AbstractState newUpper = domain.top(); + AbstractStateImpl newUpper = domain.top(); newUpper.meetWith(upper); newUpper.meetWith(consequence); upper = newUpper; @@ -111,9 +111,9 @@ AbstractState RelationSolver::bilateral(const AbstractState&domain, const Z3Expr return upper; } -AbstractState RelationSolver::RSY(const AbstractState& domain, const Z3Expr& phi) +AbstractStateImpl RelationSolver::RSY(const AbstractStateImpl& domain, const Z3Expr& phi) { - AbstractState lower = domain.bottom(); + AbstractStateImpl lower = domain.bottom(); z3::solver& solver = Z3Expr::getSolver(); z3::params p(Z3Expr::getContext()); /// TODO: add option for timeout @@ -147,7 +147,7 @@ AbstractState RelationSolver::RSY(const AbstractState& domain, const Z3Expr& phi } } solver.pop(); - AbstractState newLower = domain.bottom(); + AbstractStateImpl newLower = domain.bottom(); newLower.joinWith(lower); newLower.joinWith(beta(solution, domain)); lower = newLower; @@ -167,8 +167,8 @@ AbstractState RelationSolver::RSY(const AbstractState& domain, const Z3Expr& phi return lower; } -AbstractState RelationSolver::abstract_consequence( - const AbstractState& lower, const AbstractState& upper, const AbstractState& domain) const +AbstractStateImpl RelationSolver::abstract_consequence( + const AbstractStateImpl& lower, const AbstractStateImpl& upper, const AbstractStateImpl& domain) const { /*Returns the "abstract consequence" of lower and upper. @@ -184,7 +184,7 @@ AbstractState RelationSolver::abstract_consequence( it != domain.getVarToVal().end(); ++it) /// for variable in self.variables: { - AbstractState proposed = domain.top(); /// proposed = self.top.copy() + AbstractStateImpl proposed = domain.top(); /// proposed = self.top.copy() proposed[it->first] = lower[it->first].getInterval(); /// proposed.set_interval(variable, lower.interval_of(variable)) /// proposed._locToItvVal @@ -196,7 +196,7 @@ AbstractState RelationSolver::abstract_consequence( return lower; /// return lower.copy() } -Z3Expr RelationSolver::gamma_hat(const AbstractState& exeState) const +Z3Expr RelationSolver::gamma_hat(const AbstractStateImpl& exeState) const { Z3Expr res(Z3Expr::getContext().bool_val(true)); for (auto& item : exeState.getVarToVal()) @@ -213,8 +213,8 @@ Z3Expr RelationSolver::gamma_hat(const AbstractState& exeState) const return res; } -Z3Expr RelationSolver::gamma_hat(const AbstractState& alpha, - const AbstractState& exeState) const +Z3Expr RelationSolver::gamma_hat(const AbstractStateImpl& alpha, + const AbstractStateImpl& exeState) const { Z3Expr res(Z3Expr::getContext().bool_val(true)); for (auto& item : exeState.getVarToVal()) @@ -231,7 +231,7 @@ Z3Expr RelationSolver::gamma_hat(const AbstractState& alpha, return res; } -Z3Expr RelationSolver::gamma_hat(u32_t id, const AbstractState& exeState) const +Z3Expr RelationSolver::gamma_hat(u32_t id, const AbstractStateImpl& exeState) const { auto it = exeState.getVarToVal().find(id); assert(it != exeState.getVarToVal().end() && "id not in varToVal?"); @@ -242,10 +242,10 @@ Z3Expr RelationSolver::gamma_hat(u32_t id, const AbstractState& exeState) const return res; } -AbstractState RelationSolver::beta(const Map& sigma, - const AbstractState& exeState) const +AbstractStateImpl RelationSolver::beta(const Map& sigma, + const AbstractStateImpl& exeState) const { - AbstractState res; + AbstractStateImpl res; for (const auto& item : exeState.getVarToVal()) { res[item.first] = IntervalValue( @@ -267,7 +267,7 @@ void RelationSolver::updateMap(Map& map, u32_t key, const s32_t& v } } -AbstractState RelationSolver::BS(const AbstractState& domain, const Z3Expr &phi) +AbstractStateImpl RelationSolver::BS(const AbstractStateImpl& domain, const Z3Expr &phi) { /// because key of _varToItvVal is u32_t, -key may out of range for int /// so we do key + bias for -key @@ -315,7 +315,7 @@ AbstractState RelationSolver::BS(const AbstractState& domain, const Z3Expr &phi) /// optimize each object BoxedOptSolver(new_phi.simplify(), ret, low_values, high_values); /// fill in the return values - AbstractState retInv; + AbstractStateImpl retInv; for (const auto& item: ret) { if (item.first >= bias) diff --git a/svf/lib/AE/Svfexe/AEDetector.cpp b/svf/lib/AE/Svfexe/AEDetector.cpp index bb834b21a..7eb1b07fd 100644 --- a/svf/lib/AE/Svfexe/AEDetector.cpp +++ b/svf/lib/AE/Svfexe/AEDetector.cpp @@ -33,69 +33,81 @@ using namespace SVF; /** - * @brief Detects buffer overflow issues within a given ICFG node. + * @brief Check for buffer overflow in a single statement. * - * This function handles both non-call nodes, where it analyzes GEP (GetElementPtr) - * instructions for potential buffer overflows, and call nodes, where it checks - * for external API calls that may cause overflows. + * This method performs buffer overflow detection for a single GEP statement + * in the same loop as state updates, eliminating redundant traversals. + * GEP offset tracking is now handled in AbstractState during GEP processing. * - * @param as Reference to the abstract state. - * @param node Pointer to the ICFG node. + * @param stmt Pointer to the SVF statement to check. + * @param as Reference to the abstract state interface. */ -void BufOverflowDetector::detect(IAbstractState& as, const ICFGNode* node) +void BufOverflowDetector::checkStatement(const SVFStmt* stmt, AbstractState& as) { - if (!SVFUtil::isa(node)) + if (SVFUtil::isa(stmt->getICFGNode())) { + return; + } + // Only check GEP statements for buffer overflow + if (const GepStmt* gep = SVFUtil::dyn_cast(stmt)) { - // Handle non-call nodes by analyzing GEP instructions - for (const SVFStmt* stmt : node->getSVFStmts()) - { - if (const GepStmt* gep = SVFUtil::dyn_cast(stmt)) - { - SVFIR* svfir = PAG::getPAG(); - NodeID lhs = gep->getLHSVarID(); - NodeID rhs = gep->getRHSVarID(); + SVFIR* svfir = PAG::getPAG(); + NodeID lhs = gep->getLHSVarID(); + NodeID rhs = gep->getRHSVarID(); - // Update the GEP object offset from its base - updateGepObjOffsetFromBase(as, as[lhs].getAddrs(), as[rhs].getAddrs(), as.getByteOffset(gep)); + // Update the GEP object offset from its base (same as Python version) + updateGepObjOffsetFromBase(as, as[lhs].getAddrs(), as[rhs].getAddrs(), as.getByteOffset(gep)); - IntervalValue baseObjSize = IntervalValue::bottom(); - AddressValue objAddrs = as[gep->getRHSVarID()].getAddrs(); - for (const auto& addr : objAddrs) - { - NodeID objId = as.getIDFromAddr(addr); - u32_t size = 0; - // like `int arr[10]` which has constant size before runtime - if (svfir->getBaseObject(objId)->isConstantByteSize()) - { - size = svfir->getBaseObject(objId)->getByteSizeOfObj(); - } - else - { - // like `int len = ***; int arr[len]`, whose size can only be known in runtime - const ICFGNode* addrNode = svfir->getBaseObject(objId)->getICFGNode(); - for (const SVFStmt* stmt2 : addrNode->getSVFStmts()) - { - if (const AddrStmt* addrStmt = SVFUtil::dyn_cast(stmt2)) - { - size = as.getAllocaInstByteSize(addrStmt); - } - } - } + AddressValue objAddrs = as[rhs].getAddrs(); + for (const auto& addr : objAddrs) + { + NodeID objId = as.getIDFromAddr(addr); + u32_t size = 0; - // Calculate access offset and check for potential overflow - IntervalValue accessOffset = getAccessOffset(as, objId, gep); - if (accessOffset.ub().getIntNumeral() >= size) + // Get object size - constant or runtime-determined + if (svfir->getBaseObject(objId)->isConstantByteSize()) + { + size = svfir->getBaseObject(objId)->getByteSizeOfObj(); + } + else + { + // Runtime-determined size (e.g., VLA) + const ICFGNode* addrNode = svfir->getBaseObject(objId)->getICFGNode(); + for (const SVFStmt* stmt2 : addrNode->getSVFStmts()) + { + if (const AddrStmt* addrStmt = SVFUtil::dyn_cast(stmt2)) { - AEException bug(stmt->toString()); - addBugToReporter(bug, stmt->getICFGNode()); + size = as.getAllocaInstByteSize(addrStmt); } } } + + // Calculate access offset and check for potential overflow + IntervalValue accessOffset = getAccessOffset(as, objId, gep); + if (accessOffset.ub().getIntNumeral() >= size) + { + AEException bug(stmt->toString()); + addBugToReporter(bug, stmt->getICFGNode()); + } } } - else +} + +/** + * @brief Detects buffer overflow issues within a given ICFG node. + * + * This legacy method is kept for handling external API calls at call nodes. + * GEP statement detection is now handled by checkStatement() which is called + * in the same loop as state updates, eliminating redundant traversals. + * + * @param as Reference to the abstract state. + * @param node Pointer to the ICFG node. + */ +void BufOverflowDetector::detect(AbstractState& as, const ICFGNode* node) +{ + // GEP statement detection is now handled by checkStatement() in the main loop + // This method only handles external API calls at call nodes + if (SVFUtil::isa(node)) { - // Handle call nodes by checking for external API calls const CallICFGNode* callNode = SVFUtil::cast(node); if (SVFUtil::isExtCall(callNode->getCalledFunction())) { @@ -104,6 +116,77 @@ void BufOverflowDetector::detect(IAbstractState& as, const ICFGNode* node) } } +/** + * @brief Updates the offset of a GEP object from its base. + * + * This function calculates and stores the offset of a GEP object from its base object + * using the addresses and offsets provided. + * + * @param as Reference to the abstract state. + * @param gepAddrs The addresses of the GEP objects. + * @param objAddrs The addresses of the base objects. + * @param offset The interval value of the offset. + */ +void BufOverflowDetector::updateGepObjOffsetFromBase(AbstractState& as, SVF::AddressValue gepAddrs, SVF::AddressValue objAddrs, SVF::IntervalValue offset) +{ + SVFIR* svfir = PAG::getPAG(); + + for (const auto& objAddr : objAddrs) + { + NodeID objId = as.getIDFromAddr(objAddr); + auto obj = svfir->getGNode(objId); + + if (SVFUtil::isa(obj)) + { + // if the object is a BaseObjVar, add the offset directly + // like llvm bc `arr = alloc i8 12; p = gep arr, 4` + // we write key value pair {gep, 4} + for (const auto& gepAddr : gepAddrs) + { + NodeID gepObj = as.getIDFromAddr(gepAddr); + if (const GepObjVar* gepObjVar = SVFUtil::dyn_cast(svfir->getGNode(gepObj))) + { + addToGepObjOffsetFromBase(gepObjVar, offset); + } + else + { + assert(AbstractStateImpl::isInvalidMem(gepAddr) && "GEP object is neither a GepObjVar nor an invalid memory address"); + } + } + } + else if (SVFUtil::isa(obj)) + { + // if the object is a GepObjVar, add the offset from the base object + // like llvm bc `arr = alloc i8 12; p = gep arr, 4; q = gep p, 6` + // we retreive {p, 4} and write {q, 4+6} + const GepObjVar* objVar = SVFUtil::cast(obj); + for (const auto& gepAddr : gepAddrs) + { + NodeID gepObj = as.getIDFromAddr(gepAddr); + if (const GepObjVar* gepObjVar = SVFUtil::dyn_cast(svfir->getGNode(gepObj))) + { + if (hasGepObjOffsetFromBase(objVar)) + { + IntervalValue objOffsetFromBase = + getGepObjOffsetFromBase(objVar); + if (!hasGepObjOffsetFromBase(gepObjVar)) + addToGepObjOffsetFromBase( + gepObjVar, objOffsetFromBase + offset); + } + else + { + assert(false && + "GEP RHS object has no offset from base"); + } + } + else + { + assert(AbstractStateImpl::isInvalidMem(gepAddr) && "GEP object is neither a GepObjVar nor an invalid memory address"); + } + } + } + } +} /** * @brief Handles stub functions within the ICFG node. @@ -122,7 +205,7 @@ void BufOverflowDetector::handleStubFunctions(const SVF::CallICFGNode* callNode) AbstractInterpretation::getAEInstance().checkpoints.erase(callNode); if (callNode->arg_size() < 2) return; - IAbstractState& as = + AbstractState& as = AbstractInterpretation::getAEInstance().getAbsStateFromTrace( callNode); u32_t size_id = callNode->getArgument(1)->getId(); @@ -152,7 +235,7 @@ void BufOverflowDetector::handleStubFunctions(const SVF::CallICFGNode* callNode) // void UNSAFE_BUFACCESS(void* data, int size); AbstractInterpretation::getAEInstance().checkpoints.erase(callNode); if (callNode->arg_size() < 2) return; - IAbstractState& as = AbstractInterpretation::getAEInstance().getAbsStateFromTrace(callNode); + AbstractState& as = AbstractInterpretation::getAEInstance().getAbsStateFromTrace(callNode); u32_t size_id = callNode->getArgument(1)->getId(); IntervalValue val = as[size_id].getInterval(); if (val.isBottom()) @@ -216,7 +299,7 @@ void BufOverflowDetector::initExtAPIBufOverflowCheckRules() * @param as Reference to the abstract state. * @param call Pointer to the call ICFG node. */ -void BufOverflowDetector::detectExtAPI(IAbstractState& as, +void BufOverflowDetector::detectExtAPI(AbstractState& as, const CallICFGNode* call) { assert(call->getCalledFunction() && "FunObjVar* is nullptr"); @@ -304,27 +387,29 @@ void BufOverflowDetector::detectExtAPI(IAbstractState& as, * * This function calculates the access offset for a base object or a sub-object of an * aggregate object (using GEP). If the object is a dummy object, it returns a top interval value. + * GEP offset information is now retrieved from AbstractState rather than the detector. * * @param as Reference to the abstract state. * @param objId The ID of the object. * @param gep Pointer to the GEP statement. * @return The interval value of the access offset. */ -IntervalValue BufOverflowDetector::getAccessOffset(SVF::IAbstractState& as, SVF::NodeID objId, const SVF::GepStmt* gep) +IntervalValue BufOverflowDetector::getAccessOffset(SVF::AbstractState& as, SVF::NodeID objId, const SVF::GepStmt* gep) { SVFIR* svfir = PAG::getPAG(); auto obj = svfir->getGNode(objId); if (SVFUtil::isa(obj)) { - // if the object is a BaseObjVar, return the byte offset directly - // like `int arr[10]; arr[5] = 1;` arr is the baseObjVar + // If the object is a BaseObjVar, return the byte offset directly + // Example: `int arr[10]; arr[5] = 1;` arr is the baseObjVar return as.getByteOffset(gep); } else if (SVFUtil::isa(obj)) { - // if the object is a GepObjVar, return the offset from the base object - // like `int arr[10]; int* p=arr+5; p[3] = 1`, p is the GepObjVar from arr. + // If the object is a GepObjVar, return the offset from the base object + // Example: `int arr[10]; int* p=arr+5; p[3] = 1`, p is the GepObjVar from arr. + // Use the detector's gepObjOffsetFromBase map return getGepObjOffsetFromBase(SVFUtil::cast(obj)) + as.getByteOffset(gep); } else @@ -334,76 +419,6 @@ IntervalValue BufOverflowDetector::getAccessOffset(SVF::IAbstractState& as, SVF: } } -/** - * @brief Updates the offset of a GEP object from its base. - * - * This function calculates and stores the offset of a GEP object from its base object - * using the addresses and offsets provided. - * - * @param gepAddrs The addresses of the GEP objects. - * @param objAddrs The addresses of the base objects. - * @param offset The interval value of the offset. - */ -void BufOverflowDetector::updateGepObjOffsetFromBase(IAbstractState& as, SVF::AddressValue gepAddrs, SVF::AddressValue objAddrs, SVF::IntervalValue offset) -{ - SVFIR* svfir = PAG::getPAG(); - - for (const auto& objAddr : objAddrs) - { - NodeID objId = as.getIDFromAddr(objAddr); - auto obj = svfir->getGNode(objId); - - if (SVFUtil::isa(obj)) - { - // if the object is a BaseObjVar, add the offset directly - // like llvm bc `arr = alloc i8 12; p = gep arr, 4` - // we write key value pair {gep, 4} - for (const auto& gepAddr : gepAddrs) - { - NodeID gepObj = as.getIDFromAddr(gepAddr); - if (const GepObjVar* gepObjVar = SVFUtil::dyn_cast(svfir->getGNode(gepObj))) - { - addToGepObjOffsetFromBase(gepObjVar, offset); - } - else - { - assert(AbstractState::isInvalidMem(gepAddr) && "GEP object is neither a GepObjVar nor an invalid memory address"); - } - } - } - else if (SVFUtil::isa(obj)) - { - // if the object is a GepObjVar, add the offset from the base object - // like llvm bc `arr = alloc i8 12; p = gep arr, 4; q = gep p, 6` - // we retreive {p, 4} and write {q, 4+6} - const GepObjVar* objVar = SVFUtil::cast(obj); - for (const auto& gepAddr : gepAddrs) - { - NodeID gepObj = as.getIDFromAddr(gepAddr); - if (const GepObjVar* gepObjVar = SVFUtil::dyn_cast(svfir->getGNode(gepObj))) - { - if (hasGepObjOffsetFromBase(objVar)) - { - IntervalValue objOffsetFromBase = - getGepObjOffsetFromBase(objVar); - if (!hasGepObjOffsetFromBase(gepObjVar)) - addToGepObjOffsetFromBase( - gepObjVar, objOffsetFromBase + offset); - } - else - { - assert(false && - "GEP RHS object has no offset from base"); - } - } - else - { - assert(AbstractState::isInvalidMem(gepAddr) && "GEP object is neither a GepObjVar nor an invalid memory address"); - } - } - } - } -} /** * @brief Detects buffer overflow in 'strcpy' function calls. @@ -415,12 +430,12 @@ void BufOverflowDetector::updateGepObjOffsetFromBase(IAbstractState& as, SVF::Ad * @param call Pointer to the call ICFG node. * @return True if the memory access is safe, false otherwise. */ -bool BufOverflowDetector::detectStrcpy(IAbstractState& as, const CallICFGNode *call) +bool BufOverflowDetector::detectStrcpy(AbstractState& as, const CallICFGNode *call) { const SVFVar* arg0Val = call->getArgument(0); const SVFVar* arg1Val = call->getArgument(1); // Cast to dense AbstractState for AbsExtAPI compatibility - AbstractState& denseAs = dynamic_cast(as); + AbstractStateImpl& denseAs = dynamic_cast(as); IntervalValue strLen = AbstractInterpretation::getAEInstance().getUtils()->getStrlen(denseAs, arg1Val); return canSafelyAccessMemory(as, arg0Val, strLen); } @@ -435,13 +450,13 @@ bool BufOverflowDetector::detectStrcpy(IAbstractState& as, const CallICFGNode *c * @param call Pointer to the call ICFG node. * @return True if the memory access is safe, false otherwise. */ -bool BufOverflowDetector::detectStrcat(IAbstractState& as, const CallICFGNode *call) +bool BufOverflowDetector::detectStrcat(AbstractState& as, const CallICFGNode *call) { const std::vector strcatGroup = {"__strcat_chk", "strcat", "__wcscat_chk", "wcscat"}; const std::vector strncatGroup = {"__strncat_chk", "strncat", "__wcsncat_chk", "wcsncat"}; // Cast to dense AbstractState for AbsExtAPI compatibility - AbstractState& denseAs = dynamic_cast(as); + AbstractStateImpl& denseAs = dynamic_cast(as); if (std::find(strcatGroup.begin(), strcatGroup.end(), call->getCalledFunction()->getName()) != strcatGroup.end()) { @@ -472,14 +487,15 @@ bool BufOverflowDetector::detectStrcat(IAbstractState& as, const CallICFGNode *c * @brief Checks if a memory access is safe given a specific buffer length. * * This function ensures that a given memory access, starting at a specific value, - * does not exceed the allocated size of the buffer. + * does not exceed the allocated size of the buffer. GEP offset information is now + * retrieved from AbstractState rather than the detector. * * @param as Reference to the abstract state. * @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. */ -bool BufOverflowDetector::canSafelyAccessMemory(IAbstractState& as, const SVF::SVFVar* value, const SVF::IntervalValue& len) +bool BufOverflowDetector::canSafelyAccessMemory(AbstractState& as, const SVF::SVFVar* value, const SVF::IntervalValue& len) { SVFIR* svfir = PAG::getPAG(); NodeID value_id = value->getId(); @@ -508,7 +524,7 @@ bool BufOverflowDetector::canSafelyAccessMemory(IAbstractState& as, const SVF::S } IntervalValue offset(0); - // if the object is a GepObjVar, get the offset from the base object + // if the object is a GepObjVar, get the offset from the base object (using detector's map) if (SVFUtil::isa(svfir->getGNode(objId))) { offset = getGepObjOffsetFromBase(SVFUtil::cast(svfir->getGNode(objId))) + len; @@ -528,7 +544,7 @@ bool BufOverflowDetector::canSafelyAccessMemory(IAbstractState& as, const SVF::S return true; } -void NullptrDerefDetector::detect(IAbstractState& as, const ICFGNode* node) +void NullptrDerefDetector::detect(AbstractState& as, const ICFGNode* node) { if (SVFUtil::isa(node)) { @@ -573,20 +589,23 @@ void NullptrDerefDetector::detect(IAbstractState& as, const ICFGNode* node) void NullptrDerefDetector::handleStubFunctions(const CallICFGNode* callNode) { - std::string funcName = callNode->getCalledFunction()->getName(); - if (funcName == "UNSAFE_LOAD") - { + std::string funcName; + if (callNode->getCalledFunction() == nullptr) { + return; + } else { + funcName = callNode->getCalledFunction()->getName(); + } + + if (funcName == "UNSAFE_LOAD") { // void UNSAFE_LOAD(void* ptr); AbstractInterpretation::getAEInstance().checkpoints.erase(callNode); - if (callNode->arg_size() < 1) + if (callNode->arg_size() < 1) { return; - IAbstractState& as = AbstractInterpretation::getAEInstance().getAbsStateFromTrace(callNode); - + } + AbstractState& as = AbstractInterpretation::getAEInstance().getAbsStateFromTrace(callNode); const SVFVar* arg0Val = callNode->getArgument(0); - // opt may directly dereference a null pointer and call UNSAFE_LOAD(null) bool isSafe = canSafelyDerefPtr(as, arg0Val) && arg0Val->getId() != 0; - if (!isSafe) - { + if (!isSafe) { SVFUtil::outs() << SVFUtil::sucMsg("success: expected null dereference at UNSAFE_LOAD") << " — " << callNode->toString() << "\n"; return; @@ -603,7 +622,7 @@ void NullptrDerefDetector::handleStubFunctions(const CallICFGNode* callNode) // void SAFE_LOAD(void* ptr); AbstractInterpretation::getAEInstance().checkpoints.erase(callNode); if (callNode->arg_size() < 1) return; - IAbstractState& as = AbstractInterpretation::getAEInstance().getAbsStateFromTrace(callNode); + AbstractState& as = AbstractInterpretation::getAEInstance().getAbsStateFromTrace(callNode); const SVFVar* arg0Val = callNode->getArgument(0); // opt may directly dereference a null pointer and call UNSAFE_LOAD(null)ols bool isSafe = canSafelyDerefPtr(as, arg0Val) && arg0Val->getId() != 0; @@ -622,7 +641,7 @@ void NullptrDerefDetector::handleStubFunctions(const CallICFGNode* callNode) } } -void NullptrDerefDetector::detectExtAPI(IAbstractState& as, const CallICFGNode* call) +void NullptrDerefDetector::detectExtAPI(AbstractState& as, const CallICFGNode* call) { assert(call->getCalledFunction() && "FunObjVar* is nullptr"); // get ext type @@ -681,7 +700,7 @@ void NullptrDerefDetector::detectExtAPI(IAbstractState& as, const CallICFGNode* } -bool NullptrDerefDetector::canSafelyDerefPtr(IAbstractState& as, const SVFVar* value) +bool NullptrDerefDetector::canSafelyDerefPtr(AbstractState& as, const SVFVar* value) { NodeID value_id = value->getId(); AbstractValue AbsVal = as[value_id]; @@ -692,10 +711,10 @@ bool NullptrDerefDetector::canSafelyDerefPtr(IAbstractState& as, const SVFVar* v for (const auto &addr: AbsVal.getAddrs()) { // if the addr itself is invalid mem, report unsafe - if (AbstractState::isInvalidMem(addr)) + if (AbstractStateImpl::isInvalidMem(addr)) return false; // if nullptr is detected, return unsafe - else if (AbstractState::isNullMem(addr)) + else if (AbstractStateImpl::isNullMem(addr)) return false; // if addr is labeled freed mem, report unsafe else if (as.isFreedMem(addr)) diff --git a/svf/lib/AE/Svfexe/AbsExtAPI.cpp b/svf/lib/AE/Svfexe/AbsExtAPI.cpp index 1d90ad602..2c0e39bf5 100644 --- a/svf/lib/AE/Svfexe/AbsExtAPI.cpp +++ b/svf/lib/AE/Svfexe/AbsExtAPI.cpp @@ -32,7 +32,7 @@ #include "Util/Options.h" using namespace SVF; -AbsExtAPI::AbsExtAPI(Map& traces): abstractTrace(traces) +AbsExtAPI::AbsExtAPI(Map& traces): abstractTrace(traces) { svfir = PAG::getPAG(); icfg = svfir->getICFG(); @@ -44,7 +44,7 @@ void AbsExtAPI::initExtFunMap() #define SSE_FUNC_PROCESS(LLVM_NAME ,FUNC_NAME) \ auto sse_##FUNC_NAME = [this](const CallICFGNode *callNode) { \ /* run real ext function */ \ - AbstractState& as = getAbsStateFromTrace(callNode); \ + AbstractStateImpl& as = getAbsStateFromTrace(callNode); \ u32_t rhs_id = callNode->getArgument(0)->getId(); \ if (!as.inVarToValTable(rhs_id)) return; \ u32_t rhs = as[rhs_id].getInterval().lb().getIntNumeral(); \ @@ -78,7 +78,7 @@ void AbsExtAPI::initExtFunMap() { AbstractInterpretation::getAEInstance().checkpoints.erase(callNode); u32_t arg0 = callNode->getArgument(0)->getId(); - AbstractState&as = getAbsStateFromTrace(callNode); + AbstractStateImpl&as = getAbsStateFromTrace(callNode); if (as[arg0].getInterval().equals(IntervalValue(1, 1))) { SVFUtil::errs() << SVFUtil::sucMsg("The assertion is successfully verified!!\n"); @@ -96,7 +96,7 @@ void AbsExtAPI::initExtFunMap() { u32_t arg0 = callNode->getArgument(0)->getId(); u32_t arg1 = callNode->getArgument(1)->getId(); - AbstractState&as = getAbsStateFromTrace(callNode); + AbstractStateImpl&as = getAbsStateFromTrace(callNode); if (as[arg0].getInterval().equals(as[arg1].getInterval())) { SVFUtil::errs() << SVFUtil::sucMsg("The assertion is successfully verified!!\n"); @@ -113,7 +113,7 @@ void AbsExtAPI::initExtFunMap() auto svf_print = [&](const CallICFGNode* callNode) { if (callNode->arg_size() < 2) return; - AbstractState&as = getAbsStateFromTrace(callNode); + AbstractStateImpl&as = getAbsStateFromTrace(callNode); u32_t num_id = callNode->getArgument(0)->getId(); std::string text = strRead(as, callNode->getArgument(1)); assert(as.inVarToValTable(num_id) && "print() should pass integer"); @@ -127,7 +127,7 @@ void AbsExtAPI::initExtFunMap() auto svf_set_value = [&](const CallICFGNode* callNode) { if (callNode->arg_size() < 2) return; - AbstractState&as = getAbsStateFromTrace(callNode); + AbstractStateImpl&as = getAbsStateFromTrace(callNode); AbstractValue& num = as[callNode->getArgument(0)->getId()]; AbstractValue& lb = as[callNode->getArgument(1)->getId()]; AbstractValue& ub = as[callNode->getArgument(2)->getId()]; @@ -150,7 +150,7 @@ void AbsExtAPI::initExtFunMap() auto sse_scanf = [&](const CallICFGNode* callNode) { - AbstractState& as = getAbsStateFromTrace(callNode); + AbstractStateImpl& as = getAbsStateFromTrace(callNode); //scanf("%d", &data); if (callNode->arg_size() < 2) return; @@ -174,7 +174,7 @@ void AbsExtAPI::initExtFunMap() { //fscanf(stdin, "%d", &data); if (callNode->arg_size() < 3) return; - AbstractState& as = getAbsStateFromTrace(callNode); + AbstractStateImpl& as = getAbsStateFromTrace(callNode); u32_t dst_id = callNode->getArgument(2)->getId(); if (!as.inVarToAddrsTable(dst_id)) { @@ -203,7 +203,7 @@ void AbsExtAPI::initExtFunMap() auto sse_fread = [&](const CallICFGNode *callNode) { if (callNode->arg_size() < 3) return; - AbstractState&as = getAbsStateFromTrace(callNode); + AbstractStateImpl&as = getAbsStateFromTrace(callNode); u32_t block_count_id = callNode->getArgument(2)->getId(); u32_t block_size_id = callNode->getArgument(1)->getId(); IntervalValue block_count = as[block_count_id].getInterval(); @@ -220,7 +220,7 @@ void AbsExtAPI::initExtFunMap() auto sse_snprintf = [&](const CallICFGNode *callNode) { if (callNode->arg_size() < 2) return; - AbstractState&as = getAbsStateFromTrace(callNode); + AbstractStateImpl&as = getAbsStateFromTrace(callNode); u32_t size_id = callNode->getArgument(1)->getId(); u32_t dst_id = callNode->getArgument(0)->getId(); // get elem size of arg2 @@ -261,7 +261,7 @@ void AbsExtAPI::initExtFunMap() // itoa(num, ch, 10); // num: int, ch: char*, 10 is decimal if (callNode->arg_size() < 3) return; - AbstractState&as = getAbsStateFromTrace(callNode); + AbstractStateImpl&as = getAbsStateFromTrace(callNode); u32_t num_id = callNode->getArgument(0)->getId(); u32_t num = (u32_t) as[num_id].getInterval().getNumeral(); @@ -275,7 +275,7 @@ void AbsExtAPI::initExtFunMap() // check the arg size if (callNode->arg_size() < 1) return; const SVFVar* strValue = callNode->getArgument(0); - AbstractState& as = getAbsStateFromTrace(callNode); + AbstractStateImpl& as = getAbsStateFromTrace(callNode); NodeID value_id = strValue->getId(); u32_t lhsId = callNode->getRetICFGNode()->getActualRet()->getId(); u32_t dst_size = 0; @@ -334,7 +334,7 @@ void AbsExtAPI::initExtFunMap() { // recv(sockfd, buf, len, flags); if (callNode->arg_size() < 4) return; - AbstractState&as = getAbsStateFromTrace(callNode); + AbstractStateImpl&as = getAbsStateFromTrace(callNode); u32_t len_id = callNode->getArgument(2)->getId(); IntervalValue len = as[len_id].getInterval() - IntervalValue(1); u32_t lhsId = callNode->getRetICFGNode()->getActualRet()->getId(); @@ -346,11 +346,11 @@ void AbsExtAPI::initExtFunMap() auto sse_free = [&](const CallICFGNode *callNode) { if (callNode->arg_size() < 1) return; - AbstractState& as = getAbsStateFromTrace(callNode); + AbstractStateImpl& as = getAbsStateFromTrace(callNode); const u32_t freePtr = callNode->getArgument(0)->getId(); for (auto addr: as[freePtr].getAddrs()) { - if (AbstractState::isInvalidMem(addr)) + if (AbstractStateImpl::isInvalidMem(addr)) { // Detected a double free — the address has already been freed. // No action is taken at this point. @@ -376,7 +376,7 @@ void AbsExtAPI::initExtFunMap() } }; -AbstractState& AbsExtAPI::getAbsStateFromTrace(const SVF::ICFGNode* node) +AbstractStateImpl& AbsExtAPI::getAbsStateFromTrace(const SVF::ICFGNode* node) { if (abstractTrace.count(node) == 0) { @@ -389,7 +389,7 @@ AbstractState& AbsExtAPI::getAbsStateFromTrace(const SVF::ICFGNode* node) } } -std::string AbsExtAPI::strRead(AbstractState& as, const SVFVar* rhs) +std::string AbsExtAPI::strRead(AbstractStateImpl& as, const SVFVar* rhs) { // sse read string nodeID->string std::string str0; @@ -421,7 +421,7 @@ std::string AbsExtAPI::strRead(AbstractState& as, const SVFVar* rhs) void AbsExtAPI::handleExtAPI(const CallICFGNode *call) { - AbstractState& as = getAbsStateFromTrace(call); + AbstractStateImpl& as = getAbsStateFromTrace(call); const FunObjVar *fun = call->getCalledFunction(); assert(fun && "FunObjVar* is nullptr"); ExtAPIType extType = UNCLASSIFIED; @@ -493,7 +493,7 @@ void AbsExtAPI::handleStrcpy(const CallICFGNode *call) { // strcpy, __strcpy_chk, stpcpy , wcscpy, __wcscpy_chk // get the dst and src - AbstractState& as = getAbsStateFromTrace(call); + AbstractStateImpl& as = getAbsStateFromTrace(call); const SVFVar* arg0Val = call->getArgument(0); const SVFVar* arg1Val = call->getArgument(1); IntervalValue strLen = getStrlen(as, arg1Val); @@ -501,7 +501,7 @@ void AbsExtAPI::handleStrcpy(const CallICFGNode *call) handleMemcpy(as, arg0Val, arg1Val, strLen, strLen.lb().getIntNumeral()); } -IntervalValue AbsExtAPI::getStrlen(AbstractState& as, const SVF::SVFVar *strValue) +IntervalValue AbsExtAPI::getStrlen(AbstractStateImpl& as, const SVF::SVFVar *strValue) { NodeID value_id = strValue->getId(); u32_t dst_size = 0; @@ -581,7 +581,7 @@ void AbsExtAPI::handleStrcat(const SVF::CallICFGNode *call) { // __strcat_chk, strcat, __wcscat_chk, wcscat, __strncat_chk, strncat, __wcsncat_chk, wcsncat // to check it is strcat group or strncat group - AbstractState& as = getAbsStateFromTrace(call); + AbstractStateImpl& as = getAbsStateFromTrace(call); const FunObjVar *fun = call->getCalledFunction(); const std::vector strcatGroup = {"__strcat_chk", "strcat", "__wcscat_chk", "wcscat"}; const std::vector strncatGroup = {"__strncat_chk", "strncat", "__wcsncat_chk", "wcsncat"}; @@ -612,7 +612,7 @@ void AbsExtAPI::handleStrcat(const SVF::CallICFGNode *call) } } -void AbsExtAPI::handleMemcpy(AbstractState& as, const SVF::SVFVar *dst, const SVF::SVFVar *src, IntervalValue len, u32_t start_idx) +void AbsExtAPI::handleMemcpy(AbstractStateImpl& as, const SVF::SVFVar *dst, const SVF::SVFVar *src, IntervalValue len, u32_t start_idx) { u32_t dstId = dst->getId(); // pts(dstId) = {objid} objbar objtypeinfo->getType(). u32_t srcId = src->getId(); @@ -670,7 +670,7 @@ void AbsExtAPI::handleMemcpy(AbstractState& as, const SVF::SVFVar *dst, const SV } } -void AbsExtAPI::handleMemset(AbstractState& as, const SVF::SVFVar *dst, IntervalValue elem, IntervalValue len) +void AbsExtAPI::handleMemset(AbstractStateImpl& as, const SVF::SVFVar *dst, IntervalValue elem, IntervalValue len) { u32_t dstId = dst->getId(); u32_t size = std::min((u32_t)Options::MaxFieldLimit(), (u32_t) len.lb().getIntNumeral()); diff --git a/svf/lib/AE/Svfexe/AbstractInterpretation.cpp b/svf/lib/AE/Svfexe/AbstractInterpretation.cpp index a15c3da68..61ce43b1f 100644 --- a/svf/lib/AE/Svfexe/AbstractInterpretation.cpp +++ b/svf/lib/AE/Svfexe/AbstractInterpretation.cpp @@ -163,7 +163,7 @@ void AbstractInterpretation::analyse() void AbstractInterpretation::handleGlobalNode() { const ICFGNode* node = icfg->getGlobalICFGNode(); - abstractTrace[node] = AbstractState(); + abstractTrace[node] = AbstractStateImpl(); abstractTrace[node][IRGraph::NullPtr] = AddressValue(); // Global Node, we just need to handle addr, load, store, copy and gep for (const SVFStmt *stmt: node->getSVFStmts()) @@ -177,8 +177,8 @@ void AbstractInterpretation::handleGlobalNode() /// Scenario 2: preblock -----(callEdge)----> block bool AbstractInterpretation::mergeStatesFromPredecessors(const ICFGNode * icfgNode) { - std::vector workList; - AbstractState preAs; + std::vector workList; + AbstractStateImpl preAs; for (auto& edge: icfgNode->getInEdges()) { if (abstractTrace.find(edge->getSrcNode()) != abstractTrace.end()) @@ -187,7 +187,7 @@ bool AbstractInterpretation::mergeStatesFromPredecessors(const ICFGNode * icfgNo if (const IntraCFGEdge *intraCfgEdge = SVFUtil::dyn_cast(edge)) { - AbstractState tmpEs = abstractTrace[edge->getSrcNode()]; + AbstractStateImpl tmpEs = abstractTrace[edge->getSrcNode()]; if (intraCfgEdge->getCondition()) { if (isBranchFeasible(intraCfgEdge, tmpEs)) @@ -256,9 +256,9 @@ bool AbstractInterpretation::mergeStatesFromPredecessors(const ICFGNode * icfgNo bool AbstractInterpretation::isCmpBranchFeasible(const CmpStmt* cmpStmt, s64_t succ, - AbstractState& as) + AbstractStateImpl& as) { - AbstractState new_es = as; + AbstractStateImpl new_es = as; // get cmp stmt's op0, op1, and predicate NodeID op0 = cmpStmt->getOpVarID(0); NodeID op1 = cmpStmt->getOpVarID(1); @@ -482,9 +482,9 @@ bool AbstractInterpretation::isCmpBranchFeasible(const CmpStmt* cmpStmt, s64_t s } bool AbstractInterpretation::isSwitchBranchFeasible(const SVFVar* var, s64_t succ, - AbstractState& as) + AbstractStateImpl& as) { - AbstractState new_es = as; + AbstractStateImpl new_es = as; IntervalValue& switch_cond = new_es[var->getId()].getInterval(); s64_t value = succ; FIFOWorkList workList; @@ -526,7 +526,7 @@ bool AbstractInterpretation::isSwitchBranchFeasible(const SVFVar* var, s64_t suc } bool AbstractInterpretation::isBranchFeasible(const IntraCFGEdge* intraEdge, - AbstractState& as) + AbstractStateImpl& as) { const SVFVar *cmpVar = intraEdge->getCondition(); if (cmpVar->getInEdges().empty()) @@ -561,18 +561,35 @@ void AbstractInterpretation::handleSingletonWTO(const ICFGSingletonWTO *icfgSing std::deque worklist; stat->getICFGNodeTrace()++; - // handle SVF Stmt + + // SINGLE TRAVERSAL: Update state and detect together! + // This eliminates redundant statement traversals that were previously + // happening in both the main loop and each detector's detect() method. for (const SVFStmt *stmt: node->getSVFStmts()) { + // 1. Update abstract state handleSVFStatement(stmt); + + // 2. Immediately detect issues in the same loop + for (auto& detector: detectors) + detector->checkStatement(stmt, getAbsStateFromTrace(node)); } - // inlining the callee by calling handleFunc for the callee function + + // Handle call sites (inlining the callee) if (const CallICFGNode* callnode = SVFUtil::dyn_cast(node)) { handleCallSite(callnode); + + // Check stub functions (e.g., SAFE_BUFACCESS, UNSAFE_BUFACCESS) + for (auto& detector : detectors) + detector->handleStubFunctions(callnode); } + + // Handle external API calls at call nodes (kept for backward compatibility) + // The detect() method now only handles external API calls, not GEP statements for (auto& detector: detectors) detector->detect(getAbsStateFromTrace(node), node); + stat->countStateSize(); } @@ -664,7 +681,7 @@ bool AbstractInterpretation::isRecursiveCall(const CallICFGNode *callNode) void AbstractInterpretation::recursiveCallPass(const CallICFGNode *callNode) { - AbstractState& as = getDenseAbsStateFromTrace(callNode); + AbstractStateImpl& as = getDenseAbsStateFromTrace(callNode); SkipRecursiveCall(callNode); const RetICFGNode *retNode = callNode->getRetICFGNode(); if (retNode->getSVFStmts().size() > 0) @@ -698,7 +715,7 @@ bool AbstractInterpretation::isDirectCall(const CallICFGNode *callNode) } void AbstractInterpretation::directCallFunPass(const CallICFGNode *callNode) { - AbstractState& as = getDenseAbsStateFromTrace(callNode); + AbstractStateImpl& as = getDenseAbsStateFromTrace(callNode); abstractTrace[callNode] = as; @@ -739,7 +756,7 @@ bool AbstractInterpretation::isIndirectCall(const CallICFGNode *callNode) void AbstractInterpretation::indirectCallFunPass(const CallICFGNode *callNode) { - AbstractState& as = getDenseAbsStateFromTrace(callNode); + AbstractStateImpl& as = getDenseAbsStateFromTrace(callNode); const auto callsiteMaps = svfir->getIndirectCallsites(); NodeID call_id = callsiteMaps.at(callNode); if (!as.inVarToAddrsTable(call_id)) @@ -784,9 +801,9 @@ void AbstractInterpretation::handleCycleWTO(const ICFGCycleWTO*cycle) if (cur_iter >= Options::WidenDelay()) { // Widen or narrow after processing cycle head node - AbstractState prev_head_state = abstractTrace[cycle_head]; + AbstractStateImpl prev_head_state = abstractTrace[cycle_head]; handleWTOComponent(cycle->head()); - AbstractState cur_head_state = abstractTrace[cycle_head]; + AbstractStateImpl cur_head_state = abstractTrace[cycle_head]; if (increasing) { @@ -800,7 +817,7 @@ void AbstractInterpretation::handleCycleWTO(const ICFGCycleWTO*cycle) } // Widening - abstractTrace[cycle_head] = prev_head_state.wideningDense(cur_head_state); + abstractTrace[cycle_head] = prev_head_state.widening(cur_head_state); if (abstractTrace[cycle_head] == prev_head_state) { @@ -822,7 +839,7 @@ void AbstractInterpretation::handleCycleWTO(const ICFGCycleWTO*cycle) else if (Options::HandleRecur() == WIDEN_NARROW) { // Widening's fixpoint reached in the widening phase, switch to narrowing - abstractTrace[cycle_head] = prev_head_state.narrowingDense(cur_head_state); + abstractTrace[cycle_head] = prev_head_state.narrowing(cur_head_state); if (abstractTrace[cycle_head] == prev_head_state) { // Narrowing's fixpoint reached in the narrowing phase, exit loop @@ -840,7 +857,7 @@ void AbstractInterpretation::handleCycleWTO(const ICFGCycleWTO*cycle) else { // Widening's fixpoint reached in the widening phase, switch to narrowing - abstractTrace[cycle_head] = prev_head_state.narrowingDense(cur_head_state); + abstractTrace[cycle_head] = prev_head_state.narrowing(cur_head_state); if (abstractTrace[cycle_head] == prev_head_state) { // Narrowing's fixpoint reached in the narrowing phase, exit loop @@ -922,13 +939,13 @@ void AbstractInterpretation::handleSVFStatement(const SVFStmt *stmt) void AbstractInterpretation::SkipRecursiveCall(const CallICFGNode *callNode) { - AbstractState& as = getDenseAbsStateFromTrace(callNode); + AbstractStateImpl& as = getDenseAbsStateFromTrace(callNode); const RetICFGNode *retNode = callNode->getRetICFGNode(); if (retNode->getSVFStmts().size() > 0) { if (const RetPE *retPE = SVFUtil::dyn_cast(*retNode->getSVFStmts().begin())) { - AbstractState as; + AbstractStateImpl as; if (!retPE->getLHSVar()->isPointer() && !retPE->getLHSVar()->isConstDataOrAggDataButNotNullPtr()) as[retPE->getLHSVarID()] = IntervalValue::top(); } @@ -1121,7 +1138,7 @@ void AbstractInterpretation::checkPointAllSet() void AbstractInterpretation::updateStateOnGep(const GepStmt *gep) { - AbstractState& as = getDenseAbsStateFromTrace(gep->getICFGNode()); + AbstractStateImpl& as = getDenseAbsStateFromTrace(gep->getICFGNode()); u32_t rhs = gep->getRHSVarID(); u32_t lhs = gep->getLHSVarID(); IntervalValue offsetPair = as.getElementIndex(gep); @@ -1137,7 +1154,7 @@ void AbstractInterpretation::updateStateOnGep(const GepStmt *gep) void AbstractInterpretation::updateStateOnSelect(const SelectStmt *select) { - AbstractState& as = getDenseAbsStateFromTrace(select->getICFGNode()); + AbstractStateImpl& as = getDenseAbsStateFromTrace(select->getICFGNode()); u32_t res = select->getResID(); u32_t tval = select->getTrueValue()->getId(); u32_t fval = select->getFalseValue()->getId(); @@ -1156,7 +1173,7 @@ void AbstractInterpretation::updateStateOnSelect(const SelectStmt *select) void AbstractInterpretation::updateStateOnPhi(const PhiStmt *phi) { const ICFGNode* icfgNode = phi->getICFGNode(); - AbstractState& as = getDenseAbsStateFromTrace(icfgNode); + AbstractStateImpl& as = getDenseAbsStateFromTrace(icfgNode); u32_t res = phi->getResID(); AbstractValue rhs; for (u32_t i = 0; i < phi->getOpVarNum(); i++) @@ -1165,8 +1182,8 @@ void AbstractInterpretation::updateStateOnPhi(const PhiStmt *phi) const ICFGNode* opICFGNode = phi->getOpICFGNode(i); if (hasAbsStateFromTrace(opICFGNode)) { - AbstractState tmpEs = abstractTrace[opICFGNode]; - AbstractState& opAs = getDenseAbsStateFromTrace(opICFGNode); + AbstractStateImpl tmpEs = abstractTrace[opICFGNode]; + AbstractStateImpl& opAs = getDenseAbsStateFromTrace(opICFGNode); const ICFGEdge* edge = icfg->getICFGEdge(opICFGNode, icfgNode, ICFGEdge::IntraCF); // if IntraEdge, check the condition, if it is feasible, join the value // if IntraEdge but not conditional edge, join the value @@ -1194,7 +1211,7 @@ void AbstractInterpretation::updateStateOnPhi(const PhiStmt *phi) void AbstractInterpretation::updateStateOnCall(const CallPE *callPE) { - AbstractState& as = getDenseAbsStateFromTrace(callPE->getICFGNode()); + AbstractStateImpl& as = getDenseAbsStateFromTrace(callPE->getICFGNode()); NodeID lhs = callPE->getLHSVarID(); NodeID rhs = callPE->getRHSVarID(); as[lhs] = as[rhs]; @@ -1202,7 +1219,7 @@ void AbstractInterpretation::updateStateOnCall(const CallPE *callPE) void AbstractInterpretation::updateStateOnRet(const RetPE *retPE) { - AbstractState& as = getDenseAbsStateFromTrace(retPE->getICFGNode()); + AbstractStateImpl& as = getDenseAbsStateFromTrace(retPE->getICFGNode()); NodeID lhs = retPE->getLHSVarID(); NodeID rhs = retPE->getRHSVarID(); as[lhs] = as[rhs]; @@ -1211,7 +1228,7 @@ void AbstractInterpretation::updateStateOnRet(const RetPE *retPE) void AbstractInterpretation::updateStateOnAddr(const AddrStmt *addr) { - AbstractState& as = getDenseAbsStateFromTrace(addr->getICFGNode()); + AbstractStateImpl& as = getDenseAbsStateFromTrace(addr->getICFGNode()); as.initObjVar(SVFUtil::cast(addr->getRHSVar())); if (addr->getRHSVar()->getType()->getKind() == SVFType::SVFIntegerTy) as[addr->getRHSVarID()].getInterval().meet_with(utils->getRangeLimitFromType(addr->getRHSVar()->getType())); @@ -1225,7 +1242,7 @@ void AbstractInterpretation::updateStateOnBinary(const BinaryOPStmt *binary) /// You are only required to handle integer predicates, including Add, FAdd, Sub, FSub, Mul, FMul, SDiv, FDiv, UDiv, /// SRem, FRem, URem, Xor, And, Or, AShr, Shl, LShr const ICFGNode* node = binary->getICFGNode(); - AbstractState& as = getDenseAbsStateFromTrace(node); + AbstractStateImpl& as = getDenseAbsStateFromTrace(node); u32_t op0 = binary->getOpVarID(0); u32_t op1 = binary->getOpVarID(1); u32_t res = binary->getResID(); @@ -1283,7 +1300,7 @@ void AbstractInterpretation::updateStateOnBinary(const BinaryOPStmt *binary) void AbstractInterpretation::updateStateOnCmp(const CmpStmt *cmp) { - AbstractState& as = getDenseAbsStateFromTrace(cmp->getICFGNode()); + AbstractStateImpl& as = getDenseAbsStateFromTrace(cmp->getICFGNode()); u32_t op0 = cmp->getOpVarID(0); u32_t op1 = cmp->getOpVarID(1); // if it is address @@ -1498,7 +1515,7 @@ void AbstractInterpretation::updateStateOnCmp(const CmpStmt *cmp) void AbstractInterpretation::updateStateOnLoad(const LoadStmt *load) { - AbstractState& as = getDenseAbsStateFromTrace(load->getICFGNode()); + AbstractStateImpl& as = getDenseAbsStateFromTrace(load->getICFGNode()); u32_t rhs = load->getRHSVarID(); u32_t lhs = load->getLHSVarID(); as[lhs] = as.loadValue(rhs); @@ -1506,7 +1523,7 @@ void AbstractInterpretation::updateStateOnLoad(const LoadStmt *load) void AbstractInterpretation::updateStateOnStore(const StoreStmt *store) { - AbstractState& as = getDenseAbsStateFromTrace(store->getICFGNode()); + AbstractStateImpl& as = getDenseAbsStateFromTrace(store->getICFGNode()); u32_t rhs = store->getRHSVarID(); u32_t lhs = store->getLHSVarID(); as.storeValue(lhs, as[rhs]); @@ -1514,7 +1531,7 @@ void AbstractInterpretation::updateStateOnStore(const StoreStmt *store) void AbstractInterpretation::updateStateOnCopy(const CopyStmt *copy) { - auto getZExtValue = [](AbstractState& as, const SVFVar* var) + auto getZExtValue = [](AbstractStateImpl& as, const SVFVar* var) { const SVFType* type = var->getType(); if (SVFUtil::isa(type)) @@ -1557,7 +1574,7 @@ void AbstractInterpretation::updateStateOnCopy(const CopyStmt *copy) return IntervalValue::top(); // TODO: may have better solution }; - auto getTruncValue = [&](const AbstractState& as, const SVFVar* var, + auto getTruncValue = [&](const AbstractStateImpl& as, const SVFVar* var, const SVFType* dstType) { const IntervalValue& itv = as[var->getId()].getInterval(); @@ -1610,7 +1627,7 @@ void AbstractInterpretation::updateStateOnCopy(const CopyStmt *copy) } }; - AbstractState& as = getDenseAbsStateFromTrace(copy->getICFGNode()); + AbstractStateImpl& as = getDenseAbsStateFromTrace(copy->getICFGNode()); u32_t lhs = copy->getLHSVarID(); u32_t rhs = copy->getRHSVarID(); From 2f111a588ae19f1f492200cdca6922c15a722935 Mon Sep 17 00:00:00 2001 From: bjjwwang Date: Fri, 23 Jan 2026 00:15:35 +1100 Subject: [PATCH 6/9] resume abstract state --- svf-llvm/tools/AE/ae.cpp | 176 +++++++++--------- svf/include/AE/Core/AbstractState.h | 114 +++++------- svf/include/AE/Core/AddressValue.h | 2 +- svf/include/AE/Core/IAbstractState.h | 152 --------------- svf/include/AE/Core/RelationSolver.h | 16 +- svf/include/AE/Svfexe/AEDetector.h | 1 - svf/include/AE/Svfexe/AbsExtAPI.h | 14 +- .../AE/Svfexe/AbstractInterpretation.h | 14 +- svf/lib/AE/Core/AbstractState.cpp | 83 +++------ svf/lib/AE/Core/RelationSolver.cpp | 44 ++--- svf/lib/AE/Svfexe/AEDetector.cpp | 12 +- svf/lib/AE/Svfexe/AbsExtAPI.cpp | 46 ++--- svf/lib/AE/Svfexe/AbstractInterpretation.cpp | 62 +++--- 13 files changed, 265 insertions(+), 471 deletions(-) delete mode 100644 svf/include/AE/Core/IAbstractState.h diff --git a/svf-llvm/tools/AE/ae.cpp b/svf-llvm/tools/AE/ae.cpp index d634e7179..5df194d2a 100644 --- a/svf-llvm/tools/AE/ae.cpp +++ b/svf-llvm/tools/AE/ae.cpp @@ -68,11 +68,11 @@ class SymblicAbstractionTest outs() << "hello print\n"; } - AbstractStateImpl RSY_time(AbstractStateImpl& inv, const Z3Expr& phi, + AbstractState RSY_time(AbstractState& inv, const Z3Expr& phi, RelationSolver& rs) { auto start_time = std::chrono::high_resolution_clock::now(); - AbstractStateImpl resRSY = rs.RSY(inv, phi); + AbstractState resRSY = rs.RSY(inv, phi); auto end_time = std::chrono::high_resolution_clock::now(); auto duration = std::chrono::duration_cast( end_time - start_time); @@ -80,11 +80,11 @@ class SymblicAbstractionTest << " microseconds\n"; return resRSY; } - AbstractStateImpl Bilateral_time(AbstractStateImpl& inv, const Z3Expr& phi, + AbstractState Bilateral_time(AbstractState& inv, const Z3Expr& phi, RelationSolver& rs) { auto start_time = std::chrono::high_resolution_clock::now(); - AbstractStateImpl resBilateral = rs.bilateral(inv, phi); + AbstractState resBilateral = rs.bilateral(inv, phi); auto end_time = std::chrono::high_resolution_clock::now(); auto duration = std::chrono::duration_cast( end_time - start_time); @@ -92,11 +92,11 @@ class SymblicAbstractionTest << " microseconds\n"; return resBilateral; } - AbstractStateImpl BS_time(AbstractStateImpl& inv, const Z3Expr& phi, + AbstractState BS_time(AbstractState& inv, const Z3Expr& phi, RelationSolver& rs) { auto start_time = std::chrono::high_resolution_clock::now(); - AbstractStateImpl resBS = rs.BS(inv, phi); + AbstractState resBS = rs.BS(inv, phi); auto end_time = std::chrono::high_resolution_clock::now(); auto duration = std::chrono::duration_cast( end_time - start_time); @@ -108,7 +108,7 @@ class SymblicAbstractionTest void testRelExeState1_1() { outs() << sucMsg("\t SUCCESS :") << "test1_1 start\n"; - AbstractStateImpl itv; + AbstractState itv; RelExeState relation; // var0 := [0, 1]; itv[0] = IntervalValue(0, 1); @@ -121,28 +121,28 @@ class SymblicAbstractionTest Set res; relation.extractSubVars(relation[1], res); assert(res == Set({0, 1}) && "inconsistency occurs"); - AbstractStateImpl inv = itv.sliceState(res); + AbstractState inv = itv.sliceState(res); RelationSolver rs; const Z3Expr& relExpr = relation[1]; const Z3Expr& initExpr = rs.gamma_hat(inv); const Z3Expr& phi = (relExpr && initExpr).simplify(); - AbstractStateImpl resRSY = rs.RSY(inv, phi); - AbstractStateImpl resBilateral = rs.bilateral(inv, phi); - AbstractStateImpl resBS = rs.BS(inv, phi); + AbstractState resRSY = rs.RSY(inv, phi); + AbstractState resBilateral = rs.bilateral(inv, phi); + AbstractState resBS = rs.BS(inv, phi); // 0:[0,1] 1:[1,2] assert(resRSY == resBS && resBS == resBilateral && "inconsistency occurs"); for (auto r : resRSY.getVarToVal()) { outs() << r.first << " " << r.second.getInterval() << "\n"; } - AbstractStateImpl::VarToAbsValMap intendedRes = {{0, IntervalValue(0, 1)}, {1, IntervalValue(1, 2)}}; - assert(AbstractStateImpl::eqVarToValMap(resBS.getVarToVal(), intendedRes) && "inconsistency occurs"); + AbstractState::VarToAbsValMap intendedRes = {{0, IntervalValue(0, 1)}, {1, IntervalValue(1, 2)}}; + assert(AbstractState::eqVarToValMap(resBS.getVarToVal(), intendedRes) && "inconsistency occurs"); } void testRelExeState1_2() { outs() << "test1_2 start\n"; - AbstractStateImpl itv; + AbstractState itv; RelExeState relation; // var0 := [0, 1]; relation[0] = getContext().int_const("0"); @@ -156,28 +156,28 @@ class SymblicAbstractionTest Set res; relation.extractSubVars(relation[1], res); assert(res == Set({0, 1}) && "inconsistency occurs"); - AbstractStateImpl inv = itv.sliceState(res); + AbstractState inv = itv.sliceState(res); RelationSolver rs; const Z3Expr& relExpr = relation[1]; const Z3Expr& initExpr = rs.gamma_hat(inv); const Z3Expr& phi = (relExpr && initExpr).simplify(); - AbstractStateImpl resRSY = rs.RSY(inv, phi); - AbstractStateImpl resBilateral = rs.bilateral(inv, phi); - AbstractStateImpl resBS = rs.BS(inv, phi); + AbstractState resRSY = rs.RSY(inv, phi); + AbstractState resBilateral = rs.bilateral(inv, phi); + AbstractState resBS = rs.BS(inv, phi); // 0:[0,1] 1:[0,2] assert(resRSY == resBS && resBS == resBilateral && "inconsistency occurs"); for (auto r : resRSY.getVarToVal()) { outs() << r.first << " " << r.second.getInterval() << "\n"; } - AbstractStateImpl::VarToAbsValMap intendedRes = {{0, IntervalValue(0, 1)}, {1, IntervalValue(0, 2)}}; - assert(AbstractStateImpl::eqVarToValMap(resBS.getVarToVal(), intendedRes) && "inconsistency occurs"); + AbstractState::VarToAbsValMap intendedRes = {{0, IntervalValue(0, 1)}, {1, IntervalValue(0, 2)}}; + assert(AbstractState::eqVarToValMap(resBS.getVarToVal(), intendedRes) && "inconsistency occurs"); } void testRelExeState2_1() { outs() << "test2_1 start\n"; - AbstractStateImpl itv; + AbstractState itv; RelExeState relation; // var0 := [0, 10]; relation[0] = getContext().int_const("0"); @@ -194,14 +194,14 @@ class SymblicAbstractionTest Set res; relation.extractSubVars(relation[2], res); assert(res == Set({0, 1, 2}) && "inconsistency occurs"); - AbstractStateImpl inv = itv.sliceState(res); + AbstractState inv = itv.sliceState(res); RelationSolver rs; const Z3Expr& relExpr = relation[2] && relation[1]; const Z3Expr& initExpr = rs.gamma_hat(inv); const Z3Expr& phi = (relExpr && initExpr).simplify(); - AbstractStateImpl resRSY = rs.RSY(inv, phi); - AbstractStateImpl resBilateral = rs.bilateral(inv, phi); - AbstractStateImpl resBS = rs.BS(inv, phi); + AbstractState resRSY = rs.RSY(inv, phi); + AbstractState resBilateral = rs.bilateral(inv, phi); + AbstractState resBS = rs.BS(inv, phi); // 0:[0,10] 1:[0,10] 2:[0,0] assert(resRSY == resBS && resBS == resBilateral && "inconsistency occurs"); for (auto r : resRSY.getVarToVal()) @@ -209,17 +209,17 @@ class SymblicAbstractionTest outs() << r.first << " " << r.second.getInterval() << "\n"; } // ground truth - AbstractStateImpl::VarToAbsValMap intendedRes = {{0, IntervalValue(0, 10)}, + AbstractState::VarToAbsValMap intendedRes = {{0, IntervalValue(0, 10)}, {1, IntervalValue(0, 10)}, {2, IntervalValue(0, 0)} }; - assert(AbstractStateImpl::eqVarToValMap(resBS.getVarToVal(), intendedRes) && "inconsistency occurs"); + assert(AbstractState::eqVarToValMap(resBS.getVarToVal(), intendedRes) && "inconsistency occurs"); } void testRelExeState2_2() { outs() << "test2_2 start\n"; - AbstractStateImpl itv; + AbstractState itv; RelExeState relation; // var0 := [0, 100]; relation[0] = getContext().int_const("0"); @@ -237,14 +237,14 @@ class SymblicAbstractionTest Set res; relation.extractSubVars(relation[2], res); assert(res == Set({0, 1, 2}) && "inconsistency occurs"); - AbstractStateImpl inv = itv.sliceState(res); + AbstractState inv = itv.sliceState(res); RelationSolver rs; const Z3Expr& relExpr = relation[2] && relation[1]; const Z3Expr& initExpr = rs.gamma_hat(inv); const Z3Expr& phi = (relExpr && initExpr).simplify(); - AbstractStateImpl resRSY = rs.RSY(inv, phi); - AbstractStateImpl resBilateral = rs.bilateral(inv, phi); - AbstractStateImpl resBS = rs.BS(inv, phi); + AbstractState resRSY = rs.RSY(inv, phi); + AbstractState resBilateral = rs.bilateral(inv, phi); + AbstractState resBS = rs.BS(inv, phi); // 0:[0,100] 1:[0,100] 2:[0,0] assert(resRSY == resBS && resBS == resBilateral && "inconsistency occurs"); for (auto r : resRSY.getVarToVal()) @@ -252,17 +252,17 @@ class SymblicAbstractionTest outs() << r.first << " " << r.second.getInterval() << "\n"; } // ground truth - AbstractStateImpl::VarToAbsValMap intendedRes = {{0, IntervalValue(0, 100)}, + AbstractState::VarToAbsValMap intendedRes = {{0, IntervalValue(0, 100)}, {1, IntervalValue(0, 100)}, {2, IntervalValue(0, 0)} }; - assert(AbstractStateImpl::eqVarToValMap(resBS.getVarToVal(), intendedRes) && "inconsistency occurs"); + assert(AbstractState::eqVarToValMap(resBS.getVarToVal(), intendedRes) && "inconsistency occurs"); } void testRelExeState2_3() { outs() << "test2_3 start\n"; - AbstractStateImpl itv; + AbstractState itv; RelExeState relation; // var0 := [0, 1000]; relation[0] = getContext().int_const("0"); @@ -280,14 +280,14 @@ class SymblicAbstractionTest Set res; relation.extractSubVars(relation[2], res); assert(res == Set({0, 1, 2}) && "inconsistency occurs"); - AbstractStateImpl inv = itv.sliceState(res); + AbstractState inv = itv.sliceState(res); RelationSolver rs; const Z3Expr& relExpr = relation[2] && relation[1]; const Z3Expr& initExpr = rs.gamma_hat(inv); const Z3Expr& phi = (relExpr && initExpr).simplify(); - AbstractStateImpl resRSY = rs.RSY(inv, phi); - AbstractStateImpl resBilateral = rs.bilateral(inv, phi); - AbstractStateImpl resBS = rs.BS(inv, phi); + AbstractState resRSY = rs.RSY(inv, phi); + AbstractState resBilateral = rs.bilateral(inv, phi); + AbstractState resBS = rs.BS(inv, phi); // 0:[0,1000] 1:[0,1000] 2:[0,0] assert(resRSY == resBS && resBS == resBilateral && "inconsistency occurs"); for (auto r : resRSY.getVarToVal()) @@ -295,17 +295,17 @@ class SymblicAbstractionTest outs() << r.first << " " << r.second.getInterval() << "\n"; } // ground truth - AbstractStateImpl::VarToAbsValMap intendedRes = {{0, IntervalValue(0, 1000)}, + AbstractState::VarToAbsValMap intendedRes = {{0, IntervalValue(0, 1000)}, {1, IntervalValue(0, 1000)}, {2, IntervalValue(0, 0)} }; - assert(AbstractStateImpl::eqVarToValMap(resBS.getVarToVal(), intendedRes) && "inconsistency occurs"); + assert(AbstractState::eqVarToValMap(resBS.getVarToVal(), intendedRes) && "inconsistency occurs"); } void testRelExeState2_4() { outs() << "test2_4 start\n"; - AbstractStateImpl itv; + AbstractState itv; RelExeState relation; // var0 := [0, 10000]; relation[0] = getContext().int_const("0"); @@ -323,14 +323,14 @@ class SymblicAbstractionTest Set res; relation.extractSubVars(relation[2], res); assert(res == Set({0, 1, 2}) && "inconsistency occurs"); - AbstractStateImpl inv = itv.sliceState(res); + AbstractState inv = itv.sliceState(res); RelationSolver rs; const Z3Expr& relExpr = relation[2] && relation[1]; const Z3Expr& initExpr = rs.gamma_hat(inv); const Z3Expr& phi = (relExpr && initExpr).simplify(); - AbstractStateImpl resRSY = RSY_time(inv, phi, rs); - AbstractStateImpl resBilateral = Bilateral_time(inv, phi, rs); - AbstractStateImpl resBS = BS_time(inv, phi, rs); + AbstractState resRSY = RSY_time(inv, phi, rs); + AbstractState resBilateral = Bilateral_time(inv, phi, rs); + AbstractState resBS = BS_time(inv, phi, rs); // 0:[0,10000] 1:[0,10000] 2:[0,0] assert(resRSY == resBS && resBS == resBilateral && "inconsistency occurs"); for (auto r : resRSY.getVarToVal()) @@ -338,17 +338,17 @@ class SymblicAbstractionTest outs() << r.first << " " << r.second.getInterval() << "\n"; } // ground truth - AbstractStateImpl::VarToAbsValMap intendedRes = {{0, IntervalValue(0, 10000)}, + AbstractState::VarToAbsValMap intendedRes = {{0, IntervalValue(0, 10000)}, {1, IntervalValue(0, 10000)}, {2, IntervalValue(0, 0)} }; - assert(AbstractStateImpl::eqVarToValMap(resBS.getVarToVal(), intendedRes) && "inconsistency occurs"); + assert(AbstractState::eqVarToValMap(resBS.getVarToVal(), intendedRes) && "inconsistency occurs"); } void testRelExeState2_5() { outs() << "test2_5 start\n"; - AbstractStateImpl itv; + AbstractState itv; RelExeState relation; // var0 := [0, 100000]; relation[0] = getContext().int_const("0"); @@ -366,14 +366,14 @@ class SymblicAbstractionTest Set res; relation.extractSubVars(relation[2], res); assert(res == Set({0, 1, 2}) && "inconsistency occurs"); - AbstractStateImpl inv = itv.sliceState(res); + AbstractState inv = itv.sliceState(res); RelationSolver rs; const Z3Expr& relExpr = relation[2] && relation[1]; const Z3Expr& initExpr = rs.gamma_hat(inv); const Z3Expr& phi = (relExpr && initExpr).simplify(); - AbstractStateImpl resRSY = RSY_time(inv, phi, rs); - AbstractStateImpl resBilateral = Bilateral_time(inv, phi, rs); - AbstractStateImpl resBS = BS_time(inv, phi, rs); + AbstractState resRSY = RSY_time(inv, phi, rs); + AbstractState resBilateral = Bilateral_time(inv, phi, rs); + AbstractState resBS = BS_time(inv, phi, rs); // 0:[0,100000] 1:[0,100000] 2:[0,0] assert(resRSY == resBS && resBS == resBilateral && "inconsistency occurs"); for (auto r : resRSY.getVarToVal()) @@ -381,17 +381,17 @@ class SymblicAbstractionTest outs() << r.first << " " << r.second.getInterval() << "\n"; } // ground truth - AbstractStateImpl::VarToAbsValMap intendedRes = {{0, IntervalValue(0, 100000)}, + AbstractState::VarToAbsValMap intendedRes = {{0, IntervalValue(0, 100000)}, {1, IntervalValue(0, 100000)}, {2, IntervalValue(0, 0)} }; - assert(AbstractStateImpl::eqVarToValMap(resBS.getVarToVal(), intendedRes) && "inconsistency occurs"); + assert(AbstractState::eqVarToValMap(resBS.getVarToVal(), intendedRes) && "inconsistency occurs"); } void testRelExeState3_1() { outs() << "test3_1 start\n"; - AbstractStateImpl itv; + AbstractState itv; RelExeState relation; // var0 := [1, 10]; relation[0] = getContext().int_const("0"); @@ -408,14 +408,14 @@ class SymblicAbstractionTest Set res; relation.extractSubVars(relation[2], res); assert(res == Set({0, 1, 2}) && "inconsistency occurs"); - AbstractStateImpl inv = itv.sliceState(res); + AbstractState inv = itv.sliceState(res); RelationSolver rs; const Z3Expr& relExpr = relation[2] && relation[1]; const Z3Expr& initExpr = rs.gamma_hat(inv); const Z3Expr& phi = (relExpr && initExpr).simplify(); - AbstractStateImpl resRSY = rs.RSY(inv, phi); - AbstractStateImpl resBilateral = rs.bilateral(inv, phi); - AbstractStateImpl resBS = rs.BS(inv, phi); + AbstractState resRSY = rs.RSY(inv, phi); + AbstractState resBilateral = rs.bilateral(inv, phi); + AbstractState resBS = rs.BS(inv, phi); // 0:[1,10] 1:[1,10] 2:[1,1] assert(resRSY == resBS && resBS == resBilateral && "inconsistency occurs"); for (auto r : resRSY.getVarToVal()) @@ -423,17 +423,17 @@ class SymblicAbstractionTest outs() << r.first << " " << r.second.getInterval() << "\n"; } // ground truth - AbstractStateImpl::VarToAbsValMap intendedRes = {{0, IntervalValue(1, 10)}, + AbstractState::VarToAbsValMap intendedRes = {{0, IntervalValue(1, 10)}, {1, IntervalValue(1, 10)}, {2, IntervalValue(1, 1)} }; - assert(AbstractStateImpl::eqVarToValMap(resBS.getVarToVal(), intendedRes) && "inconsistency occurs"); + assert(AbstractState::eqVarToValMap(resBS.getVarToVal(), intendedRes) && "inconsistency occurs"); } void testRelExeState3_2() { outs() << "test3_2 start\n"; - AbstractStateImpl itv; + AbstractState itv; RelExeState relation; // var0 := [1, 1000]; relation[0] = getContext().int_const("0"); @@ -450,14 +450,14 @@ class SymblicAbstractionTest Set res; relation.extractSubVars(relation[2], res); assert(res == Set({0, 1, 2}) && "inconsistency occurs"); - AbstractStateImpl inv = itv.sliceState(res); + AbstractState inv = itv.sliceState(res); RelationSolver rs; const Z3Expr& relExpr = relation[2] && relation[1]; const Z3Expr& initExpr = rs.gamma_hat(inv); const Z3Expr& phi = (relExpr && initExpr).simplify(); - AbstractStateImpl resRSY = rs.RSY(inv, phi); - AbstractStateImpl resBilateral = rs.bilateral(inv, phi); - AbstractStateImpl resBS = rs.BS(inv, phi); + AbstractState resRSY = rs.RSY(inv, phi); + AbstractState resBilateral = rs.bilateral(inv, phi); + AbstractState resBS = rs.BS(inv, phi); // 0:[1,1000] 1:[1,1000] 2:[1,1] assert(resRSY == resBS && resBS == resBilateral && "inconsistency occurs"); for (auto r : resRSY.getVarToVal()) @@ -465,17 +465,17 @@ class SymblicAbstractionTest outs() << r.first << " " << r.second.getInterval() << "\n"; } // ground truth - AbstractStateImpl::VarToAbsValMap intendedRes = {{0, IntervalValue(1, 1000)}, + AbstractState::VarToAbsValMap intendedRes = {{0, IntervalValue(1, 1000)}, {1, IntervalValue(1, 1000)}, {2, IntervalValue(1, 1)} }; - assert(AbstractStateImpl::eqVarToValMap(resBS.getVarToVal(), intendedRes) && "inconsistency occurs"); + assert(AbstractState::eqVarToValMap(resBS.getVarToVal(), intendedRes) && "inconsistency occurs"); } void testRelExeState3_3() { outs() << "test3_3 start\n"; - AbstractStateImpl itv; + AbstractState itv; RelExeState relation; // var0 := [1, 10000]; relation[0] = getContext().int_const("0"); @@ -492,14 +492,14 @@ class SymblicAbstractionTest Set res; relation.extractSubVars(relation[2], res); assert(res == Set({0, 1, 2}) && "inconsistency occurs"); - AbstractStateImpl inv = itv.sliceState(res); + AbstractState inv = itv.sliceState(res); RelationSolver rs; const Z3Expr& relExpr = relation[2] && relation[1]; const Z3Expr& initExpr = rs.gamma_hat(inv); const Z3Expr& phi = (relExpr && initExpr).simplify(); - AbstractStateImpl resRSY = RSY_time(inv, phi, rs); - AbstractStateImpl resBilateral = Bilateral_time(inv, phi, rs); - AbstractStateImpl resBS = BS_time(inv, phi, rs); + AbstractState resRSY = RSY_time(inv, phi, rs); + AbstractState resBilateral = Bilateral_time(inv, phi, rs); + AbstractState resBS = BS_time(inv, phi, rs); // 0:[1,10000] 1:[1,10000] 2:[1,1] assert(resRSY == resBS && resBS == resBilateral && "inconsistency occurs"); for (auto r : resRSY.getVarToVal()) @@ -507,7 +507,7 @@ class SymblicAbstractionTest outs() << r.first << " " << r.second.getInterval() << "\n"; } // ground truth - AbstractStateImpl::VarToAbsValMap intendedRes = {{0, IntervalValue(1, 10000)}, + AbstractState::VarToAbsValMap intendedRes = {{0, IntervalValue(1, 10000)}, {1, IntervalValue(1, 10000)}, {2, IntervalValue(1, 1)} }; @@ -516,7 +516,7 @@ class SymblicAbstractionTest void testRelExeState3_4() { outs() << "test3_4 start\n"; - AbstractStateImpl itv; + AbstractState itv; RelExeState relation; // var0 := [1, 100000]; relation[0] = getContext().int_const("0"); @@ -533,14 +533,14 @@ class SymblicAbstractionTest Set res; relation.extractSubVars(relation[2], res); assert(res == Set({0, 1, 2}) && "inconsistency occurs"); - AbstractStateImpl inv = itv.sliceState(res); + AbstractState inv = itv.sliceState(res); RelationSolver rs; const Z3Expr& relExpr = relation[2] && relation[1]; const Z3Expr& initExpr = rs.gamma_hat(inv); const Z3Expr& phi = (relExpr && initExpr).simplify(); - AbstractStateImpl resRSY = RSY_time(inv, phi, rs); - AbstractStateImpl resBilateral = Bilateral_time(inv, phi, rs); - AbstractStateImpl resBS = BS_time(inv, phi, rs); + AbstractState resRSY = RSY_time(inv, phi, rs); + AbstractState resBilateral = Bilateral_time(inv, phi, rs); + AbstractState resBS = BS_time(inv, phi, rs); // 0:[1,100000] 1:[1,100000] 2:[1,1] assert(resRSY == resBS && resBS == resBilateral && "inconsistency occurs"); for (auto r : resRSY.getVarToVal()) @@ -548,17 +548,17 @@ class SymblicAbstractionTest outs() << r.first << " " << r.second.getInterval() << "\n"; } // ground truth - AbstractStateImpl::VarToAbsValMap intendedRes = {{0, IntervalValue(1, 100000)}, + AbstractState::VarToAbsValMap intendedRes = {{0, IntervalValue(1, 100000)}, {1, IntervalValue(1, 100000)}, {2, IntervalValue(1, 1)} }; - assert(AbstractStateImpl::eqVarToValMap(resBS.getVarToVal(), intendedRes) && "inconsistency occurs"); + assert(AbstractState::eqVarToValMap(resBS.getVarToVal(), intendedRes) && "inconsistency occurs"); } void testRelExeState4_1() { outs() << "test4_1 start\n"; - AbstractStateImpl itv; + AbstractState itv; RelExeState relation; // var0 := [0, 10]; relation[0] = getContext().int_const("0"); @@ -575,7 +575,7 @@ class SymblicAbstractionTest Set res; relation.extractSubVars(relation[2], res); assert(res == Set({0, 1, 2}) && "inconsistency occurs"); - AbstractStateImpl inv = itv.sliceState(res); + AbstractState inv = itv.sliceState(res); RelationSolver rs; const Z3Expr& relExpr = relation[2] && relation[1]; const Z3Expr& initExpr = rs.gamma_hat(inv); @@ -584,7 +584,7 @@ class SymblicAbstractionTest outs() << "rsy done\n"; // IntervalExeState resBilateral = rs.bilateral(inv, phi); outs() << "bilateral done\n"; - AbstractStateImpl resBS = rs.BS(inv, phi); + AbstractState resBS = rs.BS(inv, phi); outs() << "bs done\n"; // 0:[0,10] 1:[0,10] 2:[-00,+00] // assert(resRSY == resBS && resBS == resBilateral); @@ -593,11 +593,11 @@ class SymblicAbstractionTest outs() << r.first << " " << r.second.getInterval() << "\n"; } // ground truth - AbstractStateImpl::VarToAbsValMap intendedRes = {{0, IntervalValue(0, 10)}, + AbstractState::VarToAbsValMap intendedRes = {{0, IntervalValue(0, 10)}, {1, IntervalValue(0, 10)}, {2, IntervalValue(0, 10)} }; - assert(AbstractStateImpl::eqVarToValMap(resBS.getVarToVal(), intendedRes) && "inconsistency occurs"); + assert(AbstractState::eqVarToValMap(resBS.getVarToVal(), intendedRes) && "inconsistency occurs"); } void testsValidation() @@ -827,7 +827,7 @@ class AETest void testAbsState() { - AbstractStateImpl as; + AbstractState as; as[1] = IntervalValue(1, 3); as[2] = IntervalValue(2, 7); as[3] = AddressValue(0x7f000007); diff --git a/svf/include/AE/Core/AbstractState.h b/svf/include/AE/Core/AbstractState.h index cd605dd0b..6711188af 100644 --- a/svf/include/AE/Core/AbstractState.h +++ b/svf/include/AE/Core/AbstractState.h @@ -48,7 +48,6 @@ #include "AE/Core/AbstractValue.h" #include "AE/Core/IntervalValue.h" -#include "AE/Core/IAbstractState.h" #include "SVFIR/SVFVariables.h" #include "Util/Z3Expr.h" @@ -56,7 +55,7 @@ namespace SVF { -class AbstractStateImpl : public AbstractState +class AbstractState { friend class SVFIR2AbsState; friend class RelationSolver; @@ -68,36 +67,36 @@ class AbstractStateImpl : public AbstractState public: /// default constructor - AbstractStateImpl() + AbstractState() { } - AbstractStateImpl(VarToAbsValMap&_varToValMap, AddrToAbsValMap&_locToValMap) : _varToAbsVal(_varToValMap), _addrToAbsVal(_locToValMap) {} + AbstractState(VarToAbsValMap&_varToValMap, AddrToAbsValMap&_locToValMap) : _varToAbsVal(_varToValMap), _addrToAbsVal(_locToValMap) {} /// copy constructor - AbstractStateImpl(const AbstractStateImpl&rhs) : _freedAddrs(rhs._freedAddrs), _varToAbsVal(rhs.getVarToVal()), _addrToAbsVal(rhs.getLocToVal()) + AbstractState(const AbstractState&rhs) : _freedAddrs(rhs._freedAddrs), _varToAbsVal(rhs.getVarToVal()), _addrToAbsVal(rhs.getLocToVal()) { } - virtual ~AbstractStateImpl() = default; + virtual ~AbstractState() = default; // getGepObjAddrs - AddressValue getGepObjAddrs(u32_t pointer, IntervalValue offset) override; + AddressValue getGepObjAddrs(u32_t pointer, IntervalValue offset); // initObjVar - void initObjVar(ObjVar* objVar) override; + void initObjVar(ObjVar* objVar); // getElementIndex - IntervalValue getElementIndex(const GepStmt* gep) override; + IntervalValue getElementIndex(const GepStmt* gep); // getByteOffset - IntervalValue getByteOffset(const GepStmt* gep) override; + IntervalValue getByteOffset(const GepStmt* gep); // printAbstractState // loadValue - AbstractValue loadValue(NodeID varId) override; + AbstractValue loadValue(NodeID varId); // storeValue - void storeValue(NodeID varId, AbstractValue val) override; + void storeValue(NodeID varId, AbstractValue val); - u32_t getAllocaInstByteSize(const AddrStmt *addr) override; + u32_t getAllocaInstByteSize(const AddrStmt *addr); /// The physical address starts with 0x7f...... + idx @@ -113,12 +112,11 @@ class AbstractStateImpl : public AbstractState } /// Return the internal index if addr is an address otherwise return the value of idx - inline u32_t getIDFromAddr(u32_t addr) override - { + inline u32_t getIDFromAddr(u32_t addr) { return _freedAddrs.count(addr) ? AddressValue::getInternalID(InvalidMemAddr) : AddressValue::getInternalID(addr); } - AbstractStateImpl&operator=(const AbstractStateImpl&rhs) + AbstractState&operator=(const AbstractState&rhs) { if (rhs != *this) { @@ -130,14 +128,14 @@ class AbstractStateImpl : public AbstractState } /// move constructor - AbstractStateImpl(AbstractStateImpl&&rhs) : _varToAbsVal(std::move(rhs._varToAbsVal)), + AbstractState(AbstractState&&rhs) : _varToAbsVal(std::move(rhs._varToAbsVal)), _addrToAbsVal(std::move(rhs._addrToAbsVal)) { } /// operator= move constructor - AbstractStateImpl&operator=(AbstractStateImpl&&rhs) + AbstractState&operator=(AbstractState&&rhs) { if (&rhs != this) { @@ -149,9 +147,9 @@ class AbstractStateImpl : public AbstractState } /// Set all value bottom - AbstractStateImpl bottom() const + AbstractState bottom() const { - AbstractStateImpl inv = *this; + AbstractState inv = *this; for (auto &item: inv._varToAbsVal) { if (item.second.isInterval()) @@ -161,9 +159,9 @@ class AbstractStateImpl : public AbstractState } /// Set all value top - AbstractStateImpl top() const + AbstractState top() const { - AbstractStateImpl inv = *this; + AbstractState inv = *this; for (auto &item: inv._varToAbsVal) { if (item.second.isInterval()) @@ -173,9 +171,9 @@ class AbstractStateImpl : public AbstractState } /// Copy some values and return a new IntervalExeState - AbstractStateImpl sliceState(Set &sl) + AbstractState sliceState(Set &sl) { - AbstractStateImpl inv; + AbstractState inv; for (u32_t id: sl) { inv._varToAbsVal[id] = _varToAbsVal[id]; @@ -203,20 +201,17 @@ class AbstractStateImpl : public AbstractState /// get abstract value of variable - inline AbstractValue &operator[](u32_t varId) override - { + inline AbstractValue &operator[](u32_t varId) { return _varToAbsVal[varId]; } /// get abstract value of variable - inline const AbstractValue &operator[](u32_t varId) const override - { + inline const AbstractValue &operator[](u32_t varId) const { return _varToAbsVal.at(varId); } /// whether the variable is in varToAddrs table - inline bool inVarToAddrsTable(u32_t id) const override - { + inline bool inVarToAddrsTable(u32_t id) const { if (_varToAbsVal.find(id)!= _varToAbsVal.end()) { if (_varToAbsVal.at(id).isAddr()) @@ -228,8 +223,7 @@ class AbstractStateImpl : public AbstractState } /// whether the variable is in varToVal table - inline bool inVarToValTable(u32_t id) const override - { + inline bool inVarToValTable(u32_t id) const { if (_varToAbsVal.find(id) != _varToAbsVal.end()) { if (_varToAbsVal.at(id).isInterval()) @@ -241,8 +235,7 @@ class AbstractStateImpl : public AbstractState } /// whether the memory address stores memory addresses - inline bool inAddrToAddrsTable(u32_t id) const override - { + inline bool inAddrToAddrsTable(u32_t id) const { if (_addrToAbsVal.find(id)!= _addrToAbsVal.end()) { if (_addrToAbsVal.at(id).isAddr()) @@ -254,8 +247,7 @@ class AbstractStateImpl : public AbstractState } /// whether the memory address stores abstract value - inline bool inAddrToValTable(u32_t id) const override - { + inline bool inAddrToValTable(u32_t id) const { if (_addrToAbsVal.find(id) != _addrToAbsVal.end()) { if (_addrToAbsVal.at(id).isInterval()) @@ -280,42 +272,24 @@ class AbstractStateImpl : public AbstractState public: - /// domain widen with other, and return the widened domain (interface version) - std::unique_ptr widening(const AbstractState& other) const override; - - /// domain narrow with other, and return the narrowed domain (interface version) - std::unique_ptr narrowing(const AbstractState& other) const override; - /// Widening operation - returns widened state - AbstractStateImpl widening(const AbstractStateImpl& other) const; + AbstractState widening(const AbstractState& other) const; /// Narrowing operation - returns narrowed state - AbstractStateImpl narrowing(const AbstractStateImpl& other) const; + AbstractState narrowing(const AbstractState& other) const; /// domain join with other, important! other widen this. - void joinWith(const AbstractState& other) override; + void joinWith(const AbstractState& other); /// domain meet with other, important! other widen this. - void meetWith(const AbstractState& other) override; + void meetWith(const AbstractState& other); - /// Clone this abstract state - std::unique_ptr clone() const override - { - return std::make_unique(*this); - } - - /// Get state type name - const char* getStateName() const override - { - return "DenseAbstractState"; - } - - void addToFreedAddrs(NodeID addr) override + void addToFreedAddrs(NodeID addr) { _freedAddrs.insert(addr); } - bool isFreedMem(u32_t addr) const override + bool isFreedMem(u32_t addr) const { return _freedAddrs.find(addr) != _freedAddrs.end(); } @@ -328,36 +302,34 @@ class AbstractStateImpl : public AbstractState * we can set arr[0]='c', arr[1]='c', arr[2]='\0' * @param call callnode of memset like api */ - const SVFType* getPointeeElement(NodeID id) override; + const SVFType* getPointeeElement(NodeID id); u32_t hash() const; public: - inline void store(u32_t addr, const AbstractValue &val) override - { + inline void store(u32_t addr, const AbstractValue &val) { assert(isVirtualMemAddress(addr) && "not virtual address?"); u32_t objId = getIDFromAddr(addr); if (isNullMem(addr)) return; _addrToAbsVal[objId] = val; } - inline AbstractValue &load(u32_t addr) override - { + inline AbstractValue &load(u32_t addr) { assert(isVirtualMemAddress(addr) && "not virtual address?"); u32_t objId = getIDFromAddr(addr); return _addrToAbsVal[objId]; } - void printAbstractState() const override; + void printAbstractState() const; std::string toString() const { return ""; } - bool equals(const AbstractState& other) const override; + bool equals(const AbstractState& other) const; static bool eqVarToValMap(const VarToAbsValMap&lhs, const VarToAbsValMap&rhs) @@ -407,24 +379,24 @@ class AbstractStateImpl : public AbstractState return true; } - bool operator==(const AbstractStateImpl&rhs) const + bool operator==(const AbstractState&rhs) const { return eqVarToValMap(_varToAbsVal, rhs.getVarToVal()) && eqVarToValMap(_addrToAbsVal, rhs.getLocToVal()); } - bool operator!=(const AbstractStateImpl&rhs) const + bool operator!=(const AbstractState&rhs) const { return !(*this == rhs); } - bool operator<(const AbstractStateImpl&rhs) const + bool operator<(const AbstractState&rhs) const { return !(*this >= rhs); } - bool operator>=(const AbstractStateImpl&rhs) const + bool operator>=(const AbstractState&rhs) const { return geqVarToValMap(_varToAbsVal, rhs.getVarToVal()) && geqVarToValMap(_addrToAbsVal, rhs.getLocToVal()); } diff --git a/svf/include/AE/Core/AddressValue.h b/svf/include/AE/Core/AddressValue.h index 4e6b71620..7295c186f 100644 --- a/svf/include/AE/Core/AddressValue.h +++ b/svf/include/AE/Core/AddressValue.h @@ -46,7 +46,7 @@ namespace SVF { class AddressValue { - friend class AbstractStateImpl; + friend class AbstractState; friend class RelExeState; public: typedef Set AddrSet; diff --git a/svf/include/AE/Core/IAbstractState.h b/svf/include/AE/Core/IAbstractState.h deleted file mode 100644 index fb465ab08..000000000 --- a/svf/include/AE/Core/IAbstractState.h +++ /dev/null @@ -1,152 +0,0 @@ -//===- AbstractState.h -- Abstract State Interface -------------------------// -// -// SVF: Static Value-Flow Analysis -// -// Copyright (C) <2013-2022> -// - -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU Affero General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. - -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU Affero General Public License for more details. - -// You should have received a copy of the GNU Affero General Public License -// along with this program. If not, see . -// -//===----------------------------------------------------------------------===// -/* - * AbstractState.h - * - * Interface for abstract state to support runtime polymorphism. - * This enables switching between different abstract state implementations - * (e.g., dense vs sparse) at runtime via factory pattern. - * - */ - -#ifndef SVF_ABSTRACTSTATE_H -#define SVF_ABSTRACTSTATE_H - -#include "AE/Core/AbstractValue.h" -#include "AE/Core/IntervalValue.h" -#include "SVFIR/SVFVariables.h" -#include - -namespace SVF -{ - -// Forward declarations -class GepStmt; -class AddrStmt; - -/// Abstract interface for abstract state implementations -/// This interface enables runtime polymorphism for different state representations -/// (e.g., DenseAbstractState, SparseAbstractState) -class AbstractState -{ -public: - virtual ~AbstractState() = default; - - //============= Core Domain Operations =============// - - /// Domain join with other state (modifies this state) - virtual void joinWith(const AbstractState& other) = 0; - - /// Domain meet with other state (modifies this state) - virtual void meetWith(const AbstractState& other) = 0; - - /// Check equality with another state - virtual bool equals(const AbstractState& other) const = 0; - - /// Widening operation - returns new widened state - virtual std::unique_ptr widening(const AbstractState& other) const = 0; - - /// Narrowing operation - returns new narrowed state - virtual std::unique_ptr narrowing(const AbstractState& other) const = 0; - - /// Clone this state - virtual std::unique_ptr clone() const = 0; - - //============= Variable Access Operations =============// - - /// Get abstract value of variable (mutable) - virtual AbstractValue& operator[](u32_t varId) = 0; - - /// Get abstract value of variable (const) - virtual const AbstractValue& operator[](u32_t varId) const = 0; - - /// Check if variable is in var-to-val table (interval value) - virtual bool inVarToValTable(u32_t id) const = 0; - - /// Check if variable is in var-to-addrs table (address value) - virtual bool inVarToAddrsTable(u32_t id) const = 0; - - /// Check if memory address stores interval value - virtual bool inAddrToValTable(u32_t id) const = 0; - - /// Check if memory address stores address value - virtual bool inAddrToAddrsTable(u32_t id) const = 0; - - //============= Memory Operations =============// - - /// Load value from addresses pointed by varId - virtual AbstractValue loadValue(NodeID varId) = 0; - - /// Store value to addresses pointed by varId - virtual void storeValue(NodeID varId, AbstractValue val) = 0; - - /// Store value to a specific memory address - virtual void store(u32_t addr, const AbstractValue& val) = 0; - - /// Load value from a specific memory address - virtual AbstractValue& load(u32_t addr) = 0; - - //============= GEP Operations =============// - - /// Get element index for GEP statement - virtual IntervalValue getElementIndex(const GepStmt* gep) = 0; - - /// Get byte offset for GEP statement - virtual IntervalValue getByteOffset(const GepStmt* gep) = 0; - - /// Get GEP object addresses given pointer and offset - virtual AddressValue getGepObjAddrs(u32_t pointer, IntervalValue offset) = 0; - - //============= Utility Operations =============// - - /// Get internal ID from virtual memory address - virtual u32_t getIDFromAddr(u32_t addr) = 0; - - /// Initialize object variable - virtual void initObjVar(ObjVar* objVar) = 0; - - /// Get byte size of alloca instruction - virtual u32_t getAllocaInstByteSize(const AddrStmt* addr) = 0; - - /// Get pointee element type - virtual const SVFType* getPointeeElement(NodeID id) = 0; - - /// Add address to freed addresses set - virtual void addToFreedAddrs(NodeID addr) = 0; - - /// Check if address is freed - virtual bool isFreedMem(u32_t addr) const = 0; - - /// Print abstract state for debugging - virtual void printAbstractState() const = 0; - - /// Get state type name for identification - virtual const char* getStateName() const = 0; - - //============= Static Address Utilities =============// - // Note: These remain static in AbstractState for backward compatibility - // and can be called via AbstractState::isNullMem, etc. -}; - -} // namespace SVF - -#endif // SVF_ABSTRACTSTATE_H diff --git a/svf/include/AE/Core/RelationSolver.h b/svf/include/AE/Core/RelationSolver.h index 0686eae16..ac9131eb5 100644 --- a/svf/include/AE/Core/RelationSolver.h +++ b/svf/include/AE/Core/RelationSolver.h @@ -44,17 +44,17 @@ class RelationSolver IntervalESBase (the last element of inputs) for RSY or bilateral solver */ /// Return Z3Expr according to valToValMap - Z3Expr gamma_hat(const AbstractStateImpl&exeState) const; + Z3Expr gamma_hat(const AbstractState&exeState) const; /// Return Z3Expr according to another valToValMap - Z3Expr gamma_hat(const AbstractStateImpl&alpha, const AbstractStateImpl&exeState) const; + Z3Expr gamma_hat(const AbstractState&alpha, const AbstractState&exeState) const; /// Return Z3Expr from a NodeID - Z3Expr gamma_hat(u32_t id, const AbstractStateImpl&exeState) const; + Z3Expr gamma_hat(u32_t id, const AbstractState&exeState) const; - AbstractStateImpl abstract_consequence(const AbstractStateImpl&lower, const AbstractStateImpl&upper, const AbstractStateImpl&domain) const; + AbstractState abstract_consequence(const AbstractState&lower, const AbstractState&upper, const AbstractState&domain) const; - AbstractStateImpl beta(const Map &sigma, const AbstractStateImpl&exeState) const; + AbstractState beta(const Map &sigma, const AbstractState&exeState) const; /// Return Z3 expression lazily based on SVFVar ID @@ -74,13 +74,13 @@ class RelationSolver /* two optional solvers: RSY and bilateral */ - AbstractStateImpl bilateral(const AbstractStateImpl& domain, const Z3Expr &phi, u32_t descend_check = 0); + AbstractState bilateral(const AbstractState& domain, const Z3Expr &phi, u32_t descend_check = 0); - AbstractStateImpl RSY(const AbstractStateImpl& domain, const Z3Expr &phi); + AbstractState RSY(const AbstractState& domain, const Z3Expr &phi); Map BoxedOptSolver(const Z3Expr& phi, Map& ret, Map& low_values, Map& high_values); - AbstractStateImpl BS(const AbstractStateImpl& domain, const Z3Expr &phi); + AbstractState BS(const AbstractState& domain, const Z3Expr &phi); void updateMap(Map& map, u32_t key, const s32_t& value); diff --git a/svf/include/AE/Svfexe/AEDetector.h b/svf/include/AE/Svfexe/AEDetector.h index 770c9679c..7356ee913 100644 --- a/svf/include/AE/Svfexe/AEDetector.h +++ b/svf/include/AE/Svfexe/AEDetector.h @@ -27,7 +27,6 @@ // #pragma once #include -#include #include #include "Util/SVFBugReport.h" diff --git a/svf/include/AE/Svfexe/AbsExtAPI.h b/svf/include/AE/Svfexe/AbsExtAPI.h index 121c56a49..b97da7ba5 100644 --- a/svf/include/AE/Svfexe/AbsExtAPI.h +++ b/svf/include/AE/Svfexe/AbsExtAPI.h @@ -53,7 +53,7 @@ class AbsExtAPI * @brief Constructor for AbsExtAPI. * @param abstractTrace Reference to a map of ICFG nodes to abstract states. */ - AbsExtAPI(Map& traces); + AbsExtAPI(Map& traces); /** * @brief Initializes the external function map. @@ -66,7 +66,7 @@ class AbsExtAPI * @param rhs Pointer to the SVF variable representing the string. * @return The string value. */ - std::string strRead(AbstractStateImpl& as, const SVFVar* rhs); + std::string strRead(AbstractState& as, const SVFVar* rhs); /** * @brief Handles an external API call. @@ -86,7 +86,7 @@ class AbsExtAPI * @param strValue Pointer to the SVF variable representing the string. * @return The interval value representing the string length. */ - IntervalValue getStrlen(AbstractStateImpl& as, const SVF::SVFVar *strValue); + IntervalValue getStrlen(AbstractState& as, const SVF::SVFVar *strValue); /** * @brief Handles the strcat API call. @@ -102,7 +102,7 @@ class AbsExtAPI * @param len The interval value representing the length to copy. * @param start_idx The starting index for copying. */ - void handleMemcpy(AbstractStateImpl& as, const SVF::SVFVar *dst, const SVF::SVFVar *src, IntervalValue len, u32_t start_idx); + void handleMemcpy(AbstractState& as, const SVF::SVFVar *dst, const SVF::SVFVar *src, IntervalValue len, u32_t start_idx); /** * @brief Handles the memset API call. @@ -111,7 +111,7 @@ class AbsExtAPI * @param elem The interval value representing the element to set. * @param len The interval value representing the length to set. */ - void handleMemset(AbstractStateImpl& as, const SVFVar* dst, IntervalValue elem, IntervalValue len); + void handleMemset(AbstractState& as, const SVFVar* dst, IntervalValue elem, IntervalValue len); /** * @brief Gets the range limit from a type. @@ -126,12 +126,12 @@ class AbsExtAPI * @return Reference to the abstract state. * @throws Assertion if no trace exists for the node. */ - AbstractStateImpl& getAbsStateFromTrace(const ICFGNode* node); + AbstractState& getAbsStateFromTrace(const ICFGNode* node); protected: SVFIR* svfir; ///< Pointer to the SVF intermediate representation. ICFG* icfg; ///< Pointer to the interprocedural control flow graph. - Map& abstractTrace; ///< Map of ICFG nodes to abstract states. + Map& abstractTrace; ///< Map of ICFG nodes to abstract states. Map> func_map; ///< Map of function names to handlers. }; diff --git a/svf/include/AE/Svfexe/AbstractInterpretation.h b/svf/include/AE/Svfexe/AbstractInterpretation.h index f5cc4e252..839535a78 100644 --- a/svf/include/AE/Svfexe/AbstractInterpretation.h +++ b/svf/include/AE/Svfexe/AbstractInterpretation.h @@ -178,8 +178,8 @@ class AbstractInterpretation } } - /// Dense state access from trace (for internal use when AbstractStateImpl is needed) - AbstractStateImpl& getDenseAbsStateFromTrace(const ICFGNode* node) + /// Dense state access from trace (for internal use when AbstractState is needed) + AbstractState& getDenseAbsStateFromTrace(const ICFGNode* node) { if (abstractTrace.count(node) == 0) { @@ -213,7 +213,7 @@ class AbstractInterpretation * @param intraEdge the edge from CmpStmt to the next node * @return if this edge is feasible */ - bool isBranchFeasible(const IntraCFGEdge* intraEdge, AbstractStateImpl& as); + bool isBranchFeasible(const IntraCFGEdge* intraEdge, AbstractState& as); /** * handle instructions in ICFGSingletonWTO @@ -264,7 +264,7 @@ class AbstractInterpretation * @return if this ICFGNode has preceding execution state */ bool isCmpBranchFeasible(const CmpStmt* cmpStmt, s64_t succ, - AbstractStateImpl& as); + AbstractState& as); /** * Check if this SwitchInst and succ are satisfiable to the execution state. @@ -274,7 +274,7 @@ class AbstractInterpretation * @return if this ICFGNode has preceding execution state */ bool isSwitchBranchFeasible(const SVFVar* var, s64_t succ, - AbstractStateImpl& as); + AbstractState& as); void collectCheckPoint(); @@ -327,7 +327,7 @@ class AbstractInterpretation std::unique_ptr createState() { // TODO: if (Options::UseSparseState()) - return std::make_unique(); + return std::make_unique(); } AbsExtAPI* getUtils() @@ -350,7 +350,7 @@ class AbstractInterpretation // there data should be shared with subclasses Map> func_map; - Map abstractTrace; // abstract states immediately after nodes + Map abstractTrace; // abstract states immediately after nodes std::string moduleName; std::vector> detectors; diff --git a/svf/lib/AE/Core/AbstractState.cpp b/svf/lib/AE/Core/AbstractState.cpp index a6c53f822..6d4b7ef9c 100644 --- a/svf/lib/AE/Core/AbstractState.cpp +++ b/svf/lib/AE/Core/AbstractState.cpp @@ -35,17 +35,12 @@ using namespace SVF; using namespace SVFUtil; -bool AbstractStateImpl::equals(const AbstractState& other) const +bool AbstractState::equals(const AbstractState& other) const { - const AbstractStateImpl* otherState = dynamic_cast(&other); - if (!otherState) - { - return false; // Different state types are never equal - } - return *this == *otherState; + return *this == other; } -u32_t AbstractStateImpl::hash() const +u32_t AbstractState::hash() const { size_t h = getVarToVal().size() * 2; Hash hf; @@ -62,10 +57,10 @@ u32_t AbstractStateImpl::hash() const return pairH({h, h2}); } -AbstractStateImpl AbstractStateImpl::widening(const AbstractStateImpl& other) const +AbstractState AbstractState::widening(const AbstractState& other) const { // widen interval - AbstractStateImpl es = *this; + AbstractState es = *this; for (auto it = es._varToAbsVal.begin(); it != es._varToAbsVal.end(); ++it) { auto key = it->first; @@ -83,16 +78,9 @@ AbstractStateImpl AbstractStateImpl::widening(const AbstractStateImpl& other) co return es; } -std::unique_ptr AbstractStateImpl::widening(const AbstractState& other) const -{ - const AbstractStateImpl* otherState = dynamic_cast(&other); - assert(otherState && "Type mismatch in widening: expected AbstractStateImpl"); - return std::make_unique(widening(*otherState)); -} - -AbstractStateImpl AbstractStateImpl::narrowing(const AbstractStateImpl& other) const +AbstractState AbstractState::narrowing(const AbstractState& other) const { - AbstractStateImpl es = *this; + AbstractState es = *this; for (auto it = es._varToAbsVal.begin(); it != es._varToAbsVal.end(); ++it) { auto key = it->first; @@ -110,20 +98,10 @@ AbstractStateImpl AbstractStateImpl::narrowing(const AbstractStateImpl& other) c return es; } -std::unique_ptr AbstractStateImpl::narrowing(const AbstractState& other) const -{ - const AbstractStateImpl* otherState = dynamic_cast(&other); - assert(otherState && "Type mismatch in narrowing: expected AbstractStateImpl"); - return std::make_unique(narrowing(*otherState)); -} - /// domain join with other, important! other widen this. -void AbstractStateImpl::joinWith(const AbstractState& other) +void AbstractState::joinWith(const AbstractState& other) { - const AbstractStateImpl* otherState = dynamic_cast(&other); - assert(otherState && "Type mismatch in joinWith: expected AbstractStateImpl"); - - for (auto it = otherState->_varToAbsVal.begin(); it != otherState->_varToAbsVal.end(); ++it) + for (auto it = other._varToAbsVal.begin(); it != other._varToAbsVal.end(); ++it) { auto key = it->first; auto oit = _varToAbsVal.find(key); @@ -136,7 +114,7 @@ void AbstractStateImpl::joinWith(const AbstractState& other) _varToAbsVal.emplace(key, it->second); } } - for (auto it = otherState->_addrToAbsVal.begin(); it != otherState->_addrToAbsVal.end(); ++it) + for (auto it = other._addrToAbsVal.begin(); it != other._addrToAbsVal.end(); ++it) { auto key = it->first; auto oit = _addrToAbsVal.find(key); @@ -149,16 +127,13 @@ void AbstractStateImpl::joinWith(const AbstractState& other) _addrToAbsVal.emplace(key, it->second); } } - _freedAddrs.insert(otherState->_freedAddrs.begin(), otherState->_freedAddrs.end()); + _freedAddrs.insert(other._freedAddrs.begin(), other._freedAddrs.end()); } /// domain meet with other, important! other widen this. -void AbstractStateImpl::meetWith(const AbstractState& other) +void AbstractState::meetWith(const AbstractState& other) { - const AbstractStateImpl* otherState = dynamic_cast(&other); - assert(otherState && "Type mismatch in meetWith: expected AbstractStateImpl"); - - for (auto it = otherState->_varToAbsVal.begin(); it != otherState->_varToAbsVal.end(); ++it) + for (auto it = other._varToAbsVal.begin(); it != other._varToAbsVal.end(); ++it) { auto key = it->first; auto oit = _varToAbsVal.find(key); @@ -167,7 +142,7 @@ void AbstractStateImpl::meetWith(const AbstractState& other) oit->second.meet_with(it->second); } } - for (auto it = otherState->_addrToAbsVal.begin(); it != otherState->_addrToAbsVal.end(); ++it) + for (auto it = other._addrToAbsVal.begin(); it != other._addrToAbsVal.end(); ++it) { auto key = it->first; auto oit = _addrToAbsVal.find(key); @@ -178,13 +153,13 @@ void AbstractStateImpl::meetWith(const AbstractState& other) } Set intersection; std::set_intersection(_freedAddrs.begin(), _freedAddrs.end(), - otherState->_freedAddrs.begin(), otherState->_freedAddrs.end(), + other._freedAddrs.begin(), other._freedAddrs.end(), std::inserter(intersection, intersection.begin())); _freedAddrs = std::move(intersection); } // getGepObjAddrs -AddressValue AbstractStateImpl::getGepObjAddrs(u32_t pointer, IntervalValue offset) +AddressValue AbstractState::getGepObjAddrs(u32_t pointer, IntervalValue offset) { AddressValue gepAddrs; APOffset lb = offset.lb().getIntNumeral() < Options::MaxFieldLimit() ? offset.lb().getIntNumeral() @@ -199,15 +174,15 @@ AddressValue AbstractStateImpl::getGepObjAddrs(u32_t pointer, IntervalValue offs s64_t baseObj = getIDFromAddr(addr); assert(SVFUtil::isa(PAG::getPAG()->getGNode(baseObj)) && "Fail to get the base object address!"); NodeID gepObj = PAG::getPAG()->getGepObjVar(baseObj, i); - (*this)[gepObj] = AddressValue(AbstractStateImpl::getVirtualMemAddress(gepObj)); - gepAddrs.insert(AbstractStateImpl::getVirtualMemAddress(gepObj)); + (*this)[gepObj] = AddressValue(AbstractState::getVirtualMemAddress(gepObj)); + gepAddrs.insert(AbstractState::getVirtualMemAddress(gepObj)); } } return gepAddrs; } // initObjVar -void AbstractStateImpl::initObjVar(ObjVar* objVar) +void AbstractState::initObjVar(ObjVar* objVar) { NodeID varId = objVar->getId(); @@ -233,7 +208,7 @@ void AbstractStateImpl::initObjVar(ObjVar* objVar) } else if (SVFUtil::isa(objVar)) { - (*this)[varId] = AddressValue(AbstractStateImpl::getVirtualMemAddress(varId)); + (*this)[varId] = AddressValue(AbstractState::getVirtualMemAddress(varId)); } else if (obj->isConstantArray() || obj->isConstantStruct()) { @@ -247,13 +222,13 @@ void AbstractStateImpl::initObjVar(ObjVar* objVar) // Handle non-constant memory objects else { - (*this)[varId] = AddressValue(AbstractStateImpl::getVirtualMemAddress(varId)); + (*this)[varId] = AddressValue(AbstractState::getVirtualMemAddress(varId)); } return; } // getElementIndex -IntervalValue AbstractStateImpl::getElementIndex(const GepStmt* gep) +IntervalValue AbstractState::getElementIndex(const GepStmt* gep) { // If the GEP statement has a constant offset, return it directly as the interval value if (gep->isConstantOffset()) @@ -326,7 +301,7 @@ IntervalValue AbstractStateImpl::getElementIndex(const GepStmt* gep) return res; } // getByteOffset -IntervalValue AbstractStateImpl::getByteOffset(const GepStmt* gep) +IntervalValue AbstractState::getByteOffset(const GepStmt* gep) { // If the GEP statement has a constant byte offset, return it directly as the interval value if (gep->isConstantOffset()) @@ -393,7 +368,7 @@ IntervalValue AbstractStateImpl::getByteOffset(const GepStmt* gep) return res; // Return the resulting byte offset as an IntervalValue. } -AbstractValue AbstractStateImpl::loadValue(NodeID varId) +AbstractValue AbstractState::loadValue(NodeID varId) { AbstractValue res; for (auto addr : (*this)[varId].getAddrs()) @@ -403,7 +378,7 @@ AbstractValue AbstractStateImpl::loadValue(NodeID varId) return res; } // storeValue -void AbstractStateImpl::storeValue(NodeID varId, AbstractValue val) +void AbstractState::storeValue(NodeID varId, AbstractValue val) { for (auto addr : (*this)[varId].getAddrs()) { @@ -411,7 +386,7 @@ void AbstractStateImpl::storeValue(NodeID varId, AbstractValue val) } } -void AbstractStateImpl::printAbstractState() const +void AbstractState::printAbstractState() const { SVFUtil::outs() << "-----------Var and Value-----------\n"; u32_t fieldWidth = 20; @@ -461,7 +436,7 @@ void AbstractStateImpl::printAbstractState() const for (const auto& item: addrToAbsValVec) { std::ostringstream oss; - oss << "0x" << std::hex << AbstractStateImpl::getVirtualMemAddress(item.first); + oss << "0x" << std::hex << AbstractState::getVirtualMemAddress(item.first); SVFUtil::outs() << std::left << std::setw(fieldWidth) << oss.str(); if (item.second.isInterval()) { @@ -493,7 +468,7 @@ void AbstractStateImpl::printAbstractState() const SVFUtil::outs() << "-----------------------------------------\n"; } -const SVFType* AbstractStateImpl::getPointeeElement(NodeID id) +const SVFType* AbstractState::getPointeeElement(NodeID id) { SVFIR* svfir = PAG::getPAG(); if (inVarToAddrsTable(id)) @@ -514,7 +489,7 @@ const SVFType* AbstractStateImpl::getPointeeElement(NodeID id) return nullptr; } -u32_t AbstractStateImpl::getAllocaInstByteSize(const AddrStmt *addr) +u32_t AbstractState::getAllocaInstByteSize(const AddrStmt *addr) { if (const ObjVar* objvar = SVFUtil::dyn_cast(addr->getRHSVar())) { diff --git a/svf/lib/AE/Core/RelationSolver.cpp b/svf/lib/AE/Core/RelationSolver.cpp index a0a43e64b..a5cc9dd9d 100644 --- a/svf/lib/AE/Core/RelationSolver.cpp +++ b/svf/lib/AE/Core/RelationSolver.cpp @@ -33,19 +33,19 @@ using namespace SVF; using namespace SVFUtil; -AbstractStateImpl RelationSolver::bilateral(const AbstractStateImpl&domain, const Z3Expr& phi, +AbstractState RelationSolver::bilateral(const AbstractState&domain, const Z3Expr& phi, u32_t descend_check) { /// init variables - AbstractStateImpl upper = domain.top(); - AbstractStateImpl lower = domain.bottom(); + AbstractState upper = domain.top(); + AbstractState lower = domain.bottom(); u32_t meets_in_a_row = 0; z3::solver solver = Z3Expr::getSolver(); z3::params p(Z3Expr::getContext()); /// TODO: add option for timeout p.set(":timeout", static_cast(600)); // in milliseconds solver.set(p); - AbstractStateImpl consequence; + AbstractState consequence; /// start processing while (lower != upper) @@ -85,9 +85,9 @@ AbstractStateImpl RelationSolver::bilateral(const AbstractStateImpl&domain, cons } } solver.pop(); - AbstractStateImpl newLower = domain.bottom(); + AbstractState newLower = domain.bottom(); newLower.joinWith(lower); - AbstractStateImpl rhs = beta(solution, domain); + AbstractState rhs = beta(solution, domain); newLower.joinWith(rhs); lower = newLower; meets_in_a_row = 0; @@ -101,7 +101,7 @@ AbstractStateImpl RelationSolver::bilateral(const AbstractStateImpl&domain, cons if (solver.reason_unknown() == "timeout") return upper; } - AbstractStateImpl newUpper = domain.top(); + AbstractState newUpper = domain.top(); newUpper.meetWith(upper); newUpper.meetWith(consequence); upper = newUpper; @@ -111,9 +111,9 @@ AbstractStateImpl RelationSolver::bilateral(const AbstractStateImpl&domain, cons return upper; } -AbstractStateImpl RelationSolver::RSY(const AbstractStateImpl& domain, const Z3Expr& phi) +AbstractState RelationSolver::RSY(const AbstractState& domain, const Z3Expr& phi) { - AbstractStateImpl lower = domain.bottom(); + AbstractState lower = domain.bottom(); z3::solver& solver = Z3Expr::getSolver(); z3::params p(Z3Expr::getContext()); /// TODO: add option for timeout @@ -147,7 +147,7 @@ AbstractStateImpl RelationSolver::RSY(const AbstractStateImpl& domain, const Z3E } } solver.pop(); - AbstractStateImpl newLower = domain.bottom(); + AbstractState newLower = domain.bottom(); newLower.joinWith(lower); newLower.joinWith(beta(solution, domain)); lower = newLower; @@ -167,8 +167,8 @@ AbstractStateImpl RelationSolver::RSY(const AbstractStateImpl& domain, const Z3E return lower; } -AbstractStateImpl RelationSolver::abstract_consequence( - const AbstractStateImpl& lower, const AbstractStateImpl& upper, const AbstractStateImpl& domain) const +AbstractState RelationSolver::abstract_consequence( + const AbstractState& lower, const AbstractState& upper, const AbstractState& domain) const { /*Returns the "abstract consequence" of lower and upper. @@ -184,7 +184,7 @@ AbstractStateImpl RelationSolver::abstract_consequence( it != domain.getVarToVal().end(); ++it) /// for variable in self.variables: { - AbstractStateImpl proposed = domain.top(); /// proposed = self.top.copy() + AbstractState proposed = domain.top(); /// proposed = self.top.copy() proposed[it->first] = lower[it->first].getInterval(); /// proposed.set_interval(variable, lower.interval_of(variable)) /// proposed._locToItvVal @@ -196,7 +196,7 @@ AbstractStateImpl RelationSolver::abstract_consequence( return lower; /// return lower.copy() } -Z3Expr RelationSolver::gamma_hat(const AbstractStateImpl& exeState) const +Z3Expr RelationSolver::gamma_hat(const AbstractState& exeState) const { Z3Expr res(Z3Expr::getContext().bool_val(true)); for (auto& item : exeState.getVarToVal()) @@ -213,8 +213,8 @@ Z3Expr RelationSolver::gamma_hat(const AbstractStateImpl& exeState) const return res; } -Z3Expr RelationSolver::gamma_hat(const AbstractStateImpl& alpha, - const AbstractStateImpl& exeState) const +Z3Expr RelationSolver::gamma_hat(const AbstractState& alpha, + const AbstractState& exeState) const { Z3Expr res(Z3Expr::getContext().bool_val(true)); for (auto& item : exeState.getVarToVal()) @@ -231,7 +231,7 @@ Z3Expr RelationSolver::gamma_hat(const AbstractStateImpl& alpha, return res; } -Z3Expr RelationSolver::gamma_hat(u32_t id, const AbstractStateImpl& exeState) const +Z3Expr RelationSolver::gamma_hat(u32_t id, const AbstractState& exeState) const { auto it = exeState.getVarToVal().find(id); assert(it != exeState.getVarToVal().end() && "id not in varToVal?"); @@ -242,10 +242,10 @@ Z3Expr RelationSolver::gamma_hat(u32_t id, const AbstractStateImpl& exeState) co return res; } -AbstractStateImpl RelationSolver::beta(const Map& sigma, - const AbstractStateImpl& exeState) const +AbstractState RelationSolver::beta(const Map& sigma, + const AbstractState& exeState) const { - AbstractStateImpl res; + AbstractState res; for (const auto& item : exeState.getVarToVal()) { res[item.first] = IntervalValue( @@ -267,7 +267,7 @@ void RelationSolver::updateMap(Map& map, u32_t key, const s32_t& v } } -AbstractStateImpl RelationSolver::BS(const AbstractStateImpl& domain, const Z3Expr &phi) +AbstractState RelationSolver::BS(const AbstractState& domain, const Z3Expr &phi) { /// because key of _varToItvVal is u32_t, -key may out of range for int /// so we do key + bias for -key @@ -315,7 +315,7 @@ AbstractStateImpl RelationSolver::BS(const AbstractStateImpl& domain, const Z3Ex /// optimize each object BoxedOptSolver(new_phi.simplify(), ret, low_values, high_values); /// fill in the return values - AbstractStateImpl retInv; + AbstractState retInv; for (const auto& item: ret) { if (item.first >= bias) diff --git a/svf/lib/AE/Svfexe/AEDetector.cpp b/svf/lib/AE/Svfexe/AEDetector.cpp index 7eb1b07fd..56000935f 100644 --- a/svf/lib/AE/Svfexe/AEDetector.cpp +++ b/svf/lib/AE/Svfexe/AEDetector.cpp @@ -150,7 +150,7 @@ void BufOverflowDetector::updateGepObjOffsetFromBase(AbstractState& as, SVF::Add } else { - assert(AbstractStateImpl::isInvalidMem(gepAddr) && "GEP object is neither a GepObjVar nor an invalid memory address"); + assert(AbstractState::isInvalidMem(gepAddr) && "GEP object is neither a GepObjVar nor an invalid memory address"); } } } @@ -181,7 +181,7 @@ void BufOverflowDetector::updateGepObjOffsetFromBase(AbstractState& as, SVF::Add } else { - assert(AbstractStateImpl::isInvalidMem(gepAddr) && "GEP object is neither a GepObjVar nor an invalid memory address"); + assert(AbstractState::isInvalidMem(gepAddr) && "GEP object is neither a GepObjVar nor an invalid memory address"); } } } @@ -435,7 +435,7 @@ bool BufOverflowDetector::detectStrcpy(AbstractState& as, const CallICFGNode *ca const SVFVar* arg0Val = call->getArgument(0); const SVFVar* arg1Val = call->getArgument(1); // Cast to dense AbstractState for AbsExtAPI compatibility - AbstractStateImpl& denseAs = dynamic_cast(as); + AbstractState& denseAs = dynamic_cast(as); IntervalValue strLen = AbstractInterpretation::getAEInstance().getUtils()->getStrlen(denseAs, arg1Val); return canSafelyAccessMemory(as, arg0Val, strLen); } @@ -456,7 +456,7 @@ bool BufOverflowDetector::detectStrcat(AbstractState& as, const CallICFGNode *ca const std::vector strncatGroup = {"__strncat_chk", "strncat", "__wcsncat_chk", "wcsncat"}; // Cast to dense AbstractState for AbsExtAPI compatibility - AbstractStateImpl& denseAs = dynamic_cast(as); + AbstractState& denseAs = dynamic_cast(as); if (std::find(strcatGroup.begin(), strcatGroup.end(), call->getCalledFunction()->getName()) != strcatGroup.end()) { @@ -711,10 +711,10 @@ bool NullptrDerefDetector::canSafelyDerefPtr(AbstractState& as, const SVFVar* va for (const auto &addr: AbsVal.getAddrs()) { // if the addr itself is invalid mem, report unsafe - if (AbstractStateImpl::isInvalidMem(addr)) + if (AbstractState::isInvalidMem(addr)) return false; // if nullptr is detected, return unsafe - else if (AbstractStateImpl::isNullMem(addr)) + else if (AbstractState::isNullMem(addr)) return false; // if addr is labeled freed mem, report unsafe else if (as.isFreedMem(addr)) diff --git a/svf/lib/AE/Svfexe/AbsExtAPI.cpp b/svf/lib/AE/Svfexe/AbsExtAPI.cpp index 2c0e39bf5..1d90ad602 100644 --- a/svf/lib/AE/Svfexe/AbsExtAPI.cpp +++ b/svf/lib/AE/Svfexe/AbsExtAPI.cpp @@ -32,7 +32,7 @@ #include "Util/Options.h" using namespace SVF; -AbsExtAPI::AbsExtAPI(Map& traces): abstractTrace(traces) +AbsExtAPI::AbsExtAPI(Map& traces): abstractTrace(traces) { svfir = PAG::getPAG(); icfg = svfir->getICFG(); @@ -44,7 +44,7 @@ void AbsExtAPI::initExtFunMap() #define SSE_FUNC_PROCESS(LLVM_NAME ,FUNC_NAME) \ auto sse_##FUNC_NAME = [this](const CallICFGNode *callNode) { \ /* run real ext function */ \ - AbstractStateImpl& as = getAbsStateFromTrace(callNode); \ + AbstractState& as = getAbsStateFromTrace(callNode); \ u32_t rhs_id = callNode->getArgument(0)->getId(); \ if (!as.inVarToValTable(rhs_id)) return; \ u32_t rhs = as[rhs_id].getInterval().lb().getIntNumeral(); \ @@ -78,7 +78,7 @@ void AbsExtAPI::initExtFunMap() { AbstractInterpretation::getAEInstance().checkpoints.erase(callNode); u32_t arg0 = callNode->getArgument(0)->getId(); - AbstractStateImpl&as = getAbsStateFromTrace(callNode); + AbstractState&as = getAbsStateFromTrace(callNode); if (as[arg0].getInterval().equals(IntervalValue(1, 1))) { SVFUtil::errs() << SVFUtil::sucMsg("The assertion is successfully verified!!\n"); @@ -96,7 +96,7 @@ void AbsExtAPI::initExtFunMap() { u32_t arg0 = callNode->getArgument(0)->getId(); u32_t arg1 = callNode->getArgument(1)->getId(); - AbstractStateImpl&as = getAbsStateFromTrace(callNode); + AbstractState&as = getAbsStateFromTrace(callNode); if (as[arg0].getInterval().equals(as[arg1].getInterval())) { SVFUtil::errs() << SVFUtil::sucMsg("The assertion is successfully verified!!\n"); @@ -113,7 +113,7 @@ void AbsExtAPI::initExtFunMap() auto svf_print = [&](const CallICFGNode* callNode) { if (callNode->arg_size() < 2) return; - AbstractStateImpl&as = getAbsStateFromTrace(callNode); + AbstractState&as = getAbsStateFromTrace(callNode); u32_t num_id = callNode->getArgument(0)->getId(); std::string text = strRead(as, callNode->getArgument(1)); assert(as.inVarToValTable(num_id) && "print() should pass integer"); @@ -127,7 +127,7 @@ void AbsExtAPI::initExtFunMap() auto svf_set_value = [&](const CallICFGNode* callNode) { if (callNode->arg_size() < 2) return; - AbstractStateImpl&as = getAbsStateFromTrace(callNode); + AbstractState&as = getAbsStateFromTrace(callNode); AbstractValue& num = as[callNode->getArgument(0)->getId()]; AbstractValue& lb = as[callNode->getArgument(1)->getId()]; AbstractValue& ub = as[callNode->getArgument(2)->getId()]; @@ -150,7 +150,7 @@ void AbsExtAPI::initExtFunMap() auto sse_scanf = [&](const CallICFGNode* callNode) { - AbstractStateImpl& as = getAbsStateFromTrace(callNode); + AbstractState& as = getAbsStateFromTrace(callNode); //scanf("%d", &data); if (callNode->arg_size() < 2) return; @@ -174,7 +174,7 @@ void AbsExtAPI::initExtFunMap() { //fscanf(stdin, "%d", &data); if (callNode->arg_size() < 3) return; - AbstractStateImpl& as = getAbsStateFromTrace(callNode); + AbstractState& as = getAbsStateFromTrace(callNode); u32_t dst_id = callNode->getArgument(2)->getId(); if (!as.inVarToAddrsTable(dst_id)) { @@ -203,7 +203,7 @@ void AbsExtAPI::initExtFunMap() auto sse_fread = [&](const CallICFGNode *callNode) { if (callNode->arg_size() < 3) return; - AbstractStateImpl&as = getAbsStateFromTrace(callNode); + AbstractState&as = getAbsStateFromTrace(callNode); u32_t block_count_id = callNode->getArgument(2)->getId(); u32_t block_size_id = callNode->getArgument(1)->getId(); IntervalValue block_count = as[block_count_id].getInterval(); @@ -220,7 +220,7 @@ void AbsExtAPI::initExtFunMap() auto sse_snprintf = [&](const CallICFGNode *callNode) { if (callNode->arg_size() < 2) return; - AbstractStateImpl&as = getAbsStateFromTrace(callNode); + AbstractState&as = getAbsStateFromTrace(callNode); u32_t size_id = callNode->getArgument(1)->getId(); u32_t dst_id = callNode->getArgument(0)->getId(); // get elem size of arg2 @@ -261,7 +261,7 @@ void AbsExtAPI::initExtFunMap() // itoa(num, ch, 10); // num: int, ch: char*, 10 is decimal if (callNode->arg_size() < 3) return; - AbstractStateImpl&as = getAbsStateFromTrace(callNode); + AbstractState&as = getAbsStateFromTrace(callNode); u32_t num_id = callNode->getArgument(0)->getId(); u32_t num = (u32_t) as[num_id].getInterval().getNumeral(); @@ -275,7 +275,7 @@ void AbsExtAPI::initExtFunMap() // check the arg size if (callNode->arg_size() < 1) return; const SVFVar* strValue = callNode->getArgument(0); - AbstractStateImpl& as = getAbsStateFromTrace(callNode); + AbstractState& as = getAbsStateFromTrace(callNode); NodeID value_id = strValue->getId(); u32_t lhsId = callNode->getRetICFGNode()->getActualRet()->getId(); u32_t dst_size = 0; @@ -334,7 +334,7 @@ void AbsExtAPI::initExtFunMap() { // recv(sockfd, buf, len, flags); if (callNode->arg_size() < 4) return; - AbstractStateImpl&as = getAbsStateFromTrace(callNode); + AbstractState&as = getAbsStateFromTrace(callNode); u32_t len_id = callNode->getArgument(2)->getId(); IntervalValue len = as[len_id].getInterval() - IntervalValue(1); u32_t lhsId = callNode->getRetICFGNode()->getActualRet()->getId(); @@ -346,11 +346,11 @@ void AbsExtAPI::initExtFunMap() auto sse_free = [&](const CallICFGNode *callNode) { if (callNode->arg_size() < 1) return; - AbstractStateImpl& as = getAbsStateFromTrace(callNode); + AbstractState& as = getAbsStateFromTrace(callNode); const u32_t freePtr = callNode->getArgument(0)->getId(); for (auto addr: as[freePtr].getAddrs()) { - if (AbstractStateImpl::isInvalidMem(addr)) + if (AbstractState::isInvalidMem(addr)) { // Detected a double free — the address has already been freed. // No action is taken at this point. @@ -376,7 +376,7 @@ void AbsExtAPI::initExtFunMap() } }; -AbstractStateImpl& AbsExtAPI::getAbsStateFromTrace(const SVF::ICFGNode* node) +AbstractState& AbsExtAPI::getAbsStateFromTrace(const SVF::ICFGNode* node) { if (abstractTrace.count(node) == 0) { @@ -389,7 +389,7 @@ AbstractStateImpl& AbsExtAPI::getAbsStateFromTrace(const SVF::ICFGNode* node) } } -std::string AbsExtAPI::strRead(AbstractStateImpl& as, const SVFVar* rhs) +std::string AbsExtAPI::strRead(AbstractState& as, const SVFVar* rhs) { // sse read string nodeID->string std::string str0; @@ -421,7 +421,7 @@ std::string AbsExtAPI::strRead(AbstractStateImpl& as, const SVFVar* rhs) void AbsExtAPI::handleExtAPI(const CallICFGNode *call) { - AbstractStateImpl& as = getAbsStateFromTrace(call); + AbstractState& as = getAbsStateFromTrace(call); const FunObjVar *fun = call->getCalledFunction(); assert(fun && "FunObjVar* is nullptr"); ExtAPIType extType = UNCLASSIFIED; @@ -493,7 +493,7 @@ void AbsExtAPI::handleStrcpy(const CallICFGNode *call) { // strcpy, __strcpy_chk, stpcpy , wcscpy, __wcscpy_chk // get the dst and src - AbstractStateImpl& as = getAbsStateFromTrace(call); + AbstractState& as = getAbsStateFromTrace(call); const SVFVar* arg0Val = call->getArgument(0); const SVFVar* arg1Val = call->getArgument(1); IntervalValue strLen = getStrlen(as, arg1Val); @@ -501,7 +501,7 @@ void AbsExtAPI::handleStrcpy(const CallICFGNode *call) handleMemcpy(as, arg0Val, arg1Val, strLen, strLen.lb().getIntNumeral()); } -IntervalValue AbsExtAPI::getStrlen(AbstractStateImpl& as, const SVF::SVFVar *strValue) +IntervalValue AbsExtAPI::getStrlen(AbstractState& as, const SVF::SVFVar *strValue) { NodeID value_id = strValue->getId(); u32_t dst_size = 0; @@ -581,7 +581,7 @@ void AbsExtAPI::handleStrcat(const SVF::CallICFGNode *call) { // __strcat_chk, strcat, __wcscat_chk, wcscat, __strncat_chk, strncat, __wcsncat_chk, wcsncat // to check it is strcat group or strncat group - AbstractStateImpl& as = getAbsStateFromTrace(call); + AbstractState& as = getAbsStateFromTrace(call); const FunObjVar *fun = call->getCalledFunction(); const std::vector strcatGroup = {"__strcat_chk", "strcat", "__wcscat_chk", "wcscat"}; const std::vector strncatGroup = {"__strncat_chk", "strncat", "__wcsncat_chk", "wcsncat"}; @@ -612,7 +612,7 @@ void AbsExtAPI::handleStrcat(const SVF::CallICFGNode *call) } } -void AbsExtAPI::handleMemcpy(AbstractStateImpl& as, const SVF::SVFVar *dst, const SVF::SVFVar *src, IntervalValue len, u32_t start_idx) +void AbsExtAPI::handleMemcpy(AbstractState& as, const SVF::SVFVar *dst, const SVF::SVFVar *src, IntervalValue len, u32_t start_idx) { u32_t dstId = dst->getId(); // pts(dstId) = {objid} objbar objtypeinfo->getType(). u32_t srcId = src->getId(); @@ -670,7 +670,7 @@ void AbsExtAPI::handleMemcpy(AbstractStateImpl& as, const SVF::SVFVar *dst, cons } } -void AbsExtAPI::handleMemset(AbstractStateImpl& as, const SVF::SVFVar *dst, IntervalValue elem, IntervalValue len) +void AbsExtAPI::handleMemset(AbstractState& as, const SVF::SVFVar *dst, IntervalValue elem, IntervalValue len) { u32_t dstId = dst->getId(); u32_t size = std::min((u32_t)Options::MaxFieldLimit(), (u32_t) len.lb().getIntNumeral()); diff --git a/svf/lib/AE/Svfexe/AbstractInterpretation.cpp b/svf/lib/AE/Svfexe/AbstractInterpretation.cpp index 61ce43b1f..b433b0d56 100644 --- a/svf/lib/AE/Svfexe/AbstractInterpretation.cpp +++ b/svf/lib/AE/Svfexe/AbstractInterpretation.cpp @@ -163,7 +163,7 @@ void AbstractInterpretation::analyse() void AbstractInterpretation::handleGlobalNode() { const ICFGNode* node = icfg->getGlobalICFGNode(); - abstractTrace[node] = AbstractStateImpl(); + abstractTrace[node] = AbstractState(); abstractTrace[node][IRGraph::NullPtr] = AddressValue(); // Global Node, we just need to handle addr, load, store, copy and gep for (const SVFStmt *stmt: node->getSVFStmts()) @@ -177,8 +177,8 @@ void AbstractInterpretation::handleGlobalNode() /// Scenario 2: preblock -----(callEdge)----> block bool AbstractInterpretation::mergeStatesFromPredecessors(const ICFGNode * icfgNode) { - std::vector workList; - AbstractStateImpl preAs; + std::vector workList; + AbstractState preAs; for (auto& edge: icfgNode->getInEdges()) { if (abstractTrace.find(edge->getSrcNode()) != abstractTrace.end()) @@ -187,7 +187,7 @@ bool AbstractInterpretation::mergeStatesFromPredecessors(const ICFGNode * icfgNo if (const IntraCFGEdge *intraCfgEdge = SVFUtil::dyn_cast(edge)) { - AbstractStateImpl tmpEs = abstractTrace[edge->getSrcNode()]; + AbstractState tmpEs = abstractTrace[edge->getSrcNode()]; if (intraCfgEdge->getCondition()) { if (isBranchFeasible(intraCfgEdge, tmpEs)) @@ -256,9 +256,9 @@ bool AbstractInterpretation::mergeStatesFromPredecessors(const ICFGNode * icfgNo bool AbstractInterpretation::isCmpBranchFeasible(const CmpStmt* cmpStmt, s64_t succ, - AbstractStateImpl& as) + AbstractState& as) { - AbstractStateImpl new_es = as; + AbstractState new_es = as; // get cmp stmt's op0, op1, and predicate NodeID op0 = cmpStmt->getOpVarID(0); NodeID op1 = cmpStmt->getOpVarID(1); @@ -482,9 +482,9 @@ bool AbstractInterpretation::isCmpBranchFeasible(const CmpStmt* cmpStmt, s64_t s } bool AbstractInterpretation::isSwitchBranchFeasible(const SVFVar* var, s64_t succ, - AbstractStateImpl& as) + AbstractState& as) { - AbstractStateImpl new_es = as; + AbstractState new_es = as; IntervalValue& switch_cond = new_es[var->getId()].getInterval(); s64_t value = succ; FIFOWorkList workList; @@ -526,7 +526,7 @@ bool AbstractInterpretation::isSwitchBranchFeasible(const SVFVar* var, s64_t suc } bool AbstractInterpretation::isBranchFeasible(const IntraCFGEdge* intraEdge, - AbstractStateImpl& as) + AbstractState& as) { const SVFVar *cmpVar = intraEdge->getCondition(); if (cmpVar->getInEdges().empty()) @@ -681,7 +681,7 @@ bool AbstractInterpretation::isRecursiveCall(const CallICFGNode *callNode) void AbstractInterpretation::recursiveCallPass(const CallICFGNode *callNode) { - AbstractStateImpl& as = getDenseAbsStateFromTrace(callNode); + AbstractState& as = getDenseAbsStateFromTrace(callNode); SkipRecursiveCall(callNode); const RetICFGNode *retNode = callNode->getRetICFGNode(); if (retNode->getSVFStmts().size() > 0) @@ -715,7 +715,7 @@ bool AbstractInterpretation::isDirectCall(const CallICFGNode *callNode) } void AbstractInterpretation::directCallFunPass(const CallICFGNode *callNode) { - AbstractStateImpl& as = getDenseAbsStateFromTrace(callNode); + AbstractState& as = getDenseAbsStateFromTrace(callNode); abstractTrace[callNode] = as; @@ -756,7 +756,7 @@ bool AbstractInterpretation::isIndirectCall(const CallICFGNode *callNode) void AbstractInterpretation::indirectCallFunPass(const CallICFGNode *callNode) { - AbstractStateImpl& as = getDenseAbsStateFromTrace(callNode); + AbstractState& as = getDenseAbsStateFromTrace(callNode); const auto callsiteMaps = svfir->getIndirectCallsites(); NodeID call_id = callsiteMaps.at(callNode); if (!as.inVarToAddrsTable(call_id)) @@ -801,9 +801,9 @@ void AbstractInterpretation::handleCycleWTO(const ICFGCycleWTO*cycle) if (cur_iter >= Options::WidenDelay()) { // Widen or narrow after processing cycle head node - AbstractStateImpl prev_head_state = abstractTrace[cycle_head]; + AbstractState prev_head_state = abstractTrace[cycle_head]; handleWTOComponent(cycle->head()); - AbstractStateImpl cur_head_state = abstractTrace[cycle_head]; + AbstractState cur_head_state = abstractTrace[cycle_head]; if (increasing) { @@ -939,13 +939,13 @@ void AbstractInterpretation::handleSVFStatement(const SVFStmt *stmt) void AbstractInterpretation::SkipRecursiveCall(const CallICFGNode *callNode) { - AbstractStateImpl& as = getDenseAbsStateFromTrace(callNode); + AbstractState& as = getDenseAbsStateFromTrace(callNode); const RetICFGNode *retNode = callNode->getRetICFGNode(); if (retNode->getSVFStmts().size() > 0) { if (const RetPE *retPE = SVFUtil::dyn_cast(*retNode->getSVFStmts().begin())) { - AbstractStateImpl as; + AbstractState as; if (!retPE->getLHSVar()->isPointer() && !retPE->getLHSVar()->isConstDataOrAggDataButNotNullPtr()) as[retPE->getLHSVarID()] = IntervalValue::top(); } @@ -1138,7 +1138,7 @@ void AbstractInterpretation::checkPointAllSet() void AbstractInterpretation::updateStateOnGep(const GepStmt *gep) { - AbstractStateImpl& as = getDenseAbsStateFromTrace(gep->getICFGNode()); + AbstractState& as = getDenseAbsStateFromTrace(gep->getICFGNode()); u32_t rhs = gep->getRHSVarID(); u32_t lhs = gep->getLHSVarID(); IntervalValue offsetPair = as.getElementIndex(gep); @@ -1154,7 +1154,7 @@ void AbstractInterpretation::updateStateOnGep(const GepStmt *gep) void AbstractInterpretation::updateStateOnSelect(const SelectStmt *select) { - AbstractStateImpl& as = getDenseAbsStateFromTrace(select->getICFGNode()); + AbstractState& as = getDenseAbsStateFromTrace(select->getICFGNode()); u32_t res = select->getResID(); u32_t tval = select->getTrueValue()->getId(); u32_t fval = select->getFalseValue()->getId(); @@ -1173,7 +1173,7 @@ void AbstractInterpretation::updateStateOnSelect(const SelectStmt *select) void AbstractInterpretation::updateStateOnPhi(const PhiStmt *phi) { const ICFGNode* icfgNode = phi->getICFGNode(); - AbstractStateImpl& as = getDenseAbsStateFromTrace(icfgNode); + AbstractState& as = getDenseAbsStateFromTrace(icfgNode); u32_t res = phi->getResID(); AbstractValue rhs; for (u32_t i = 0; i < phi->getOpVarNum(); i++) @@ -1182,8 +1182,8 @@ void AbstractInterpretation::updateStateOnPhi(const PhiStmt *phi) const ICFGNode* opICFGNode = phi->getOpICFGNode(i); if (hasAbsStateFromTrace(opICFGNode)) { - AbstractStateImpl tmpEs = abstractTrace[opICFGNode]; - AbstractStateImpl& opAs = getDenseAbsStateFromTrace(opICFGNode); + AbstractState tmpEs = abstractTrace[opICFGNode]; + AbstractState& opAs = getDenseAbsStateFromTrace(opICFGNode); const ICFGEdge* edge = icfg->getICFGEdge(opICFGNode, icfgNode, ICFGEdge::IntraCF); // if IntraEdge, check the condition, if it is feasible, join the value // if IntraEdge but not conditional edge, join the value @@ -1211,7 +1211,7 @@ void AbstractInterpretation::updateStateOnPhi(const PhiStmt *phi) void AbstractInterpretation::updateStateOnCall(const CallPE *callPE) { - AbstractStateImpl& as = getDenseAbsStateFromTrace(callPE->getICFGNode()); + AbstractState& as = getDenseAbsStateFromTrace(callPE->getICFGNode()); NodeID lhs = callPE->getLHSVarID(); NodeID rhs = callPE->getRHSVarID(); as[lhs] = as[rhs]; @@ -1219,7 +1219,7 @@ void AbstractInterpretation::updateStateOnCall(const CallPE *callPE) void AbstractInterpretation::updateStateOnRet(const RetPE *retPE) { - AbstractStateImpl& as = getDenseAbsStateFromTrace(retPE->getICFGNode()); + AbstractState& as = getDenseAbsStateFromTrace(retPE->getICFGNode()); NodeID lhs = retPE->getLHSVarID(); NodeID rhs = retPE->getRHSVarID(); as[lhs] = as[rhs]; @@ -1228,7 +1228,7 @@ void AbstractInterpretation::updateStateOnRet(const RetPE *retPE) void AbstractInterpretation::updateStateOnAddr(const AddrStmt *addr) { - AbstractStateImpl& as = getDenseAbsStateFromTrace(addr->getICFGNode()); + AbstractState& as = getDenseAbsStateFromTrace(addr->getICFGNode()); as.initObjVar(SVFUtil::cast(addr->getRHSVar())); if (addr->getRHSVar()->getType()->getKind() == SVFType::SVFIntegerTy) as[addr->getRHSVarID()].getInterval().meet_with(utils->getRangeLimitFromType(addr->getRHSVar()->getType())); @@ -1242,7 +1242,7 @@ void AbstractInterpretation::updateStateOnBinary(const BinaryOPStmt *binary) /// You are only required to handle integer predicates, including Add, FAdd, Sub, FSub, Mul, FMul, SDiv, FDiv, UDiv, /// SRem, FRem, URem, Xor, And, Or, AShr, Shl, LShr const ICFGNode* node = binary->getICFGNode(); - AbstractStateImpl& as = getDenseAbsStateFromTrace(node); + AbstractState& as = getDenseAbsStateFromTrace(node); u32_t op0 = binary->getOpVarID(0); u32_t op1 = binary->getOpVarID(1); u32_t res = binary->getResID(); @@ -1300,7 +1300,7 @@ void AbstractInterpretation::updateStateOnBinary(const BinaryOPStmt *binary) void AbstractInterpretation::updateStateOnCmp(const CmpStmt *cmp) { - AbstractStateImpl& as = getDenseAbsStateFromTrace(cmp->getICFGNode()); + AbstractState& as = getDenseAbsStateFromTrace(cmp->getICFGNode()); u32_t op0 = cmp->getOpVarID(0); u32_t op1 = cmp->getOpVarID(1); // if it is address @@ -1515,7 +1515,7 @@ void AbstractInterpretation::updateStateOnCmp(const CmpStmt *cmp) void AbstractInterpretation::updateStateOnLoad(const LoadStmt *load) { - AbstractStateImpl& as = getDenseAbsStateFromTrace(load->getICFGNode()); + AbstractState& as = getDenseAbsStateFromTrace(load->getICFGNode()); u32_t rhs = load->getRHSVarID(); u32_t lhs = load->getLHSVarID(); as[lhs] = as.loadValue(rhs); @@ -1523,7 +1523,7 @@ void AbstractInterpretation::updateStateOnLoad(const LoadStmt *load) void AbstractInterpretation::updateStateOnStore(const StoreStmt *store) { - AbstractStateImpl& as = getDenseAbsStateFromTrace(store->getICFGNode()); + AbstractState& as = getDenseAbsStateFromTrace(store->getICFGNode()); u32_t rhs = store->getRHSVarID(); u32_t lhs = store->getLHSVarID(); as.storeValue(lhs, as[rhs]); @@ -1531,7 +1531,7 @@ void AbstractInterpretation::updateStateOnStore(const StoreStmt *store) void AbstractInterpretation::updateStateOnCopy(const CopyStmt *copy) { - auto getZExtValue = [](AbstractStateImpl& as, const SVFVar* var) + auto getZExtValue = [](AbstractState& as, const SVFVar* var) { const SVFType* type = var->getType(); if (SVFUtil::isa(type)) @@ -1574,7 +1574,7 @@ void AbstractInterpretation::updateStateOnCopy(const CopyStmt *copy) return IntervalValue::top(); // TODO: may have better solution }; - auto getTruncValue = [&](const AbstractStateImpl& as, const SVFVar* var, + auto getTruncValue = [&](const AbstractState& as, const SVFVar* var, const SVFType* dstType) { const IntervalValue& itv = as[var->getId()].getInterval(); @@ -1627,7 +1627,7 @@ void AbstractInterpretation::updateStateOnCopy(const CopyStmt *copy) } }; - AbstractStateImpl& as = getDenseAbsStateFromTrace(copy->getICFGNode()); + AbstractState& as = getDenseAbsStateFromTrace(copy->getICFGNode()); u32_t lhs = copy->getLHSVarID(); u32_t rhs = copy->getRHSVarID(); From 8fe84ba6ddc9b411d02004968321b076c8f8f449 Mon Sep 17 00:00:00 2001 From: bjjwwang Date: Fri, 23 Jan 2026 10:11:32 +1100 Subject: [PATCH 7/9] revoke the code format change --- svf/include/AE/Core/AbstractState.h | 27 ++++++++++++++++++--------- svf/include/AE/Core/AbstractValue.h | 4 ---- 2 files changed, 18 insertions(+), 13 deletions(-) diff --git a/svf/include/AE/Core/AbstractState.h b/svf/include/AE/Core/AbstractState.h index 6711188af..3426ca913 100644 --- a/svf/include/AE/Core/AbstractState.h +++ b/svf/include/AE/Core/AbstractState.h @@ -112,7 +112,8 @@ class AbstractState } /// Return the internal index if addr is an address otherwise return the value of idx - inline u32_t getIDFromAddr(u32_t addr) { + inline u32_t getIDFromAddr(u32_t addr) + { return _freedAddrs.count(addr) ? AddressValue::getInternalID(InvalidMemAddr) : AddressValue::getInternalID(addr); } @@ -201,17 +202,20 @@ class AbstractState /// get abstract value of variable - inline AbstractValue &operator[](u32_t varId) { + inline AbstractValue &operator[](u32_t varId) + { return _varToAbsVal[varId]; } /// get abstract value of variable - inline const AbstractValue &operator[](u32_t varId) const { + inline const AbstractValue &operator[](u32_t varId) const + { return _varToAbsVal.at(varId); } /// whether the variable is in varToAddrs table - inline bool inVarToAddrsTable(u32_t id) const { + inline bool inVarToAddrsTable(u32_t id) const + { if (_varToAbsVal.find(id)!= _varToAbsVal.end()) { if (_varToAbsVal.at(id).isAddr()) @@ -223,7 +227,8 @@ class AbstractState } /// whether the variable is in varToVal table - inline bool inVarToValTable(u32_t id) const { + inline bool inVarToValTable(u32_t id) const + { if (_varToAbsVal.find(id) != _varToAbsVal.end()) { if (_varToAbsVal.at(id).isInterval()) @@ -235,7 +240,8 @@ class AbstractState } /// whether the memory address stores memory addresses - inline bool inAddrToAddrsTable(u32_t id) const { + inline bool inAddrToAddrsTable(u32_t id) const + { if (_addrToAbsVal.find(id)!= _addrToAbsVal.end()) { if (_addrToAbsVal.at(id).isAddr()) @@ -247,7 +253,8 @@ class AbstractState } /// whether the memory address stores abstract value - inline bool inAddrToValTable(u32_t id) const { + inline bool inAddrToValTable(u32_t id) const + { if (_addrToAbsVal.find(id) != _addrToAbsVal.end()) { if (_addrToAbsVal.at(id).isInterval()) @@ -308,14 +315,16 @@ class AbstractState u32_t hash() const; public: - inline void store(u32_t addr, const AbstractValue &val) { + inline void store(u32_t addr, const AbstractValue &val) + { assert(isVirtualMemAddress(addr) && "not virtual address?"); u32_t objId = getIDFromAddr(addr); if (isNullMem(addr)) return; _addrToAbsVal[objId] = val; } - inline AbstractValue &load(u32_t addr) { + inline AbstractValue &load(u32_t addr) + { assert(isVirtualMemAddress(addr) && "not virtual address?"); u32_t objId = getIDFromAddr(addr); return _addrToAbsVal[objId]; diff --git a/svf/include/AE/Core/AbstractValue.h b/svf/include/AE/Core/AbstractValue.h index 87e5e9909..dec9d3914 100644 --- a/svf/include/AE/Core/AbstractValue.h +++ b/svf/include/AE/Core/AbstractValue.h @@ -24,9 +24,6 @@ // Xiao Cheng, Jiawei Wang and Yulei Sui. Precise Sparse Abstract Execution via Cross-Domain Interaction. // 46th International Conference on Software Engineering. (ICSE24) -#ifndef SVF_ABSTRACTVALUE_H -#define SVF_ABSTRACTVALUE_H - #include "AE/Core/IntervalValue.h" #include "AE/Core/AddressValue.h" #include "Util/SVFUtil.h" @@ -158,4 +155,3 @@ class AbstractValue } }; } -#endif // SVF_ABSTRACTVALUE_H From 14413c49e492784bddbccbcf5a2c7d67c22cddef Mon Sep 17 00:00:00 2001 From: bjjwwang Date: Fri, 23 Jan 2026 10:17:55 +1100 Subject: [PATCH 8/9] revoke all changes in AbstractState and AbstractValue --- svf/include/AE/Core/AbstractState.h | 24 ++++++++++++------------ svf/include/AE/Core/AbstractValue.h | 2 +- svf/lib/AE/Core/AbstractState.cpp | 8 ++++---- 3 files changed, 17 insertions(+), 17 deletions(-) diff --git a/svf/include/AE/Core/AbstractState.h b/svf/include/AE/Core/AbstractState.h index 3426ca913..847fcfad5 100644 --- a/svf/include/AE/Core/AbstractState.h +++ b/svf/include/AE/Core/AbstractState.h @@ -202,13 +202,13 @@ class AbstractState /// get abstract value of variable - inline AbstractValue &operator[](u32_t varId) + inline virtual AbstractValue &operator[](u32_t varId) { return _varToAbsVal[varId]; } /// get abstract value of variable - inline const AbstractValue &operator[](u32_t varId) const + inline virtual const AbstractValue &operator[](u32_t varId) const { return _varToAbsVal.at(varId); } @@ -227,7 +227,7 @@ class AbstractState } /// whether the variable is in varToVal table - inline bool inVarToValTable(u32_t id) const + inline virtual bool inVarToValTable(u32_t id) const { if (_varToAbsVal.find(id) != _varToAbsVal.end()) { @@ -253,7 +253,7 @@ class AbstractState } /// whether the memory address stores abstract value - inline bool inAddrToValTable(u32_t id) const + inline virtual bool inAddrToValTable(u32_t id) const { if (_addrToAbsVal.find(id) != _addrToAbsVal.end()) { @@ -279,17 +279,17 @@ class AbstractState public: - /// Widening operation - returns widened state - AbstractState widening(const AbstractState& other) const; + /// domain widen with other, and return the widened domain + AbstractState widening(const AbstractState&other); - /// Narrowing operation - returns narrowed state - AbstractState narrowing(const AbstractState& other) const; + /// domain narrow with other, and return the narrowed domain + AbstractState narrowing(const AbstractState&other); /// domain join with other, important! other widen this. - void joinWith(const AbstractState& other); + void joinWith(const AbstractState&other); /// domain meet with other, important! other widen this. - void meetWith(const AbstractState& other); + void meetWith(const AbstractState&other); void addToFreedAddrs(NodeID addr) { @@ -323,7 +323,7 @@ class AbstractState _addrToAbsVal[objId] = val; } - inline AbstractValue &load(u32_t addr) + inline virtual AbstractValue &load(u32_t addr) { assert(isVirtualMemAddress(addr) && "not virtual address?"); u32_t objId = getIDFromAddr(addr); @@ -338,7 +338,7 @@ class AbstractState return ""; } - bool equals(const AbstractState& other) const; + bool equals(const AbstractState&other) const; static bool eqVarToValMap(const VarToAbsValMap&lhs, const VarToAbsValMap&rhs) diff --git a/svf/include/AE/Core/AbstractValue.h b/svf/include/AE/Core/AbstractValue.h index dec9d3914..1430d37c1 100644 --- a/svf/include/AE/Core/AbstractValue.h +++ b/svf/include/AE/Core/AbstractValue.h @@ -154,4 +154,4 @@ class AbstractValue return "<" + interval.toString() + ", " + addrs.toString() + ">"; } }; -} +} \ No newline at end of file diff --git a/svf/lib/AE/Core/AbstractState.cpp b/svf/lib/AE/Core/AbstractState.cpp index 6d4b7ef9c..d31f111a3 100644 --- a/svf/lib/AE/Core/AbstractState.cpp +++ b/svf/lib/AE/Core/AbstractState.cpp @@ -30,12 +30,11 @@ #include "AE/Core/AbstractState.h" #include "Util/SVFUtil.h" #include "Util/Options.h" -#include using namespace SVF; using namespace SVFUtil; -bool AbstractState::equals(const AbstractState& other) const +bool AbstractState::equals(const AbstractState&other) const { return *this == other; } @@ -57,7 +56,7 @@ u32_t AbstractState::hash() const return pairH({h, h2}); } -AbstractState AbstractState::widening(const AbstractState& other) const +AbstractState AbstractState::widening(const AbstractState& other) { // widen interval AbstractState es = *this; @@ -78,7 +77,7 @@ AbstractState AbstractState::widening(const AbstractState& other) const return es; } -AbstractState AbstractState::narrowing(const AbstractState& other) const +AbstractState AbstractState::narrowing(const AbstractState& other) { AbstractState es = *this; for (auto it = es._varToAbsVal.begin(); it != es._varToAbsVal.end(); ++it) @@ -96,6 +95,7 @@ AbstractState AbstractState::narrowing(const AbstractState& other) const it->second.getInterval().narrow_with(other._addrToAbsVal.at(key).getInterval()); } return es; + } /// domain join with other, important! other widen this. From 93755cf6cc93cd3625aa740fbe534608db8da2bb Mon Sep 17 00:00:00 2001 From: bjjwwang Date: Fri, 23 Jan 2026 13:01:03 +1100 Subject: [PATCH 9/9] remove some redundancy, and add getAbsValueFromTrace() --- svf/include/AE/Svfexe/AEDetector.h | 4 +-- .../AE/Svfexe/AbstractInterpretation.h | 21 ++++++------ svf/lib/AE/Svfexe/AEDetector.cpp | 12 +++---- svf/lib/AE/Svfexe/AbstractInterpretation.cpp | 32 +++++++++---------- 4 files changed, 31 insertions(+), 38 deletions(-) diff --git a/svf/include/AE/Svfexe/AEDetector.h b/svf/include/AE/Svfexe/AEDetector.h index 7356ee913..7930d444e 100644 --- a/svf/include/AE/Svfexe/AEDetector.h +++ b/svf/include/AE/Svfexe/AEDetector.h @@ -152,9 +152,6 @@ class BufOverflowDetector : public AEDetector { friend class AbstractInterpretation; -private: - Map gepObjOffsetFromBase; ///< Maps GEP objects to their offsets from the base. - public: /** * @brief Constructor initializes the detector kind to BUF_OVERFLOW and sets up external API buffer overflow rules. @@ -354,6 +351,7 @@ class BufOverflowDetector : public AEDetector bool detectStrcpy(AbstractState& as, const CallICFGNode *call); private: + Map gepObjOffsetFromBase; ///< Maps GEP objects to their offsets from their base. Map>> extAPIBufOverflowCheckRules; ///< Rules for checking buffer overflows in external APIs. Set bugLoc; ///< Set of locations where bugs have been reported. SVFBugReport recoder; ///< Recorder for abstract execution bugs. diff --git a/svf/include/AE/Svfexe/AbstractInterpretation.h b/svf/include/AE/Svfexe/AbstractInterpretation.h index 839535a78..99449f822 100644 --- a/svf/include/AE/Svfexe/AbstractInterpretation.h +++ b/svf/include/AE/Svfexe/AbstractInterpretation.h @@ -178,8 +178,14 @@ class AbstractInterpretation } } - /// Dense state access from trace (for internal use when AbstractState is needed) - AbstractState& getDenseAbsStateFromTrace(const ICFGNode* node) + /* + * @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) { @@ -188,7 +194,8 @@ class AbstractInterpretation } else { - return abstractTrace[node]; + //TODO: support sparse abstract state + return abstractTrace[node][varId]; } } @@ -322,14 +329,6 @@ class AbstractInterpretation return abstractTrace.count(node) != 0; } - /// Factory method to create abstract state based on CLI option - /// Currently returns DenseAbstractState; will support SparseAbstractState in the future - std::unique_ptr createState() - { - // TODO: if (Options::UseSparseState()) - return std::make_unique(); - } - AbsExtAPI* getUtils() { return utils; diff --git a/svf/lib/AE/Svfexe/AEDetector.cpp b/svf/lib/AE/Svfexe/AEDetector.cpp index 56000935f..d6dc9bbcd 100644 --- a/svf/lib/AE/Svfexe/AEDetector.cpp +++ b/svf/lib/AE/Svfexe/AEDetector.cpp @@ -435,8 +435,7 @@ bool BufOverflowDetector::detectStrcpy(AbstractState& as, const CallICFGNode *ca const SVFVar* arg0Val = call->getArgument(0); const SVFVar* arg1Val = call->getArgument(1); // Cast to dense AbstractState for AbsExtAPI compatibility - AbstractState& denseAs = dynamic_cast(as); - IntervalValue strLen = AbstractInterpretation::getAEInstance().getUtils()->getStrlen(denseAs, arg1Val); + IntervalValue strLen = AbstractInterpretation::getAEInstance().getUtils()->getStrlen(as, arg1Val); return canSafelyAccessMemory(as, arg0Val, strLen); } @@ -455,15 +454,12 @@ bool BufOverflowDetector::detectStrcat(AbstractState& as, const CallICFGNode *ca const std::vector strcatGroup = {"__strcat_chk", "strcat", "__wcscat_chk", "wcscat"}; const std::vector strncatGroup = {"__strncat_chk", "strncat", "__wcsncat_chk", "wcsncat"}; - // Cast to dense AbstractState for AbsExtAPI compatibility - AbstractState& denseAs = dynamic_cast(as); - if (std::find(strcatGroup.begin(), strcatGroup.end(), call->getCalledFunction()->getName()) != strcatGroup.end()) { const SVFVar* arg0Val = call->getArgument(0); const SVFVar* arg1Val = call->getArgument(1); - IntervalValue strLen0 = AbstractInterpretation::getAEInstance().getUtils()->getStrlen(denseAs, arg0Val); - IntervalValue strLen1 = AbstractInterpretation::getAEInstance().getUtils()->getStrlen(denseAs, arg1Val); + IntervalValue strLen0 = AbstractInterpretation::getAEInstance().getUtils()->getStrlen(as, arg0Val); + IntervalValue strLen1 = AbstractInterpretation::getAEInstance().getUtils()->getStrlen(as, arg1Val); IntervalValue totalLen = strLen0 + strLen1; return canSafelyAccessMemory(as, arg0Val, totalLen); } @@ -472,7 +468,7 @@ bool BufOverflowDetector::detectStrcat(AbstractState& as, const CallICFGNode *ca const SVFVar* arg0Val = call->getArgument(0); const SVFVar* arg2Val = call->getArgument(2); IntervalValue arg2Num = as[arg2Val->getId()].getInterval(); - IntervalValue strLen0 = AbstractInterpretation::getAEInstance().getUtils()->getStrlen(denseAs, arg0Val); + IntervalValue strLen0 = AbstractInterpretation::getAEInstance().getUtils()->getStrlen(as, arg0Val); IntervalValue totalLen = strLen0 + arg2Num; return canSafelyAccessMemory(as, arg0Val, totalLen); } diff --git a/svf/lib/AE/Svfexe/AbstractInterpretation.cpp b/svf/lib/AE/Svfexe/AbstractInterpretation.cpp index b433b0d56..28661ac53 100644 --- a/svf/lib/AE/Svfexe/AbstractInterpretation.cpp +++ b/svf/lib/AE/Svfexe/AbstractInterpretation.cpp @@ -681,7 +681,7 @@ bool AbstractInterpretation::isRecursiveCall(const CallICFGNode *callNode) void AbstractInterpretation::recursiveCallPass(const CallICFGNode *callNode) { - AbstractState& as = getDenseAbsStateFromTrace(callNode); + AbstractState& as = getAbsStateFromTrace(callNode); SkipRecursiveCall(callNode); const RetICFGNode *retNode = callNode->getRetICFGNode(); if (retNode->getSVFStmts().size() > 0) @@ -715,7 +715,7 @@ bool AbstractInterpretation::isDirectCall(const CallICFGNode *callNode) } void AbstractInterpretation::directCallFunPass(const CallICFGNode *callNode) { - AbstractState& as = getDenseAbsStateFromTrace(callNode); + AbstractState& as = getAbsStateFromTrace(callNode); abstractTrace[callNode] = as; @@ -756,7 +756,7 @@ bool AbstractInterpretation::isIndirectCall(const CallICFGNode *callNode) void AbstractInterpretation::indirectCallFunPass(const CallICFGNode *callNode) { - AbstractState& as = getDenseAbsStateFromTrace(callNode); + AbstractState& as = getAbsStateFromTrace(callNode); const auto callsiteMaps = svfir->getIndirectCallsites(); NodeID call_id = callsiteMaps.at(callNode); if (!as.inVarToAddrsTable(call_id)) @@ -939,7 +939,7 @@ void AbstractInterpretation::handleSVFStatement(const SVFStmt *stmt) void AbstractInterpretation::SkipRecursiveCall(const CallICFGNode *callNode) { - AbstractState& as = getDenseAbsStateFromTrace(callNode); + AbstractState& as = getAbsStateFromTrace(callNode); const RetICFGNode *retNode = callNode->getRetICFGNode(); if (retNode->getSVFStmts().size() > 0) { @@ -1138,7 +1138,7 @@ void AbstractInterpretation::checkPointAllSet() void AbstractInterpretation::updateStateOnGep(const GepStmt *gep) { - AbstractState& as = getDenseAbsStateFromTrace(gep->getICFGNode()); + AbstractState& as = getAbsStateFromTrace(gep->getICFGNode()); u32_t rhs = gep->getRHSVarID(); u32_t lhs = gep->getLHSVarID(); IntervalValue offsetPair = as.getElementIndex(gep); @@ -1154,7 +1154,7 @@ void AbstractInterpretation::updateStateOnGep(const GepStmt *gep) void AbstractInterpretation::updateStateOnSelect(const SelectStmt *select) { - AbstractState& as = getDenseAbsStateFromTrace(select->getICFGNode()); + AbstractState& as = getAbsStateFromTrace(select->getICFGNode()); u32_t res = select->getResID(); u32_t tval = select->getTrueValue()->getId(); u32_t fval = select->getFalseValue()->getId(); @@ -1173,7 +1173,7 @@ void AbstractInterpretation::updateStateOnSelect(const SelectStmt *select) void AbstractInterpretation::updateStateOnPhi(const PhiStmt *phi) { const ICFGNode* icfgNode = phi->getICFGNode(); - AbstractState& as = getDenseAbsStateFromTrace(icfgNode); + AbstractState& as = getAbsStateFromTrace(icfgNode); u32_t res = phi->getResID(); AbstractValue rhs; for (u32_t i = 0; i < phi->getOpVarNum(); i++) @@ -1183,7 +1183,7 @@ void AbstractInterpretation::updateStateOnPhi(const PhiStmt *phi) if (hasAbsStateFromTrace(opICFGNode)) { AbstractState tmpEs = abstractTrace[opICFGNode]; - AbstractState& opAs = getDenseAbsStateFromTrace(opICFGNode); + AbstractState& opAs = getAbsStateFromTrace(opICFGNode); const ICFGEdge* edge = icfg->getICFGEdge(opICFGNode, icfgNode, ICFGEdge::IntraCF); // if IntraEdge, check the condition, if it is feasible, join the value // if IntraEdge but not conditional edge, join the value @@ -1211,7 +1211,7 @@ void AbstractInterpretation::updateStateOnPhi(const PhiStmt *phi) void AbstractInterpretation::updateStateOnCall(const CallPE *callPE) { - AbstractState& as = getDenseAbsStateFromTrace(callPE->getICFGNode()); + AbstractState& as = getAbsStateFromTrace(callPE->getICFGNode()); NodeID lhs = callPE->getLHSVarID(); NodeID rhs = callPE->getRHSVarID(); as[lhs] = as[rhs]; @@ -1219,7 +1219,7 @@ void AbstractInterpretation::updateStateOnCall(const CallPE *callPE) void AbstractInterpretation::updateStateOnRet(const RetPE *retPE) { - AbstractState& as = getDenseAbsStateFromTrace(retPE->getICFGNode()); + AbstractState& as = getAbsStateFromTrace(retPE->getICFGNode()); NodeID lhs = retPE->getLHSVarID(); NodeID rhs = retPE->getRHSVarID(); as[lhs] = as[rhs]; @@ -1228,7 +1228,7 @@ void AbstractInterpretation::updateStateOnRet(const RetPE *retPE) void AbstractInterpretation::updateStateOnAddr(const AddrStmt *addr) { - AbstractState& as = getDenseAbsStateFromTrace(addr->getICFGNode()); + AbstractState& as = getAbsStateFromTrace(addr->getICFGNode()); as.initObjVar(SVFUtil::cast(addr->getRHSVar())); if (addr->getRHSVar()->getType()->getKind() == SVFType::SVFIntegerTy) as[addr->getRHSVarID()].getInterval().meet_with(utils->getRangeLimitFromType(addr->getRHSVar()->getType())); @@ -1242,7 +1242,7 @@ void AbstractInterpretation::updateStateOnBinary(const BinaryOPStmt *binary) /// You are only required to handle integer predicates, including Add, FAdd, Sub, FSub, Mul, FMul, SDiv, FDiv, UDiv, /// SRem, FRem, URem, Xor, And, Or, AShr, Shl, LShr const ICFGNode* node = binary->getICFGNode(); - AbstractState& as = getDenseAbsStateFromTrace(node); + AbstractState& as = getAbsStateFromTrace(node); u32_t op0 = binary->getOpVarID(0); u32_t op1 = binary->getOpVarID(1); u32_t res = binary->getResID(); @@ -1300,7 +1300,7 @@ void AbstractInterpretation::updateStateOnBinary(const BinaryOPStmt *binary) void AbstractInterpretation::updateStateOnCmp(const CmpStmt *cmp) { - AbstractState& as = getDenseAbsStateFromTrace(cmp->getICFGNode()); + AbstractState& as = getAbsStateFromTrace(cmp->getICFGNode()); u32_t op0 = cmp->getOpVarID(0); u32_t op1 = cmp->getOpVarID(1); // if it is address @@ -1515,7 +1515,7 @@ void AbstractInterpretation::updateStateOnCmp(const CmpStmt *cmp) void AbstractInterpretation::updateStateOnLoad(const LoadStmt *load) { - AbstractState& as = getDenseAbsStateFromTrace(load->getICFGNode()); + AbstractState& as = getAbsStateFromTrace(load->getICFGNode()); u32_t rhs = load->getRHSVarID(); u32_t lhs = load->getLHSVarID(); as[lhs] = as.loadValue(rhs); @@ -1523,7 +1523,7 @@ void AbstractInterpretation::updateStateOnLoad(const LoadStmt *load) void AbstractInterpretation::updateStateOnStore(const StoreStmt *store) { - AbstractState& as = getDenseAbsStateFromTrace(store->getICFGNode()); + AbstractState& as = getAbsStateFromTrace(store->getICFGNode()); u32_t rhs = store->getRHSVarID(); u32_t lhs = store->getLHSVarID(); as.storeValue(lhs, as[rhs]); @@ -1627,7 +1627,7 @@ void AbstractInterpretation::updateStateOnCopy(const CopyStmt *copy) } }; - AbstractState& as = getDenseAbsStateFromTrace(copy->getICFGNode()); + AbstractState& as = getAbsStateFromTrace(copy->getICFGNode()); u32_t lhs = copy->getLHSVarID(); u32_t rhs = copy->getRHSVarID();