Skip to content

Commit 558624c

Browse files
authored
Handle returned values from Function.protoype.apply calls in ACG (#855)
1 parent 59afde0 commit 558624c

File tree

4 files changed

+43
-26
lines changed

4 files changed

+43
-26
lines changed

com.ibm.wala.cast.js.rhino/src/test/java/com/ibm/wala/cast/js/rhino/callgraph/fieldbased/test/TestFieldBasedCG.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,8 @@ public void testLexicalWorklist() throws WalaException, Error, CancelException {
108108
},
109109
new Object[] {"suffix:Function_prototype_call", new String[] {"suffix:f"}},
110110
new Object[] {"suffix:Function_prototype_apply", new String[] {"suffix:x"}},
111-
new Object[] {"suffix:f", new String[] {"suffix:k"}}
111+
new Object[] {"suffix:f", new String[] {"suffix:k"}},
112+
new Object[] {"suffix:p", new String[] {"suffix:n"}}
112113
};
113114

114115
@Test

com.ibm.wala.cast.js.rhino/src/test/java/com/ibm/wala/cast/js/test/TestFlowGraphJSON.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,9 @@ public void testCallAndApply() {
7777
"Param(Func(flowgraph_constraints.js@30), 2)"));
7878
assertThat(
7979
Arrays.asList(parsedJSON.get("Ret(Func(flowgraph_constraints.js@30))")),
80-
containsInAnyOrder("Var(flowgraph_constraints.js@29, [res1])"));
80+
containsInAnyOrder(
81+
"Var(flowgraph_constraints.js@29, [res1])",
82+
"Var(flowgraph_constraints.js@29, [res2])"));
8183
}
8284

8385
private static Map<String, String[]> getParsedFlowGraphJSON(String script)

com.ibm.wala.cast.js/src/main/java/com/ibm/wala/cast/js/callgraph/fieldbased/WorklistBasedOptimisticCallgraphBuilder.java

Lines changed: 29 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,8 @@ public Set<Pair<CallVertex, FuncVertex>> extractCallGraphEdges(
7575
VertexFactory factory = flowgraph.getVertexFactory();
7676
Set<Vertex> worklist = HashSetFactory.make();
7777
Map<Vertex, Set<FuncVertex>> reachingFunctions = HashMapFactory.make();
78-
Map<VarVertex, JavaScriptInvoke> reflectiveCalleeVertices = HashMapFactory.make();
78+
Map<VarVertex, Pair<JavaScriptInvoke, Boolean>> reflectiveCalleeVertices =
79+
HashMapFactory.make();
7980

8081
for (Vertex v : flowgraph) {
8182
if (v instanceof FuncVertex) {
@@ -116,21 +117,22 @@ public Set<Pair<CallVertex, FuncVertex>> extractCallGraphEdges(
116117
reflectiveCalleeVertex,
117118
factory.makeReflectiveCallVertex(callVertex.getCaller(), invk));
118119
// we only add dataflow edges for Function.prototype.call
119-
if (fullName.equals("Lprologue.js/Function_prototype_call")) {
120-
reflectiveCalleeVertices.put(reflectiveCalleeVertex, invk);
121-
for (FuncVertex fw :
122-
MapUtil.findOrCreateSet(reachingFunctions, reflectiveCalleeVertex))
123-
addReflectiveCallEdge(flowgraph, reflectiveCalleeVertex, invk, fw, worklist);
124-
}
120+
boolean isCall = fullName.equals("Lprologue.js/Function_prototype_call");
121+
reflectiveCalleeVertices.put(reflectiveCalleeVertex, Pair.make(invk, isCall));
122+
for (FuncVertex fw :
123+
MapUtil.findOrCreateSet(reachingFunctions, reflectiveCalleeVertex))
124+
addReflectiveCallEdge(
125+
flowgraph, reflectiveCalleeVertex, invk, fw, worklist, isCall);
125126
}
126127
}
127128
}
128129
} else if (handleCallApply && reflectiveCalleeVertices.containsKey(w)) {
129-
JavaScriptInvoke invk = reflectiveCalleeVertices.get(w);
130+
Pair<JavaScriptInvoke, Boolean> invkAndIsCall = reflectiveCalleeVertices.get(w);
130131
for (FuncVertex fv : vReach) {
131132
if (wReach.add(fv)) {
132133
changed = true;
133-
addReflectiveCallEdge(flowgraph, (VarVertex) w, invk, fv, worklist);
134+
addReflectiveCallEdge(
135+
flowgraph, (VarVertex) w, invkAndIsCall.fst, fv, worklist, invkAndIsCall.snd);
134136
}
135137
}
136138
} else {
@@ -197,24 +199,27 @@ private void addReflectiveCallEdge(
197199
VarVertex reflectiveCallee,
198200
JavaScriptInvoke invk,
199201
FuncVertex realCallee,
200-
Set<Vertex> worklist) {
202+
Set<Vertex> worklist,
203+
boolean isFunctionPrototypeCall) {
201204
VertexFactory factory = flowgraph.getVertexFactory();
202205
FuncVertex caller = reflectiveCallee.getFunction();
203206

204-
// flow from arguments to parameters
205-
for (int i = 2; i < invk.getNumberOfPositionalParameters(); ++i) {
206-
addFlowEdge(
207-
flowgraph,
208-
factory.makeVarVertex(caller, invk.getUse(i)),
209-
factory.makeParamVertex(realCallee, i - 1),
210-
worklist);
211-
212-
// flow from return vertex to result vertex
213-
addFlowEdge(
214-
flowgraph,
215-
factory.makeRetVertex(realCallee),
216-
factory.makeVarVertex(caller, invk.getDef()),
217-
worklist);
207+
if (isFunctionPrototypeCall) {
208+
// flow from arguments to parameters
209+
for (int i = 2; i < invk.getNumberOfPositionalParameters(); ++i) {
210+
addFlowEdge(
211+
flowgraph,
212+
factory.makeVarVertex(caller, invk.getUse(i)),
213+
factory.makeParamVertex(realCallee, i - 1),
214+
worklist);
215+
}
218216
}
217+
218+
// flow from return vertex to result vertex
219+
addFlowEdge(
220+
flowgraph,
221+
factory.makeRetVertex(realCallee),
222+
factory.makeVarVertex(caller, invk.getDef()),
223+
worklist);
219224
}
220225
}

com.ibm.wala.cast.js/src/test/resources/tests/fieldbased/reflective_calls.js

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,12 @@ function h() {
1414
function k() {}
1515

1616
h();
17+
18+
function m() {
19+
return function n() {}
20+
}
21+
22+
function p() {
23+
var x = m.apply(null, []);
24+
x();
25+
}

0 commit comments

Comments
 (0)