@@ -204,7 +204,7 @@ class AbstractExecutionHelper:
204204 managing GEP object offsets, and other utilities.
205205 """
206206
207- def __init__ (self , svfir : pysvf .SVFIR ):
207+ def __init__ (self , svfir : pysvf .SVFIR , svf_state_mgr : pysvf . AbstractStateManager = None ):
208208 """
209209 Initialize member variables.
210210 """
@@ -216,6 +216,48 @@ def __init__(self, svfir: pysvf.SVFIR):
216216 # Map to store exception information for each ICFGNode
217217 self .node_to_bug_info = {}
218218 self .svfir = svfir
219+ # Optional: if a stateMgr is provided, getByteOffset delegates to its
220+ # getGepByteOffset (the C++ side does the same via svfStateMgr->...).
221+ self .svf_state_mgr = svf_state_mgr
222+
223+ # ------------------------------------------------------------------
224+ # Helpers that used to live as instance methods on `pysvf.AbstractState`.
225+ # Upstream (Semi-Sparse refactor) moved them to `AbstractStateManager`,
226+ # which requires a sparsity-aware trace we don't keep here. We re-implement
227+ # the dense-mode behavior using only public AbstractState surface so the
228+ # Python side mirrors the C++ side (`AbstractExecutionHelper::getByteOffset`).
229+ # ------------------------------------------------------------------
230+ def getByteOffset (self , abstract_state : pysvf .AbstractState , gep : pysvf .GepStmt ) -> pysvf .IntervalValue :
231+ # Delegates to the stateMgr's upstream impl, mirroring the C++ side
232+ # `svfStateMgr->getGepByteOffset(gep)`. The `abstract_state` argument
233+ # is kept in the signature for symmetry with the call-site shape but
234+ # is not consulted here -- the mgr reads non-constant indices from
235+ # its own trace, which is the same trace this helper writes to.
236+ return self .svf_state_mgr .getGepByteOffset (gep )
237+
238+ def getGepObjAddrs (self , abstract_state : pysvf .AbstractState , var_id : int , offset : pysvf .IntervalValue ) -> pysvf .AddressValue :
239+ # Delegates to the stateMgr's upstream impl. mgr.getGepObjAddrs takes
240+ # a ValVar* (and infers the ICFGNode from it), so we look the var up
241+ # by id. Matches the C++ side `svfStateMgr->getGepObjAddrs(...)`.
242+ pointer = self .svfir .getGNode (var_id )
243+ return self .svf_state_mgr .getGepObjAddrs (pointer , offset )
244+
245+ def getPointeeElement (self , abstract_state : pysvf .AbstractState , var_id : int ):
246+ ptr_val = abstract_state [var_id ]
247+ if not ptr_val .isAddr ():
248+ return None
249+ for addr in ptr_val .getAddrs ():
250+ obj_id = abstract_state .getIDFromAddr (addr )
251+ if obj_id == 0 :
252+ continue
253+ return self .svfir .getBaseObject (obj_id ).getType ()
254+ return None
255+
256+ def getAllocaInstByteSize (self , abstract_state : pysvf .AbstractState , addr : pysvf .AddrStmt ) -> int :
257+ # Delegates to the stateMgr's upstream impl. mgr.getAllocaInstByteSize
258+ # takes the AddrStmt directly (it derives node + sizes itself). Matches
259+ # the C++ side `svfStateMgr->getAllocaInstByteSize(addr)`.
260+ return self .svf_state_mgr .getAllocaInstByteSize (addr )
219261
220262 def reportBufOverflow (self , node , msg ):
221263 """
@@ -277,7 +319,7 @@ def handleMemcpy(self, abstractState: pysvf.AbstractState, dst: pysvf.SVFVar, sr
277319 if dst .getType ().isArrayTy ():
278320 elemSize = dst .getType ().getTypeOfElement ().getByteSize ()
279321 elif dst .getType ().isPointerTy ():
280- elemType = abstractState .getPointeeElement (dstId )
322+ elemType = self .getPointeeElement (abstractState , dstId )
281323 if elemType .isArrayTy ():
282324 elemSize = elemType .getTypeOfElement ().getByteSize ()
283325 else :
@@ -288,8 +330,8 @@ def handleMemcpy(self, abstractState: pysvf.AbstractState, dst: pysvf.SVFVar, sr
288330 range_val = size / elemSize
289331 if abstractState .inVarToAddrsTable (dstId ) and abstractState .inVarToAddrsTable (srcId ):
290332 for index in range (0 , int (range_val )):
291- expr_src = abstractState .getGepObjAddrs (srcId , pysvf .IntervalValue (index ))
292- expr_dst = abstractState .getGepObjAddrs (dstId , pysvf .IntervalValue (index + start_idx ))
333+ expr_src = self .getGepObjAddrs (abstractState , srcId , pysvf .IntervalValue (index ))
334+ expr_dst = self .getGepObjAddrs (abstractState , dstId , pysvf .IntervalValue (index + start_idx ))
293335 for addr_src in expr_src :
294336 for addr_dst in expr_dst :
295337 objId = abstractState .getIDFromAddr (addr_src )
@@ -320,15 +362,15 @@ def getStrlen(self, abstractState, strValue):
320362 icfg_node = base_object .getICFGNode ()
321363 for stmt in icfg_node .getSVFStmts ():
322364 if isinstance (stmt , pysvf .AddrStmt ):
323- dst_size = abstractState .getAllocaInstByteSize (stmt )
365+ dst_size = self .getAllocaInstByteSize (abstractState , stmt )
324366
325367 length = 0
326368 elem_size = 1
327369
328370 # Calculate the string length
329371 if abstractState .getVar (value_id ).isAddr ():
330372 for index in range (dst_size ):
331- expr0 = abstractState .getGepObjAddrs (value_id , pysvf .IntervalValue (index ))
373+ expr0 = self .getGepObjAddrs (abstractState , value_id , pysvf .IntervalValue (index ))
332374 val = pysvf .AbstractValue ()
333375
334376 for addr in expr0 :
@@ -343,7 +385,7 @@ def getStrlen(self, abstractState, strValue):
343385 if strValue .getType ().isArrayTy ():
344386 elem_size = strValue .getType ().getTypeOfElement ().getByteSize ()
345387 elif strValue .getType ().isPointerTy ():
346- elem_type = abstractState .getPointeeElement (value_id )
388+ elem_type = self .getPointeeElement (abstractState , value_id )
347389 if elem_type :
348390 if elem_type .isArrayTy ():
349391 elem_size = elem_type .getTypeOfElement ().getByteSize ()
@@ -400,8 +442,16 @@ def __init__(self, pag: pysvf.SVFIR):
400442 self .func_to_wto = {}
401443 self .recursive_funs = set ()
402444 self .pre_abs_trace = {}
403- self .post_abs_trace = {}
404- self .buf_overflow_helper = AbstractExecutionHelper (self .svfir )
445+ # Owns the post-trace and is the backing store for AbsExtAPI as well
446+ # as the GEP/load/store helpers (getGepByteOffset etc.). Replaces
447+ # the old `self.post_abs_trace` dict so reads/writes on
448+ # `self.post_abs_trace[node]` go through the mgr's trace.
449+ self .ander = pysvf .AndersenWaveDiff (self .svfir )
450+ self .svf_state_mgr = pysvf .AbstractStateManager (self .svfir , self .ander )
451+ # Alias preserved so existing call-sites `self.post_abs_trace[node]`
452+ # keep working. The mgr supports __getitem__/__setitem__/__contains__.
453+ self .post_abs_trace = self .svf_state_mgr
454+ self .buf_overflow_helper = AbstractExecutionHelper (self .svfir , self .svf_state_mgr )
405455 self .assert_points = set ()
406456 self .widen_delay = 3
407457 self .addressMask = 0x7f000000
@@ -1071,14 +1121,14 @@ def getAccessOffset(self, objId: int, gep: pysvf.GepStmt) -> pysvf.IntervalValue
10711121 # Field-insensitive base object
10721122 if isinstance (obj , pysvf .BaseObjVar ):
10731123 # Get base size
1074- access_offset = abstract_state . getByteOffset (gep )
1124+ access_offset = self . buf_overflow_helper . getByteOffset (abstract_state , gep )
10751125 return access_offset
10761126
10771127 # A sub-object of an aggregate object
10781128 elif isinstance (obj , pysvf .GepObjVar ):
10791129 access_offset = (
10801130 self .buf_overflow_helper .getGepObjOffsetFromBase (obj )
1081- + abstract_state . getByteOffset (gep )
1131+ + self . buf_overflow_helper . getByteOffset (abstract_state , gep )
10821132 )
10831133 return access_offset
10841134
0 commit comments