incorporate changes from other branch

- basic compatibility with Java 7 (i.e., don't crash immediately)
- Added utility class for converting call graphs to JSON.
- add edgeExists CLI option to check if some edge exists in the call graph
This commit is contained in:
Juergen Graf 2014-04-09 16:55:36 +02:00
parent 883b5f2437
commit b8477d2144
6 changed files with 200 additions and 3 deletions

View File

@ -37,6 +37,7 @@ 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.collections.Iterator2Iterable;
import com.ibm.wala.util.io.CommandLine;
import com.ibm.wala.util.io.FileProvider;
@ -168,6 +169,13 @@ public class HTMLCGBuilder {
if (parsedArgs.containsKey("reachable")) {
reachableName = parsedArgs.getProperty("reachable");
}
String srcNode = null, dstNode = null;
if (parsedArgs.containsKey("edgeExists")) {
String[] nodes = parsedArgs.getProperty("edgeExists").split(":");
srcNode = nodes[0];
dstNode = nodes[1];
}
// 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);
@ -183,5 +191,16 @@ public class HTMLCGBuilder {
}
}
}
if (srcNode != null) {
for (CGNode node : res.cg) {
if (node.getMethod().getDeclaringClass().getName().toString().endsWith(srcNode)) {
for (CGNode callee : Iterator2Iterable.make(res.cg.getSuccNodes(node))) {
if (callee.getMethod().getDeclaringClass().getName().toString().endsWith(dstNode)) {
System.out.println("EDGE EXISTS");
}
}
}
}
}
}
}

View File

@ -0,0 +1,174 @@
/******************************************************************************
* 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.util;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import com.ibm.wala.cast.js.types.JavaScriptMethods;
import com.ibm.wala.cast.loader.AstMethod;
import com.ibm.wala.cast.tree.CAstSourcePositionMap.Position;
import com.ibm.wala.cast.types.AstMethodReference;
import com.ibm.wala.classLoader.CallSiteReference;
import com.ibm.wala.classLoader.IMethod;
import com.ibm.wala.ipa.callgraph.CGNode;
import com.ibm.wala.ipa.callgraph.CallGraph;
import com.ibm.wala.util.collections.HashMapFactory;
import com.ibm.wala.util.collections.MapUtil;
import com.ibm.wala.util.collections.Util;
import com.ibm.wala.util.functions.Function;
/**
* Utility class to serialize call graphs as JSON objects.
*
* The serialised objects have the form
*
* <pre>
* {
* "&lt;callsite1&gt;": [ "&lt;callee1&gt;", "&lt;callee2&gt;", ... ],
* "&lt;callsite2&gt;": ...
* }
* </pre>
*
* where both call sites and callees are encoded as strings
* of the form
*
* <pre>
* "&lt;filename&gt;@&lt;lineno&gt;:&lt;beginoff&gt;-&lt;endoff&gt;"
* </pre>
*
* Here, <code>filename</code> is the name of the containing
* JavaScript file (not including its directory), and
* <code>lineno</code>, <code>beginoff</code> and <code>endoff</code>
* encode the source position of the call expression (for
* call sites) or the function declaration/expression (for
* callees) inside the file in terms of its starting line,
* its starting offset (in characters from the beginning of the
* file), and its end offset.
*
* @author mschaefer
*/
public class CallGraph2JSON {
public static boolean IGNORE_HARNESS = true;
public static String serialize(CallGraph cg) {
Map<String, Set<String>> edges = extractEdges(cg);
return toJSON(edges);
}
public static Map<String, Set<String>> extractEdges(CallGraph cg) {
Map<String, Set<String>> edges = HashMapFactory.make();
for(CGNode nd : cg) {
if(!isRealFunction(nd.getMethod()))
continue;
AstMethod method = (AstMethod)nd.getMethod();
for(Iterator<CallSiteReference> iter = nd.iterateCallSites(); iter.hasNext();) {
CallSiteReference callsite = iter.next();
Set<IMethod> targets = Util.mapToSet(cg.getPossibleTargets(nd, callsite), new Function<CGNode, IMethod>() {
@Override
public IMethod apply(CGNode nd) {
return nd.getMethod();
}
});
serializeCallSite(method, callsite, targets, edges);
}
}
return edges;
}
public static void serializeCallSite(AstMethod method, CallSiteReference callsite, Set<IMethod> targets,
Map<String, Set<String>> edges) {
Set<String> targetNames = MapUtil.findOrCreateSet(edges, ppPos(method, method.getSourcePosition(callsite.getProgramCounter())));
for(IMethod target : targets) {
target = getCallTargetMethod(target);
if(!isRealFunction(target))
continue;
targetNames.add(ppPos((AstMethod)target, ((AstMethod)target).getSourcePosition()));
}
}
private static IMethod getCallTargetMethod(IMethod method) {
if(method.getName().equals(JavaScriptMethods.ctorAtom)) {
method = method.getDeclaringClass().getMethod(AstMethodReference.fnSelector);
if(method != null)
return method;
}
return method;
}
public static boolean isRealFunction(IMethod method) {
if(method instanceof AstMethod) {
String methodName = method.getDeclaringClass().getName().toString();
// exclude synthetic DOM modelling functions
if(methodName.contains("/make_node"))
return false;
if(IGNORE_HARNESS && methodName.startsWith("Lprologue.js/") || methodName.startsWith("Lpreamble.js/"))
return false;
return method.getName().equals(AstMethodReference.fnAtom);
}
return false;
}
private static String ppPos(AstMethod method, Position pos) {
String file = pos.getURL().getFile();
file = file.substring(file.lastIndexOf('/')+1);
int line = pos.getFirstLine(), start_offset = pos.getFirstOffset(), end_offset = pos.getLastOffset();
return file + "@" + line + ":" + start_offset + "-" + end_offset;
}
public static String toJSON(Map<String, Set<String>> map) {
StringBuffer res = new StringBuffer();
res.append("{\n");
res.append(joinWith(Util.mapToSet(map.entrySet(), new Function<Map.Entry<String, Set<String>>, String>() {
@Override
public String apply(Map.Entry<String, Set<String>> e) {
StringBuffer res = new StringBuffer();
if(e.getValue().size() > 0) {
res.append(" \"" + e.getKey() + "\": [\n");
res.append(joinWith(Util.mapToSet(e.getValue(), new Function<String, String>() {
@Override
public String apply(String str) {
return " \"" + str + "\"";
}
}), ",\n"));
res.append("\n ]");
}
return res.length() == 0 ? null : res.toString();
}
}), ",\n"));
res.append("\n}");
return res.toString();
}
private static String joinWith(Iterable<String> lst, String sep) {
StringBuffer res = new StringBuffer();
ArrayList<String> strings = new ArrayList<String>();
for(String s : lst)
if(s != null)
strings.add(s);
boolean fst = true;
for(String s : strings) {
if(fst)
fst = false;
else
res.append(sep);
res.append(s);
}
return res.toString();
}
}

