Added minimalistic implementation of an exceptio analyisis. (Not fully

functional yet.)
This commit is contained in:
Stephan Gocht 2015-11-20 21:19:41 +01:00
parent 3acd97ebfb
commit c5c4799b35
8 changed files with 538 additions and 0 deletions

View File

@ -0,0 +1,57 @@
/*******************************************************************************
* Copyright (c) 2007 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.analysis.exceptionanalysis;
import java.util.Set;
import com.ibm.wala.dataflow.graph.BitVectorFramework;
import com.ibm.wala.dataflow.graph.BitVectorSolver;
import com.ibm.wala.fixpoint.BitVectorVariable;
import com.ibm.wala.ipa.callgraph.CGNode;
import com.ibm.wala.ipa.callgraph.CallGraph;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.util.CancelException;
import com.ibm.wala.util.graph.Graph;
import com.ibm.wala.util.graph.impl.InvertedGraph;
import com.ibm.wala.util.graph.impl.SelfLoopAddedGraph;
public class ExceptionAnalysis {
private BitVectorSolver<CGNode> solver;
private ExceptionToBitvectorTransformer transformer;
public ExceptionAnalysis(CallGraph callgraph){
IntraproceduralResult intraResult = new IntraproceduralResult(callgraph);
transformer = new ExceptionToBitvectorTransformer(intraResult.getExceptions());
ExceptionTransferFunctionProvider transferFunctionProvider = new ExceptionTransferFunctionProvider(intraResult, callgraph, transformer);
Graph<CGNode> graph = new SelfLoopAddedGraph<>(new InvertedGraph<CGNode>(callgraph));
BitVectorFramework<CGNode, TypeReference> problem = new BitVectorFramework<>(graph, transferFunctionProvider, transformer.getValues());
solver = new ExceptionFlowSolver(problem, intraResult, transformer);
solver.initForFirstSolve();
try {
solver.solve(null);
} catch (CancelException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
public Set<TypeReference> getCGNodeExceptions(CGNode node){
BitVectorVariable nodeResult = solver.getIn(node);
if (nodeResult != null) {
return transformer.computeExceptions(nodeResult);
} else {
return null;
}
}
}

View File

@ -0,0 +1,63 @@
/*******************************************************************************
* Copyright (c) 2007 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.analysis.exceptionanalysis;
import java.util.Set;
import com.ibm.wala.dataflow.graph.BitVectorSolver;
import com.ibm.wala.dataflow.graph.IKilldallFramework;
import com.ibm.wala.fixpoint.BitVectorVariable;
import com.ibm.wala.ipa.callgraph.CGNode;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.util.intset.BitVector;
public class ExceptionFlowSolver extends BitVectorSolver<CGNode> {
private IntraproceduralResult intraResult;
private ExceptionToBitvectorTransformer transformer;
public ExceptionFlowSolver(IKilldallFramework<CGNode, BitVectorVariable> problem, IntraproceduralResult intraResult,
ExceptionToBitvectorTransformer transformer) {
super(problem);
this.intraResult = intraResult;
this.transformer = transformer;
}
@Override
protected BitVectorVariable makeNodeVariable(CGNode n, boolean IN) {
BitVectorVariable result = new BitVectorVariable();
Set<TypeReference> exceptions = intraResult.getIntraproceduralExceptions(n);
BitVector bitVector = transformer.computeBitVector(exceptions);
result.addAll(bitVector);
return result;
}
@Override
protected BitVectorVariable makeEdgeVariable(CGNode src, CGNode dst) {
if (src.equals(dst)) {
/*
* Set edge variables of self loops to the value of the node, otherwise
* leafs will lose their information.
*/
return makeNodeVariable(src, true);
} else {
/*
* If we do not initialize BitVectorVariable, with a BitVector, it
* contains null, which may crash in combination with {@link
* BitVectorMinusVector} used in {@link ExceptionTransferFunction}
*/
BitVectorVariable result = new BitVectorVariable();
result.addAll(new BitVector());
return result;
}
}
}

View File

