2013-05-22 23:04:25 +00:00
|
|
|
/******************************************************************************
|
|
|
|
* Copyright (c) 2002 - 2012 IBM Corporation.
|
|
|
|
* All rights reserved. This program and the accompanying materials
|
|
|
|
* are made available under the terms of the Eclipse Public License v1.0
|
|
|
|
* which accompanies this distribution, and is available at
|
|
|
|
* http://www.eclipse.org/legal/epl-v10.html
|
|
|
|
*
|
|
|
|
* Contributors:
|
|
|
|
* IBM Corporation - initial API and implementation
|
|
|
|
*****************************************************************************/
|
|
|
|
package com.ibm.wala.cast.js.callgraph.fieldbased;
|
|
|
|
|
|
|
|
import java.util.Iterator;
|
|
|
|
|
|
|
|
import com.ibm.wala.cast.js.callgraph.fieldbased.flowgraph.FlowGraph;
|
|
|
|
import com.ibm.wala.cast.js.callgraph.fieldbased.flowgraph.vertices.FuncVertex;
|
|
|
|
import com.ibm.wala.cast.js.callgraph.fieldbased.flowgraph.vertices.VertexFactory;
|
2014-05-28 17:35:40 +00:00
|
|
|
import com.ibm.wala.cast.js.ipa.summaries.JavaScriptConstructorFunctions;
|
2013-05-22 23:04:25 +00:00
|
|
|
import com.ibm.wala.cast.js.ssa.JavaScriptInvoke;
|
|
|
|
import com.ibm.wala.cast.js.types.JavaScriptTypes;
|
2013-09-26 17:13:05 +00:00
|
|
|
import com.ibm.wala.cast.loader.AstMethod;
|
2013-05-22 23:04:25 +00:00
|
|
|
import com.ibm.wala.cast.types.AstMethodReference;
|
|
|
|
import com.ibm.wala.classLoader.IClass;
|
|
|
|
import com.ibm.wala.classLoader.IMethod;
|
|
|
|
import com.ibm.wala.ipa.callgraph.AnalysisCache;
|
|
|
|
import com.ibm.wala.ipa.callgraph.AnalysisOptions;
|
2014-05-28 17:35:40 +00:00
|
|
|
import com.ibm.wala.ipa.callgraph.MethodTargetSelector;
|
2013-05-22 23:04:25 +00:00
|
|
|
import com.ibm.wala.ipa.cha.IClassHierarchy;
|
|
|
|
import com.ibm.wala.ssa.DefUse;
|
|
|
|
import com.ibm.wala.ssa.IR;
|
|
|
|
import com.ibm.wala.ssa.SSAInstruction;
|
|
|
|
import com.ibm.wala.ssa.SymbolTable;
|
|
|
|
import com.ibm.wala.types.TypeReference;
|
|
|
|
import com.ibm.wala.util.MonitorUtil.IProgressMonitor;
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Call graph builder for building pessimistic call graphs, where inter-procedural flows are not
|
|
|
|
* tracked except in the trivial case of local calls. This builder is fast, but in general less
|
|
|
|
* sound than {@link OptimisticCallgraphBuilder}.
|
|
|
|
*
|
|
|
|
* @author mschaefer
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
public class PessimisticCallGraphBuilder extends FieldBasedCallGraphBuilder {
|
2014-10-20 02:44:03 +00:00
|
|
|
public PessimisticCallGraphBuilder(IClassHierarchy cha, AnalysisOptions options, AnalysisCache cache, boolean supportFullPointerAnalysis) {
|
|
|
|
super(cha, options, cache, supportFullPointerAnalysis);
|
2013-05-22 23:04:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
2014-10-20 02:44:03 +00:00
|
|
|
public FlowGraph buildFlowGraph(IProgressMonitor monitor) {
|
|
|
|
FlowGraph flowgraph = flowGraphFactory();
|
2013-08-05 18:35:41 +00:00
|
|
|
resolveLocalCalls(flowgraph);
|
2013-05-22 23:04:25 +00:00
|
|
|
return flowgraph;
|
|
|
|
}
|
|
|
|
|
2013-10-16 21:37:53 +00:00
|
|
|
protected boolean filterFunction(IMethod function) {
|
|
|
|
return function.getDescriptor().equals(AstMethodReference.fnDesc);
|
|
|
|
}
|
|
|
|
|
2013-05-22 23:04:25 +00:00
|
|
|
// add inter-procedural flow for local calls
|
|
|
|
private void resolveLocalCalls(FlowGraph flowgraph) {
|
|
|
|
for(IClass klass : cha) {
|
|
|
|
for(IMethod method : klass.getDeclaredMethods()) {
|
2013-10-16 21:37:53 +00:00
|
|
|
if (filterFunction(method)) {
|
2013-05-22 23:04:25 +00:00
|
|
|
IR ir = cache.getIR(method);
|
|
|
|
ir.visitAllInstructions(new LocalCallSSAVisitor(method, ir.getSymbolTable(), cache.getDefUse(ir), flowgraph));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* This visitor looks for calls where the callee can be determined locally by a def-use graph, and adds
|
|
|
|
* inter-procedural edges.
|
|
|
|
*
|
|
|
|
* @author mschaefer
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
private class LocalCallSSAVisitor extends JSMethodInstructionVisitor {
|
|
|
|
private final FlowGraph flowgraph;
|
|
|
|
private final VertexFactory factory;
|
|
|
|
private final FuncVertex caller;
|
|
|
|
|
|
|
|
public LocalCallSSAVisitor(IMethod method, SymbolTable symtab, DefUse du, FlowGraph flowgraph) {
|
|
|
|
super(method, symtab, du);
|
|
|
|
this.flowgraph = flowgraph;
|
|
|
|
this.factory = flowgraph.getVertexFactory();
|
|
|
|
this.caller = this.factory.makeFuncVertex(method.getDeclaringClass());
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void visitJavaScriptInvoke(JavaScriptInvoke invk) {
|
|
|
|
// check whether this instruction corresponds to a function expression/declaration
|
|
|
|
if(isFunctionConstructorInvoke(invk)) {
|
|
|
|
int defn = invk.getDef();
|
|
|
|
|
|
|
|
// the name of the function
|
|
|
|
String fnName = symtab.getStringValue(invk.getUse(1));
|
|
|
|
IClass fnClass = cha.lookupClass(TypeReference.findOrCreate(JavaScriptTypes.jsLoader, fnName));
|
2013-09-26 17:13:05 +00:00
|
|
|
if (fnClass == null) {
|
|
|
|
System.err.println("cannot find " + fnName + " at " + ((AstMethod)method).getSourcePosition());
|
|
|
|
return;
|
|
|
|
}
|
2013-05-22 23:04:25 +00:00
|
|
|
IMethod fn = fnClass.getMethod(AstMethodReference.fnSelector);
|
|
|
|
FuncVertex callee = factory.makeFuncVertex(fnClass);
|
|
|
|
|
|
|
|
// look at all uses
|
|
|
|
for(Iterator<SSAInstruction> uses = du.getUses(defn);uses.hasNext();) {
|
|
|
|
SSAInstruction use = uses.next();
|
|
|
|
|
|
|
|
// check whether this is a local call
|
|
|
|
if(use instanceof JavaScriptInvoke && ((JavaScriptInvoke)use).getFunction() == defn) {
|
|
|
|
JavaScriptInvoke use_invk = (JavaScriptInvoke)use;
|
|
|
|
|
|
|
|
// yes, so add edges from arguments to parameters...
|
|
|
|
for(int i=2;i<use_invk.getNumberOfParameters();++i)
|
2014-05-28 17:35:40 +00:00
|
|
|
flowgraph.addEdge(factory.makeVarVertex(caller, use_invk.getUse(i)), factory.makeParamVertex(callee, i));
|
2013-05-22 23:04:25 +00:00
|
|
|
|
|
|
|
// ...and from return to result
|
|
|
|
flowgraph.addEdge(factory.makeRetVertex(callee), factory.makeVarVertex(caller, use.getDef()));
|
|
|
|
|
|
|
|
// note: local calls are never qualified, so there is no flow into the receiver vertex
|
|
|
|
} else {
|
|
|
|
// no, it's a more complicated use, so add flows from/to unknown
|
|
|
|
for(int i=1;i<fn.getNumberOfParameters();++i)
|
|
|
|
flowgraph.addEdge(factory.makeUnknownVertex(), factory.makeParamVertex(callee, i));
|
|
|
|
flowgraph.addEdge(factory.makeRetVertex(callee), factory.makeUnknownVertex());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
// this is a genuine function call; find out where the function came from
|
|
|
|
SSAInstruction def = du.getDef(invk.getFunction());
|
|
|
|
|
|
|
|
// if it's not a local call, add flows from/to unknown
|
|
|
|
if(!(def instanceof JavaScriptInvoke) || !isFunctionConstructorInvoke((JavaScriptInvoke)def)) {
|
|
|
|
for(int i=1;i<invk.getNumberOfParameters();++i)
|
|
|
|
flowgraph.addEdge(factory.makeVarVertex(caller, invk.getUse(i)), factory.makeUnknownVertex());
|
|
|
|
flowgraph.addEdge(factory.makeUnknownVertex(), factory.makeVarVertex(caller, invk.getDef()));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|