Skip to content

Commit 6519ae4

Browse files
authored
Merge pull request #60 from bjjwwang/sync-llvm-21
Sync llvm 21
2 parents 63c0e59 + 6cdc22f commit 6519ae4

8 files changed

Lines changed: 98 additions & 33 deletions

File tree

.github/workflows/build.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ jobs:
4343
- name: build
4444
run: |
4545
export SVF_DIR=$(npm root)/SVF
46-
export LLVM_DIR=$(npm root)/llvm-18.1.0.obj
46+
export LLVM_DIR=$(npm root)/llvm-21.1.0.obj
4747
export Z3_DIR=$(npm root)/z3.obj
4848
echo "SVF_DIR="$SVF_DIR
4949
echo "LLVM_DIR="$LLVM_DIR

Assignment-3/CPP/Assignment_3.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ void AbstractExecution::bufOverflowDetection(const SVF::SVFStmt* stmt) {
7676
AbstractState& as = getAbsStateFromTrace(gep->getICFGNode());
7777
NodeID lhs = gep->getLHSVarID();
7878
NodeID rhs = gep->getRHSVarID();
79-
updateGepObjOffsetFromBase(as, as[lhs].getAddrs(), as[rhs].getAddrs(), as.getByteOffset(gep));
79+
updateGepObjOffsetFromBase(as, as[lhs].getAddrs(), as[rhs].getAddrs(), svfStateMgr->getGepByteOffset(gep));
8080

8181
/// TODO: your code starts from here
8282

@@ -264,9 +264,9 @@ void AbstractExecution::updateStateOnCall(const CallPE* callPE) {
264264
{
265265
NodeID curId = callPE->getOpVarID(i);
266266
const ICFGNode* opICFGNode = callPE->getOpCallICFGNode(i);
267-
if (postAbsTrace.count(opICFGNode))
267+
if (postAbsTrace().count(opICFGNode))
268268
{
269-
AbstractState& opAs = postAbsTrace[opICFGNode];
269+
AbstractState& opAs = postAbsTrace()[opICFGNode];
270270
rhs.join_with(opAs[curId]);
271271
}
272272
}

Assignment-3/CPP/Assignment_3.h

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
*/
2727
#include "Assignment_3_Helper.h"
2828
#include "AE/Svfexe/AbsExtAPI.h"
29+
#include "AE/Svfexe/AbstractStateManager.h"
2930
#include "SVFIR/SVFIR.h"
3031

3132
namespace SVF {
@@ -108,7 +109,7 @@ namespace SVF {
108109

109110
/// Return its abstract state given an ICFGNode
110111
AbstractState& getAbsStateFromTrace(const ICFGNode* node) {
111-
return postAbsTrace[node];
112+
return (*svfStateMgr)[node];
112113
}
113114

114115
/// Update the offset of a GEP (GetElementPtr) object from its base address
@@ -121,21 +122,29 @@ namespace SVF {
121122

122123
/// Destructor
123124
virtual ~AbstractExecution() {
125+
delete svfStateMgr;
124126
}
125127

126128
protected:
127129
/// SVFIR and ICFG
128130
SVFIR* svfir;
129131
ICFG* icfg;
132+
/// Owns the abstract trace immediately after an ICFGNode (post trace).
133+
/// AbsExtAPI and the GEP/load/store helpers (getGepByteOffset etc.)
134+
/// read and write through this manager; we don't keep a separate
135+
/// postAbsTrace map any more.
136+
AbstractStateManager* svfStateMgr = nullptr;
130137

131138
/// Map a function to its corresponding WTO
132139
Map<const FunObjVar*, ICFGWTO*> funcToWTO;
133140
/// A set of functions which are involved in recursions
134141
Set<const FunObjVar*> recursiveFuns;
135142
/// Abstract trace immediately before an ICFGNode.
136143
Map<const ICFGNode*, AbstractState> preAbsTrace;
137-
/// Abstract trace immediately after an ICFGNode.
138-
Map<const ICFGNode*, AbstractState> postAbsTrace;
144+
/// Convenience alias: the "post" trace lives inside svfStateMgr.
145+
Map<const ICFGNode*, AbstractState>& postAbsTrace() {
146+
return svfStateMgr->getTrace();
147+
}
139148

140149
private:
141150
AbstractExecutionHelper bufOverflowHelper;

Assignment-3/CPP/Assignment_3_Helper.cpp

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -81,13 +81,13 @@ IntervalValue AbstractExecution::getAccessOffset(NodeID objId, const GepStmt* ge
8181
// Field-insensitive base object
8282
if (SVFUtil::isa<BaseObjVar>(obj)) {
8383
// get base size
84-
IntervalValue accessOffset = as.getByteOffset(gep);
84+
IntervalValue accessOffset = svfStateMgr->getGepByteOffset(gep);
8585
return accessOffset;
8686
}
8787
// A sub object of an aggregate object
8888
else if (SVFUtil::isa<GepObjVar>(obj)) {
8989
IntervalValue accessOffset =
90-
bufOverflowHelper.getGepObjOffsetFromBase(SVFUtil::cast<GepObjVar>(obj)) + as.getByteOffset(gep);
90+
bufOverflowHelper.getGepObjOffsetFromBase(SVFUtil::cast<GepObjVar>(obj)) + svfStateMgr->getGepByteOffset(gep);
9191
return accessOffset;
9292
}
9393
else{
@@ -221,12 +221,12 @@ bool AbstractExecution::mergeStatesFromPredecessors(const ICFGNode* block, Abstr
221221
// Iterate over all incoming edges of the given block
222222
for (auto& edge : block->getInEdges()) {
223223
// Check if the source node of the edge has a post-execution state recorded
224-
if (postAbsTrace.find(edge->getSrcNode()) != postAbsTrace.end()) {
224+
if (postAbsTrace().find(edge->getSrcNode()) != postAbsTrace().end()) {
225225
const IntraCFGEdge* intraCfgEdge = SVFUtil::dyn_cast<IntraCFGEdge>(edge);
226226

227227
// If the edge is an intra-block edge and has a condition
228228
if (intraCfgEdge && intraCfgEdge->getCondition()) {
229-
AbstractState tmpEs = postAbsTrace[edge->getSrcNode()];
229+
AbstractState tmpEs = postAbsTrace()[edge->getSrcNode()];
230230
// Check if the branch condition is feasible
231231
if (isBranchFeasible(intraCfgEdge, tmpEs)) {
232232
as.joinWith(tmpEs); // Merge the state with the current state
@@ -236,7 +236,7 @@ bool AbstractExecution::mergeStatesFromPredecessors(const ICFGNode* block, Abstr
236236
}
237237
else {
238238
// For non-conditional edges, directly merge the state
239-
as.joinWith(postAbsTrace[edge->getSrcNode()]);
239+
as.joinWith(postAbsTrace()[edge->getSrcNode()]);
240240
inEdgeNum++;
241241
}
242242
}
@@ -492,8 +492,8 @@ bool AbstractExecution::isBranchFeasible(const IntraCFGEdge* intraEdge, Abstract
492492
void AbstractExecution::handleGlobalNode() {
493493
AbstractState as;
494494
const ICFGNode* node = icfg->getGlobalICFGNode();
495-
postAbsTrace[node] = preAbsTrace[node];
496-
postAbsTrace[node][0] = AddressValue();
495+
postAbsTrace()[node] = preAbsTrace[node];
496+
postAbsTrace()[node][0] = AddressValue();
497497
// Global Node, we just need to handle addr, load, store, copy and gep
498498
for (const SVFStmt* stmt : node->getSVFStmts()) {
499499
updateAbsState(stmt);
@@ -543,7 +543,9 @@ void AbstractExecution::ensureAllAssertsValidated() {
543543
void AbstractExecution::analyse() {
544544
// Init WTOs for all functions, and handle Global ICFGNode of SVFModule
545545
initWTO();
546-
utils = new AbsExtAPI(postAbsTrace);
546+
AndersenWaveDiff* ander = AndersenWaveDiff::createAndersenWaveDiff(svfir);
547+
svfStateMgr = new AbstractStateManager(svfir, ander);
548+
utils = new AbsExtAPI(svfStateMgr);
547549

548550
// Handle the global node
549551
handleGlobalNode();
@@ -583,8 +585,8 @@ bool AbstractExecution::handleICFGNode(const ICFGNode* node) {
583585
}
584586
preAbsTrace[node] = tmpEs;
585587
// Store the last abstract state, used to check if the abstract state has reached a fixpoint
586-
AbstractState last_as = postAbsTrace[node];
587-
postAbsTrace[node] = preAbsTrace[node];
588+
AbstractState last_as = postAbsTrace()[node];
589+
postAbsTrace()[node] = preAbsTrace[node];
588590
for (const SVFStmt* stmt : node->getSVFStmts()) {
589591
updateAbsState(stmt);
590592
bufOverflowDetection(stmt);
@@ -594,7 +596,7 @@ bool AbstractExecution::handleICFGNode(const ICFGNode* node) {
594596
handleCallSite(callNode);
595597
}
596598
// If the abstract state is the same as the last abstract state, return false because we have reached fixpoint
597-
if (postAbsTrace[node] == last_as) {
599+
if (postAbsTrace()[node] == last_as) {
598600
return false;
599601
}
600602
return true;
@@ -680,14 +682,15 @@ void AbstractExecution::handleCallSite(const CallICFGNode* callNode) {
680682
}
681683
else if (fun_name == "nd" || fun_name == "rand") {
682684
NodeID lhsId = callNode->getRetICFGNode()->getActualRet()->getId();
683-
postAbsTrace[callNode][lhsId] = AbstractValue(IntervalValue::top());
685+
postAbsTrace()[callNode][lhsId] = AbstractValue(IntervalValue::top());
684686
}
685687
else if (isExternalCallForAssignment(callee)) {
686688
// implement external calls for the assignment
687689
updateStateOnExtCall(callNode);
688690
}
689691
else if (SVFUtil::isExtCall(callee)) {
690-
// handle external API calls
692+
// handle external API calls — AbsExtAPI reads/writes through the
693+
// same svfStateMgr that backs postAbsTrace(), so no sync needed.
691694
utils->handleExtAPI(callNode);
692695
}
693696
else if (recursiveFuns.find(callee) != recursiveFuns.end()) {

Assignment-3/CPP/Assignment_3_Helper.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,13 @@
2828
#include "AE/Core/AbstractState.h"
2929
#include "AE/Svfexe/AEDetector.h"
3030
#include "AE/Core/ICFGWTO.h"
31+
#include "SVFIR/SVFStatements.h"
32+
#include "Util/Options.h"
3133
#include "Util/SVFBugReport.h"
3234
namespace SVF {
3335
class AbstractExecutionHelper {
3436
public:
37+
3538
/// Add a detected bug to the bug reporter and print the report
3639
///@{
3740
void addBugToReporter(const AEException& e, const ICFGNode* node) {

Assignment-3/Python/Assignment_3.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ def bufOverflowDetection(self, stmt: pysvf.SVFStmt):
7777
# Update GEP object offset from base
7878
self.buf_overflow_helper.updateGepObjOffsetFromBase(abstract_state,
7979
abstract_state[lhs].getAddrs(), abstract_state[rhs].getAddrs(),
80-
abstract_state.getByteOffset(stmt)
80+
self.buf_overflow_helper.getByteOffset(abstract_state, stmt)
8181
)
8282

8383
# TODO: your code starts from here

Assignment-3/Python/Assignment_3_Helper.py

Lines changed: 61 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ ARG TARGETPLATFORM
88
RUN set -e
99

1010
# Define LLVM version.
11-
ENV llvm_version=18.1.0
11+
ENV llvm_version=21.1.0
1212

1313
# Define home directory
1414
ENV HOME=/home/SVF-tools

0 commit comments

Comments
 (0)