178 lines
6.7 KiB
Java
178 lines
6.7 KiB
Java
package com.ibm.wala.cast.js.rhino.test;
|
|
|
|
import java.io.File;
|
|
import java.io.FileNotFoundException;
|
|
import java.io.IOException;
|
|
import java.net.MalformedURLException;
|
|
import java.net.URL;
|
|
import java.util.Properties;
|
|
|
|
import junit.framework.Assert;
|
|
|
|
import org.eclipse.core.runtime.NullProgressMonitor;
|
|
|
|
import com.ibm.wala.cast.ir.translator.AstTranslator;
|
|
import com.ibm.wala.cast.js.ipa.callgraph.ForInContextSelector;
|
|
import com.ibm.wala.cast.js.ipa.callgraph.JSCFABuilder;
|
|
import com.ibm.wala.cast.js.ipa.callgraph.JavaScriptFunctionDotCallTargetSelector;
|
|
import com.ibm.wala.cast.js.ipa.callgraph.RecursionCheckContextSelector;
|
|
import com.ibm.wala.cast.js.ipa.callgraph.correlations.extraction.CorrelatedPairExtractorFactory;
|
|
import com.ibm.wala.cast.js.test.JSCallGraphBuilderUtil;
|
|
import com.ibm.wala.cast.js.test.JSCallGraphBuilderUtil.CGBuilderType;
|
|
import com.ibm.wala.cast.js.translator.CAstRhinoTranslatorFactory;
|
|
import com.ibm.wala.ipa.callgraph.CGNode;
|
|
import com.ibm.wala.ipa.callgraph.CallGraph;
|
|
import com.ibm.wala.ipa.callgraph.CallGraphBuilderCancelException;
|
|
import com.ibm.wala.ipa.callgraph.propagation.PointerAnalysis;
|
|
import com.ibm.wala.ipa.cha.ClassHierarchyException;
|
|
import com.ibm.wala.util.ProgressMaster;
|
|
import com.ibm.wala.util.ProgressMonitorDelegate;
|
|
import com.ibm.wala.util.io.CommandLine;
|
|
import com.ibm.wala.util.io.FileProvider;
|
|
|
|
/**
|
|
* Utility class for building call graphs of HTML pages.
|
|
*
|
|
* @author mschaefer
|
|
*
|
|
*/
|
|
public class HTMLCGBuilder {
|
|
public static final int DEFAULT_TIMEOUT = 120;
|
|
|
|
/**
|
|
* Simple struct-like type to hold results of call graph construction.
|
|
*
|
|
* @author mschaefer
|
|
*
|
|
*/
|
|
public static class CGBuilderResult {
|
|
/** time it took to build the call graph; {@code -1} if timeout occurred */
|
|
public long construction_time;
|
|
|
|
/** builder responsible for building the call graph*/
|
|
public JSCFABuilder builder;
|
|
|
|
/** pointer analysis results; partial if {@link #construction_time} is {@code -1} */
|
|
public PointerAnalysis pa;
|
|
|
|
/** call graph; partial if {@link #construction_time} is {@code -1} */
|
|
public CallGraph cg;
|
|
}
|
|
|
|
/**
|
|
* Build a call graph for an HTML page, optionally with a timeout.
|
|
*
|
|
* @param src
|
|
* the HTML page to analyse, can either be a path to a local file or a URL
|
|
* @param timeout
|
|
* analysis timeout in seconds, -1 means no timeout
|
|
* @param automated_extraction
|
|
* whether to automatically extract correlated pairs
|
|
* @throws IOException
|
|
* @throws ClassHierarchyException
|
|
*/
|
|
public static CGBuilderResult buildHTMLCG(String src, int timeout, boolean automated_extraction, CGBuilderType builderType)
|
|
throws ClassHierarchyException, IOException {
|
|
CGBuilderResult res = new CGBuilderResult();
|
|
URL url = null;
|
|
try {
|
|
url = toUrl(src);
|
|
} catch (MalformedURLException e1) {
|
|
Assert.fail("Could not find page to analyse: " + src);
|
|
}
|
|
com.ibm.wala.cast.js.ipa.callgraph.JSCallGraphUtil.setTranslatorFactory(new CAstRhinoTranslatorFactory());
|
|
if(automated_extraction)
|
|
com.ibm.wala.cast.js.ipa.callgraph.JSCallGraphUtil.setPreprocessor(new CorrelatedPairExtractorFactory(new CAstRhinoTranslatorFactory(), url));
|
|
JSCFABuilder builder = null;
|
|
try {
|
|
builder = JSCallGraphBuilderUtil.makeHTMLCGBuilder(url, builderType);
|
|
builder.setContextSelector(new ForInContextSelector(2, builder.getContextSelector()));
|
|
builder.setContextSelector(new ForInContextSelector(3, builder.getContextSelector()));
|
|
// TODO we need to find a better way to do this ContextSelector delegation;
|
|
// the code below belongs somewhere else!!!
|
|
// the bound of 4 is what is needed to pass our current framework tests
|
|
if (AstTranslator.NEW_LEXICAL) {
|
|
// builder.setContextSelector(new RecursionBoundContextSelector(builder.getContextSelector(), 4));
|
|
builder.setContextSelector(new RecursionCheckContextSelector(builder.getContextSelector()));
|
|
}
|
|
ProgressMaster master = ProgressMaster.make(new NullProgressMonitor());
|
|
if (timeout > 0) {
|
|
master.setMillisPerWorkItem(timeout * 1000);
|
|
master.beginTask("runSolver", 1);
|
|
}
|
|
long start = System.currentTimeMillis();
|
|
CallGraph cg = timeout > 0 ? builder.makeCallGraph(builder.getOptions(),
|
|
ProgressMonitorDelegate.createProgressMonitorDelegate(master)) : builder.makeCallGraph(builder.getOptions());
|
|
long end = System.currentTimeMillis();
|
|
master.done();
|
|
res.construction_time = (end - start);
|
|
res.cg = cg;
|
|
res.pa = builder.getPointerAnalysis();
|
|
res.builder = builder;
|
|
return res;
|
|
} catch (CallGraphBuilderCancelException e) {
|
|
res.construction_time = -1;
|
|
res.cg = e.getPartialCallGraph();
|
|
res.pa = e.getPartialPointerAnalysis();
|
|
res.builder = builder;
|
|
return res;
|
|
} catch (Exception e) {
|
|
throw new Error(e);
|
|
}
|
|
}
|
|
|
|
private static URL toUrl(String src) throws MalformedURLException {
|
|
// first try interpreting as local file name, if that doesn't work just
|
|
// assume it's a URL
|
|
try {
|
|
File f = FileProvider.getFileFromClassLoader(src, HTMLCGBuilder.class.getClassLoader());
|
|
URL url = f.toURI().toURL();
|
|
return url;
|
|
} catch (FileNotFoundException fnfe) {
|
|
return new URL(src);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Usage: HTMLCGBuilder -src path_to_html_file -timeout timeout_in_seconds -reachable function_name
|
|
* timeout argument is optional and defaults to {@link #DEFAULT_TIMEOUT}.
|
|
* reachable argument is optional. if provided, and some reachable function name contains function_name,
|
|
* will print "REACHABLE"
|
|
* @throws IOException
|
|
* @throws ClassHierarchyException
|
|
*
|
|
*/
|
|
public static void main(String[] args) throws ClassHierarchyException, IOException {
|
|
Properties parsedArgs = CommandLine.parse(args);
|
|
String src = parsedArgs.getProperty("src");
|
|
if (src == null) {
|
|
throw new IllegalArgumentException("-src argument is required");
|
|
}
|
|
int timeout;
|
|
if (parsedArgs.containsKey("timeout")) {
|
|
timeout = Integer.parseInt(parsedArgs.getProperty("timeout"));
|
|
} else {
|
|
timeout = DEFAULT_TIMEOUT;
|
|
}
|
|
String reachableName = null;
|
|
if (parsedArgs.containsKey("reachable")) {
|
|
reachableName = parsedArgs.getProperty("reachable");
|
|
}
|
|
// suppress debug output
|
|
JavaScriptFunctionDotCallTargetSelector.WARN_ABOUT_IMPRECISE_CALLGRAPH = false;
|
|
CGBuilderResult res = buildHTMLCG(src, timeout, true, AstTranslator.NEW_LEXICAL ? CGBuilderType.ONE_CFA_PRECISE_LEXICAL : CGBuilderType.ZERO_ONE_CFA);
|
|
if(res.construction_time == -1)
|
|
System.out.println("TIMED OUT");
|
|
else
|
|
System.out.println("Call graph construction took " + res.construction_time/1000.0 + " seconds");
|
|
if (reachableName != null) {
|
|
for (CGNode node : res.cg) {
|
|
if (node.getMethod().getDeclaringClass().getName().toString().contains(reachableName)) {
|
|
System.out.println("REACHABLE");
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|