View File

@ -36,7 +36,7 @@ public class LibraryVersionTest extends WalaTestCase {
@Test public void testLibraryVersion() throws IOException {
AnalysisScope scope = AnalysisScopeReader.readJavaScope(TestConstants.WALA_TESTDATA, (new FileProvider()).getFile("J2SEClassHierarchyExclusions.txt"), MY_CLASSLOADER);
System.err.println("java library version is " + scope.getJavaLibraryVersion());
Assert.assertTrue(scope.isJava16Libraries() || scope.isJava15Libraries()||scope.isJava14Libraries());
Assert.assertTrue(scope.isJava17Libraries() || scope.isJava16Libraries() || scope.isJava15Libraries()||scope.isJava14Libraries());
}
}

View File

@ -67,7 +67,7 @@ public class DataflowTest extends WalaTestCase {
public static void beforeClass() throws Exception {
scope = AnalysisScopeReader.readJavaScope(TestConstants.WALA_TESTDATA,
(new FileProvider()).getFile("J2SEClassHierarchyExclusions.txt"), DataflowTest.class.getClassLoader());
(new FileProvider()).getFile(CallGraphTestUtil.REGRESSION_EXCLUSIONS), DataflowTest.class.getClassLoader());
try {
cha = ClassHierarchy.make(scope);

View File

@ -411,6 +411,10 @@ public class AnalysisScope {
}
}
public boolean isJava17Libraries() throws IllegalStateException {
return getJavaLibraryVersion().startsWith("1.7");
}
public boolean isJava16Libraries() throws IllegalStateException {
return getJavaLibraryVersion().startsWith("1.6");
}

View File

@ -64,7 +64,7 @@ public final class ClassReader implements ClassConstants {
if (magic != MAGIC) {
throw new InvalidClassFileException(offset, "bad magic number: " + magic);
}
if (majorVersion < 45 || majorVersion > 50) {
if (majorVersion < 45 || majorVersion > 51) {
throw new InvalidClassFileException(offset, "unknown class file version: " + majorVersion + "." + minorVersion);
}