@ -0,0 +1,88 @@
/*******************************************************************************
* Copyright (c) 2007 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.analysis.exceptionanalysis;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import com.ibm.wala.fixpoint.BitVectorVariable;
import com.ibm.wala.ipa.cha.ClassHierarchy;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.util.collections.ObjectArrayMapping;
import com.ibm.wala.util.intset.BitVector;
import com.ibm.wala.util.intset.OrdinalSetMapping;
public class ExceptionToBitvectorTransformer {
private Map<TypeReference, BitVector> includingExceptions;
private OrdinalSetMapping<TypeReference> values;
public OrdinalSetMapping<TypeReference> getValues() {
return values;
}
public ExceptionToBitvectorTransformer(Set<TypeReference> exceptions) {
includingExceptions = new HashMap<TypeReference, BitVector>();
createValues(exceptions);
for (TypeReference exception : exceptions) {
BitVector bv = new BitVector(values.getSize());
bv.set(values.getMappedIndex(exception));
includingExceptions.put(exception, bv);
}
}
public ExceptionToBitvectorTransformer(Set<TypeReference> exceptions, ClassHierarchy cha) {
// TODO
throw new UnsupportedOperationException();
}
private void createValues(Set<TypeReference> exceptions) {
TypeReference[] exceptionsArray = new TypeReference[exceptions.size()];
exceptions.toArray(exceptionsArray);
values = new ObjectArrayMapping<TypeReference>(exceptionsArray);
}
public BitVector computeBitVector(Set<TypeReference> exceptions) {
BitVector result = new BitVector(values.getSize());
for (TypeReference exception : exceptions) {
if (!includingExceptions.containsKey(exception)) {
throw new IllegalArgumentException("Got exception I don't know about,"
+ "make sure only to use exceptions given to the constructor ");
}
result.or(includingExceptions.get(exception));
}
return result;
}
public Set<TypeReference> computeExceptions(BitVector bitVector) {
assert bitVector.length() == values.getSize();
Set<TypeReference> result = new HashSet<>();
for (int i = 0; i < bitVector.length(); i++) {
if (bitVector.get(i)){
result.add(values.getMappedObject(i));
}
}
return result;
}
public Set<TypeReference> computeExceptions(BitVectorVariable bitVector) {
Set<TypeReference> result = new HashSet<>();
for (int i = 0; i < values.getSize(); i++) {
if (bitVector.get(i)){
result.add(values.getMappedObject(i));
}
}
return result;
}
}

View File

@ -0,0 +1,97 @@
/*******************************************************************************
* Copyright (c) 2007 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.analysis.exceptionanalysis;
import java.util.Iterator;
import com.ibm.wala.classLoader.CallSiteReference;
import com.ibm.wala.dataflow.graph.AbstractMeetOperator;
import com.ibm.wala.dataflow.graph.BitVectorIdentity;
import com.ibm.wala.dataflow.graph.BitVectorMinusVector;
import com.ibm.wala.dataflow.graph.BitVectorUnion;
import com.ibm.wala.dataflow.graph.ITransferFunctionProvider;
import com.ibm.wala.fixpoint.BitVectorVariable;
import com.ibm.wala.fixpoint.UnaryOperator;
import com.ibm.wala.ipa.callgraph.CGNode;
import com.ibm.wala.ipa.callgraph.CallGraph;
import com.ibm.wala.util.intset.BitVector;
public class ExceptionTransferFunctionProvider implements ITransferFunctionProvider<CGNode, BitVectorVariable> {
private ExceptionToBitvectorTransformer transformer;
private CallGraph cg;
private IntraproceduralResult intraResult;
public ExceptionTransferFunctionProvider(IntraproceduralResult intraResult, CallGraph cg,
ExceptionToBitvectorTransformer transformer) {
this.cg = cg;
this.transformer = transformer;
this.intraResult = intraResult;
}
@Override
public boolean hasNodeTransferFunctions() {
return false;
}
@Override
public boolean hasEdgeTransferFunctions() {
return true;
}
@Override
public AbstractMeetOperator<BitVectorVariable> getMeetOperator() {
return BitVectorUnion.instance();
}
@Override
public UnaryOperator<BitVectorVariable> getNodeTransferFunction(CGNode node) {
throw new UnsupportedOperationException();
}
@Override
public UnaryOperator<BitVectorVariable> getEdgeTransferFunction(CGNode src, CGNode dst) {
// if (src.equals(dst)) {
// /*
// * To make use of start values for all nodes, self-loops were introduced
// * into the graph (Otherwise these values would get eliminated during
// * short circuit optimization.)
// *
// * If the method does not call itself, we would have no analysis result
// * for the self-loop edge. We can just return the identity function for
// * this cases.
// *
// * If the method does call itself, we could produce a more precise
// * transfer function as the method is catching its own exceptions, maybe.
// * However, the less precise transfer function we actually use, does not
// * result in a less precise result: There is an execution, that produces
// * the exceptions so they need to be included.
// */
// return BitVectorIdentity.instance();
// } else
{
Iterator<CallSiteReference> callsites = cg.getPossibleSites(src, dst);
BitVector filtered = new BitVector(transformer.getValues().getSize());
if (callsites.hasNext()) {
while (callsites.hasNext()) {
CallSiteReference callsite = callsites.next();
BitVector bv = transformer.computeBitVector(intraResult.getFilteredExceptions(src, callsite));
filtered.and(bv);
}
return new BitVectorMinusVector(filtered);
} else {
return BitVectorIdentity.instance();
}
}
}
}

View File

