Added minimalistic implementation of an exceptio analyisis. (Not fully
functional yet.)
This commit is contained in:
parent
3acd97ebfb
commit
c5c4799b35
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,2 @@
|
|||
|
||||
package com.ibm.wala.analysis.exceptionanalysis;
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue