Skip to content

Commit

Permalink
Add Thread.start() virtualedge for constructor-provided Runnable
Browse files Browse the repository at this point in the history
  • Loading branch information
t1mlange committed Sep 21, 2023
1 parent 478c3e4 commit cee86ab
Show file tree
Hide file tree
Showing 3 changed files with 89 additions and 31 deletions.
36 changes: 15 additions & 21 deletions src/main/java/soot/jimple/spark/pag/PAG.java
Original file line number Diff line number Diff line change
Expand Up @@ -1091,31 +1091,25 @@ public void addCallTarget(Edge e) {
if (ve == null) {
return;
}
/*
* direct and indirect virtual edges can be handled identically, since getSource() retrieves the original source
* defined in virtualedges.xml
*/
// The source is equal for direct and indirect targets
VirtualEdgeSource edgeSrc = ve.getSource();

if (edgeSrc instanceof InstanceinvokeSource) {
/*
* iterate through all targets; since each target knows the argument index of its source (its direct predecessor), no
* distinction between indirect and direct virtual edges is necessary
*/
for (VirtualEdgeTarget edgeTgt : ve.getTargets()) {
// The PAG node for the call argument
Node parm = srcmpag.nodeFactory().getNode(ie.getArg(edgeTgt.getArgIndex()));
parm = srcmpag.parameterize(parm, e.srcCtxt());
parm = parm.getReplacement();

// Get the PAG node for the "this" local in the callback
Node thiz = tgtmpag.nodeFactory().caseThis();
thiz = tgtmpag.parameterize(thiz, e.tgtCtxt());
thiz = thiz.getReplacement();

// Make an edge from caller.argument to callee.this
addEdge(parm, thiz);
pval = addInterproceduralAssignment(parm, thiz, e);
for (Local local : getOnFlyCallGraph().ofcgb().getReceiversOfVirtualEdge(edgeTgt, ie)) {
Node parm = srcmpag.nodeFactory().getNode(local);
parm = srcmpag.parameterize(parm, e.srcCtxt());
parm = parm.getReplacement();

// Get the PAG node for the "this" local in the callback
Node thiz = tgtmpag.nodeFactory().caseThis();
thiz = tgtmpag.parameterize(thiz, e.tgtCtxt());
thiz = thiz.getReplacement();

// Make an edge from caller.argument to callee.this
addEdge(parm, thiz);
pval = addInterproceduralAssignment(parm, thiz, e);
}
}
}
} else if (e.isExplicit() || e.kind() == Kind.THREAD) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -856,19 +856,68 @@ protected void processVirtualEdgeSummary(SootMethod m, final Stmt s, Local recei
processVirtualEdgeSummary(m, s, s, receiver, target, edgeType);
}

private Local getLocalForTarget(InvokeExpr ie, VirtualEdgeTarget target) {
if (target.isBase() && ie instanceof InstanceInvokeExpr) {
return (Local) ((InstanceInvokeExpr) ie).getBase();
}

int index = target.getArgIndex();
if (index < ie.getArgCount()) {
Value arg = ie.getArg(index);
if (arg instanceof Local) {
return (Local) arg;
}
}

return null;
}

/** Returns all values that should be mapped to this in the edge target. **/
public Set<Local> getReceiversOfVirtualEdge(VirtualEdgeTarget edgeTarget, InvokeExpr invokeExpr) {
if (edgeTarget instanceof VirtualEdgesSummaries.IndirectTarget) {
VirtualEdgesSummaries.IndirectTarget indirectTarget = (VirtualEdgesSummaries.IndirectTarget) edgeTarget;
// Recursion case: We have an indirect target, which leads us to the statement where the local,
// that gets $this inside the callee, resides.

// First find the receiver of another call
Local l = getLocalForTarget(invokeExpr, edgeTarget);
if (l == null) {
return Collections.emptySet();
}

List<VirtualCallSite> sites = receiverToSites.get(l);
if (sites == null) {
return Collections.emptySet();
}
Set<Local> results = new HashSet<>();
MethodSubSignature methodName = edgeTarget.getTargetMethod();
// Lookup all call sites on the receiver to find the indirect target method
for (VirtualCallSite site : sites) {
if (methodName.equals(site.subSig())) {
for (VirtualEdgeTarget subTargets : indirectTarget.getTargets()) {
// We have found the indirect target, recursively go down till we have a direct target,
// where we can get the local that finally gets converted to $this inside the callee.
results.addAll(getReceiversOfVirtualEdge(subTargets, site.iie()));
// We might have multiple calls of the same method on the receiver (e.g. if else)
// as well as multiple sub-targets, thus, we can't break here.
}
}
}
return results;
}

assert edgeTarget instanceof DirectTarget;
// Base case: Lookup the value based on the index referenced by the VirtualEdgeTarget.
// That local represents the $this local inside the callee.
Local l = getLocalForTarget(invokeExpr, edgeTarget);
return l == null ? Collections.emptySet() : Collections.singleton(l);
}

protected void processVirtualEdgeSummary(SootMethod callSiteMethod, Stmt callSite, final Stmt curStmt, Local receiver,
VirtualEdgeTarget target, Kind edgeType) {
// Get the target object referenced by this edge summary
InvokeExpr ie = curStmt.getInvokeExpr();
Local targetLocal = null;
if (target.isBase()) {
targetLocal = receiver;
} else if (target.argIndex < ie.getArgCount()) {
Value runnable = ie.getArg(target.argIndex);
if (runnable instanceof Local) {
targetLocal = (Local) runnable;
}
}
Local targetLocal = getLocalForTarget(ie, target);
if (targetLocal == null) {
return;
}
Expand Down
17 changes: 16 additions & 1 deletion src/main/resources/virtualedges.xml
Original file line number Diff line number Diff line change
@@ -1,10 +1,25 @@
<?xml version="1.0"?>
<virtualedges>
<!-- Thread.start() -->
<edge type="THREAD">
<edge>
<source invoketype="instance" subsignature="void start()" />
<targets>
<direct subsignature="void run()" target-position="base" />
<indirect subsignature="void &lt;init&gt;(java.lang.Runnable)" target-position="base">
<direct subsignature="void run()" target-position="argument" index="0"/>
</indirect>
<indirect subsignature="void &lt;init&gt;(java.lang.Runnable,java.lang.String)" target-position="base" >
<direct subsignature="void run()" target-position="argument" index="0"/>
</indirect>
<indirect subsignature="void &lt;init&gt;(java.lang.ThreadGroup,java.lang.Runnable)" target-position="base">
<direct subsignature="void run()" target-position="argument" index="1"/>
</indirect>
<indirect subsignature="void &lt;init&gt;(java.lang.ThreadGroup,java.lang.Runnable,java.lang.String)" target-position="base">
<direct subsignature="void run()" target-position="argument" index="1"/>
</indirect>
<indirect subsignature="void &lt;init&gt;(java.lang.ThreadGroup,java.lang.Runnable,java.lang.String,long)" target-position="base">
<direct subsignature="void run()" target-position="argument" index="1"/>
</indirect>
</targets>
</edge>

Expand Down

0 comments on commit cee86ab

Please sign in to comment.