Skip to content

Commit

Permalink
added support for passing on types in the PAG in case we later want t…
Browse files Browse the repository at this point in the history
…o later invoke a method that object which we have a summary.

Example:

List<...> l = ...;
Spliterator<...> s = l.spliterator();
s.forEachRemaining(callback);

We would normally lose the type information over the call to spliterator() if we don't have an implementation for that method. With the new deferred PAG summary, we can just use the declared type because we know that we will use a summary for the call to forEachRemaining() later anyway, so the actual type of the Spliterator is irrelevant.
  • Loading branch information
StevenArzt committed May 24, 2024
1 parent 6dc6ad1 commit 47ad2a6
Show file tree
Hide file tree
Showing 4 changed files with 213 additions and 72 deletions.
57 changes: 44 additions & 13 deletions src/main/java/soot/jimple/spark/pag/PAG.java
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import soot.AnySubType;
import soot.Context;
import soot.FastHierarchy;
import soot.Kind;
Expand Down Expand Up @@ -80,7 +81,9 @@
import soot.jimple.spark.solver.OnFlyCallGraph;
import soot.jimple.toolkits.callgraph.Edge;
import soot.jimple.toolkits.callgraph.VirtualEdgesSummaries;
import soot.jimple.toolkits.callgraph.VirtualEdgesSummaries.DeferredVirtualEdgeTarget;
import soot.jimple.toolkits.callgraph.VirtualEdgesSummaries.InstanceinvokeSource;
import soot.jimple.toolkits.callgraph.VirtualEdgesSummaries.InvocationVirtualEdgeTarget;
import soot.jimple.toolkits.callgraph.VirtualEdgesSummaries.VirtualEdge;
import soot.jimple.toolkits.callgraph.VirtualEdgesSummaries.VirtualEdgeSource;
import soot.jimple.toolkits.callgraph.VirtualEdgesSummaries.VirtualEdgeTarget;
Expand Down Expand Up @@ -1093,19 +1096,47 @@ public void addCallTarget(Edge e) {

if (edgeSrc instanceof InstanceinvokeSource) {
for (VirtualEdgeTarget edgeTgt : ve.getTargets()) {
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);
if (edgeTgt instanceof InvocationVirtualEdgeTarget) {
for (Local local : getOnFlyCallGraph().ofcgb().getReceiversOfVirtualEdge((InvocationVirtualEdgeTarget) 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 (edgeTgt instanceof DeferredVirtualEdgeTarget && e.srcStmt() instanceof AssignStmt
&& ie.getMethodRef().getReturnType() instanceof RefType) {
DeferredVirtualEdgeTarget de = (DeferredVirtualEdgeTarget) edgeTgt;

// We need to fake an edge to the return value of the call
Local lop = (Local) ((AssignStmt) e.srcStmt()).getLeftOp();
Node ln = srcmpag.nodeFactory().getNode(lop);
ln = srcmpag.parameterize(ln, e.srcCtxt());
ln = ln.getReplacement();

RefType rt = de.getTargetType();
if (rt == null)
rt = (RefType) ie.getMethodRef().getReturnType();

// Fake an allocation node
AllocNode alloc
= makeAllocNode(new Pair<VarNode, SootClass>((VarNode) ln, rt.getSootClass()), AnySubType.v(rt), e.src());

// temporary variable
VarNode tmp = makeLocalVarNode(alloc, rt, e.src());

// tmp = new T();
addAllocEdge(alloc, tmp);
addEdge(tmp, ln);
// ofcg.updatedNode((VarNode) ln);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package soot.jimple.toolkits.callgraph;

import java.lang.reflect.Constructor;

/*-
* #%L
* Soot - a J*va Optimization Framework
Expand Down Expand Up @@ -94,10 +96,13 @@
import soot.jimple.StringConstant;
import soot.jimple.VirtualInvokeExpr;
import soot.jimple.spark.pag.AllocDotField;
import soot.jimple.spark.pag.PAG;
import soot.jimple.toolkits.annotation.nullcheck.NullnessAnalysis;
import soot.jimple.toolkits.callgraph.ConstantArrayAnalysis.ArrayTypes;
import soot.jimple.toolkits.callgraph.VirtualEdgesSummaries.DeferredVirtualEdgeTarget;
import soot.jimple.toolkits.callgraph.VirtualEdgesSummaries.DirectTarget;
import soot.jimple.toolkits.callgraph.VirtualEdgesSummaries.IndirectTarget;
import soot.jimple.toolkits.callgraph.VirtualEdgesSummaries.InvocationVirtualEdgeTarget;
import soot.jimple.toolkits.callgraph.VirtualEdgesSummaries.VirtualEdge;
import soot.jimple.toolkits.callgraph.VirtualEdgesSummaries.VirtualEdgeTarget;
import soot.jimple.toolkits.reflection.ReflectionTraceInfo;
Expand Down Expand Up @@ -438,7 +443,7 @@ private void resolveInvoke(Collection<InvokeCallSite> list) {
Iterator<SootMethod> mIt = getPublicMethodIterator(baseClass, reachingTypes, methodSizes, mustNotBeNull);
while (mIt.hasNext()) {
SootMethod sm = mIt.next();
cm.addVirtualEdge(ics.container(), ics.stmt(), sm, Kind.REFL_INVOKE, null);
cm.addVirtualEdge(ics.getContainer(), ics.getStmt(), sm, Kind.REFL_INVOKE, null);
}
}
}
Expand Down Expand Up @@ -806,14 +811,20 @@ protected void findReceivers(SootMethod m, Body b) {
InstanceInvokeExpr iie = (InstanceInvokeExpr) ie;
Local receiver = (Local) iie.getBase();
MethodSubSignature subSig = new MethodSubSignature(iie.getMethodRef());
addVirtualCallSite(s, m, receiver, iie, new MethodSubSignature(iie.getMethodRef()), Edge.ieToKind(iie));

VirtualEdge virtualEdge = virtualEdgeSummaries.getVirtualEdgesMatchingSubSig(subSig);
if (virtualEdge != null) {
for (VirtualEdgeTarget t : virtualEdge.targets) {
processVirtualEdgeSummary(m, s, receiver, t, virtualEdge.edgeType);
if (t instanceof InvocationVirtualEdgeTarget) {
processVirtualEdgeSummary(m, s, receiver, (InvocationVirtualEdgeTarget) t, virtualEdge.edgeType);
} else if (t instanceof DeferredVirtualEdgeTarget) {
addVirtualCallSite(s, m, receiver, iie, new MethodSubSignature(iie.getMethodRef()), Kind.GENERIC_FAKE);
}
}
}

// if (!hasVirtualEdge || !iie.getMethod().isPhantom())
addVirtualCallSite(s, m, receiver, iie, new MethodSubSignature(iie.getMethodRef()), Edge.ieToKind(iie));
} else if (ie instanceof DynamicInvokeExpr) {
if (options.verbose()) {
logger.warn("InvokeDynamic to " + ie + " not resolved during call-graph construction.");
Expand All @@ -828,10 +839,10 @@ protected void findReceivers(SootMethod m, Body b) {
for (VirtualEdgeTarget t : virtualEdge.targets) {
if (t instanceof DirectTarget) {
DirectTarget directTarget = (DirectTarget) t;
if (t.isBase()) {
if (directTarget.isBase()) {
// this should not happen
} else {
Value runnable = ie.getArg(t.argIndex);
Value runnable = ie.getArg(directTarget.argIndex);
if (runnable instanceof Local) {
addVirtualCallSite(s, m, (Local) runnable, null, directTarget.targetMethod, Kind.GENERIC_FAKE);
}
Expand All @@ -848,12 +859,12 @@ protected void findReceivers(SootMethod m, Body b) {
}
}

protected void processVirtualEdgeSummary(SootMethod m, final Stmt s, Local receiver, VirtualEdgeTarget target,
protected void processVirtualEdgeSummary(SootMethod m, final Stmt s, Local receiver, InvocationVirtualEdgeTarget target,
Kind edgeType) {
processVirtualEdgeSummary(m, s, s, receiver, target, edgeType);
}

private Local getLocalForTarget(InvokeExpr ie, VirtualEdgeTarget target) {
private Local getLocalForTarget(InvokeExpr ie, InvocationVirtualEdgeTarget target) {
if (target.isBase() && ie instanceof InstanceInvokeExpr) {
return (Local) ((InstanceInvokeExpr) ie).getBase();
}
Expand All @@ -870,7 +881,7 @@ private Local getLocalForTarget(InvokeExpr ie, VirtualEdgeTarget target) {
}

/** Returns all values that should be mapped to this in the edge target. **/
public Set<Local> getReceiversOfVirtualEdge(VirtualEdgeTarget edgeTarget, InvokeExpr invokeExpr) {
public Set<Local> getReceiversOfVirtualEdge(InvocationVirtualEdgeTarget 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,
Expand All @@ -892,11 +903,13 @@ public Set<Local> getReceiversOfVirtualEdge(VirtualEdgeTarget edgeTarget, Invoke
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.
if (subTargets instanceof InvocationVirtualEdgeTarget) {
// 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((InvocationVirtualEdgeTarget) 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.
}
}
}
}
Expand All @@ -911,7 +924,7 @@ public Set<Local> getReceiversOfVirtualEdge(VirtualEdgeTarget edgeTarget, Invoke
}

protected void processVirtualEdgeSummary(SootMethod callSiteMethod, Stmt callSite, final Stmt curStmt, Local receiver,
VirtualEdgeTarget target, Kind edgeType) {
InvocationVirtualEdgeTarget target, Kind edgeType) {
// Get the target object referenced by this edge summary
InvokeExpr ie = curStmt.getInvokeExpr();
Local targetLocal = getLocalForTarget(ie, target);
Expand Down Expand Up @@ -941,8 +954,9 @@ protected void processVirtualEdgeSummary(SootMethod callSiteMethod, Stmt callSit
if (w.getTargetMethod().equals(site.subSig())) {
for (VirtualEdgeTarget siteTarget : w.getTargets()) {
Stmt siteStmt = site.getStmt();
if (siteStmt.containsInvokeExpr()) {
processVirtualEdgeSummary(callSiteMethod, callSite, siteStmt, receiver, siteTarget, edgeType);
if (siteStmt.containsInvokeExpr() && siteTarget instanceof InvocationVirtualEdgeTarget) {
processVirtualEdgeSummary(callSiteMethod, callSite, siteStmt, receiver,
(InvocationVirtualEdgeTarget) siteTarget, edgeType);
}
}
}
Expand Down
Loading

0 comments on commit 47ad2a6

Please sign in to comment.