@ -0,0 +1,81 @@
/*******************************************************************************
* Copyright (c) 2007 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.analysis.exceptionanalysis;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import com.ibm.wala.classLoader.CallSiteReference;
import com.ibm.wala.ipa.callgraph.CGNode;
import com.ibm.wala.ipa.callgraph.CallGraph;
import com.ibm.wala.ssa.IR;
import com.ibm.wala.ssa.ISSABasicBlock;
import com.ibm.wala.ssa.SSAInstruction;
import com.ibm.wala.ssa.SSAInvokeInstruction;
import com.ibm.wala.types.TypeReference;
public class IntraproceduralResult {
private Set<TypeReference> exceptions;
private Map<CGNode, Set<TypeReference>> intraproceduralExceptions;
private CallGraph callGraph;
public IntraproceduralResult(CallGraph cg) {
this.callGraph = cg;
intraproceduralExceptions = new HashMap<CGNode, Set<TypeReference>>();
exceptions = new HashSet<>();
compute();
}
private void compute() {
for (CGNode node : callGraph) {
intraproceduralExceptions.put(node, new HashSet<TypeReference>());
IR ir = node.getIR();
if (ir != null) {
for (ISSABasicBlock block : ir.getControlFlowGraph()) {
if (block.getLastInstructionIndex() >= 0) {
SSAInstruction lastInstruction = block.getLastInstruction();
intraproceduralExceptions.get(node).addAll(lastInstruction.getExceptionTypes());
}
// TODO: Add Throw, Analyze catch
}
}
}
for (Set<TypeReference> exceptions :intraproceduralExceptions.values()) {
this.exceptions.addAll(exceptions);
}
}
public Set<TypeReference> getFilteredExceptions(CGNode node, CallSiteReference callsite) {
assert (node.getIR().getInstructions()[callsite.getProgramCounter()] instanceof SSAInvokeInstruction);
return Collections.emptySet();
}
public Set<TypeReference> getIntraproceduralExceptions(CGNode node) {
if (!callGraph.containsNode(node)) {
throw new IllegalArgumentException("The given CG node has to be part " + "of the call graph given during construction.");
}
Set<TypeReference> result = intraproceduralExceptions.get(node);
if (result == null) {
throw new RuntimeException("Internal Error: No result for the given node.");
}
return result;
}
public Set<TypeReference> getExceptions() {
return exceptions;
}
}

View File

@ -0,0 +1,2 @@
package com.ibm.wala.analysis.exceptionanalysis;

View File

@ -0,0 +1,120 @@
package com.ibm.wala.util.graph.impl;
import java.util.Iterator;
import com.ibm.wala.util.graph.EdgeManager;
public class SelfLoopAddedEdgeManager<T> implements EdgeManager<T> {
private class PrependItterator implements Iterator<T>{
private boolean usedFirst = false;
private Iterator<T> original;
private T first;
public PrependItterator(Iterator<T> original, T first) {
super();
this.original = original;
this.first = first;
}
@Override
public boolean hasNext() {
if (!usedFirst) {
return true;
} else {
return original.hasNext();
}
}
@Override
public T next() {
if (!usedFirst) {
T tmp = first;
first = null;
usedFirst = true;
return tmp;
} else {
return original.next();
}
}
}
private final EdgeManager<T> original;
public SelfLoopAddedEdgeManager(EdgeManager<T> original) {
if (original == null) {
throw new IllegalArgumentException("original is null");
}
this.original = original;
}
@Override
public Iterator<T> getPredNodes(T n) {
if (original.hasEdge(n, n)) {
return original.getPredNodes(n);
} else {
return new PrependItterator(original.getPredNodes(n), n);
}
}
@Override
public int getPredNodeCount(T n) {
if (original.hasEdge(n, n)) {
return original.getPredNodeCount(n);
} else {
return original.getPredNodeCount(n) + 1;
}
}
@Override
public Iterator<T> getSuccNodes(T n) {
if (original.hasEdge(n, n)) {
return original.getSuccNodes(n);
} else {
return new PrependItterator(original.getSuccNodes(n), n);
}
}
@Override
public int getSuccNodeCount(T n) {
if (original.hasEdge(n, n)) {
return original.getSuccNodeCount(n);
} else {
return original.getSuccNodeCount(n) + 1;
}
}
@Override
public void addEdge(T src, T dst) {
original.addEdge(src, dst);
}
@Override
public void removeEdge(T src, T dst) throws UnsupportedOperationException {
original.removeEdge(src, dst);
}
@Override
public void removeAllIncidentEdges(T node) throws UnsupportedOperationException {
original.removeAllIncidentEdges(node);
}
@Override
public void removeIncomingEdges(T node) throws UnsupportedOperationException {
original.removeIncomingEdges(node);
}
@Override
public void removeOutgoingEdges(T node) throws UnsupportedOperationException {
original.removeOutgoingEdges(node);
}
@Override
public boolean hasEdge(T src, T dst) {
if (src.equals(dst)) {
return true;
} else {
return original.hasEdge(src, dst);
}
}
}

View File

@ -0,0 +1,30 @@
package com.ibm.wala.util.graph.impl;
import com.ibm.wala.util.graph.AbstractGraph;
import com.ibm.wala.util.graph.EdgeManager;
import com.ibm.wala.util.graph.Graph;
import com.ibm.wala.util.graph.NodeManager;
public class SelfLoopAddedGraph <T> extends AbstractGraph<T> {
final private NodeManager<T> nodes;
@Override
protected NodeManager<T> getNodeManager() {
return nodes;
}
final private EdgeManager<T> edges;
@Override
protected EdgeManager<T> getEdgeManager() {
return edges;
}
public SelfLoopAddedGraph(Graph<T> G) {
nodes = G;
edges = new SelfLoopAddedEdgeManager<T>(G);
}
}