Documentation and Refactoring.

This commit is contained in:
Stephan Gocht 2015-12-20 19:34:40 +01:00
parent 467707701f
commit c3b7f9ffb3
6 changed files with 102 additions and 386 deletions

View File

@ -10,42 +10,30 @@
*******************************************************************************/
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;
public class Exception2BitvectorTransformer {
private OrdinalSetMapping<TypeReference> values;
public OrdinalSetMapping<TypeReference> getValues() {
return values;
}
public ExceptionToBitvectorTransformer(Set<TypeReference> exceptions) {
includingExceptions = new HashMap<TypeReference, BitVector>();
public Exception2BitvectorTransformer(Set<TypeReference> exceptions) {
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);
@ -55,12 +43,12 @@ public class ExceptionToBitvectorTransformer {
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 ");
// }
if (includingExceptions.containsKey(exception)) {
result.or(includingExceptions.get(exception));
int pos = values.getMappedIndex(exception);
if (pos != -1) {
result.set(pos);
} else {
throw new IllegalArgumentException("Got exception I don't know about,"
+ "make sure only to use exceptions given to the constructor ");
}
}
return result;

View File

@ -24,13 +24,13 @@ import com.ibm.wala.ipa.cha.ClassHierarchy;
import com.ibm.wala.ssa.SSAInstruction;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.util.CancelException;
import com.ibm.wala.util.MonitorUtil.IProgressMonitor;
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;
private Exception2BitvectorTransformer transformer;
public ExceptionAnalysis(CallGraph callgraph, PointerAnalysis<InstanceKey> pointerAnalysis, ClassHierarchy cha) {
this(callgraph, pointerAnalysis, cha, null);
@ -38,16 +38,16 @@ public class ExceptionAnalysis {
public ExceptionAnalysis(CallGraph callgraph, PointerAnalysis<InstanceKey> pointerAnalysis, ClassHierarchy cha,
InterproceduralExceptionFilter<SSAInstruction> filter) {
IntraproceduralResult intraResult = new IntraproceduralResult(callgraph, pointerAnalysis, cha, filter);
transformer = new ExceptionToBitvectorTransformer(intraResult.getExceptions());
CGIntraproceduralExceptionAnalysis intraResult = new CGIntraproceduralExceptionAnalysis(callgraph, pointerAnalysis, cha, filter);
transformer = new Exception2BitvectorTransformer(intraResult.getExceptions());
ExceptionTransferFunctionProvider transferFunctionProvider = new ExceptionTransferFunctionProvider(intraResult, callgraph,
transformer);
Graph<CGNode> graph = new SelfLoopAddedGraph<>(new InvertedGraph<CGNode>(callgraph));
Graph<CGNode> graph = new InvertedGraph<CGNode>(callgraph);
BitVectorFramework<CGNode, TypeReference> problem = new BitVectorFramework<>(graph, transferFunctionProvider,
transformer.getValues());
solver = new ExceptionFlowSolver(problem, intraResult, transformer);
solver = new InitializedBitVectorSolver(problem);
solver.initForFirstSolve();
}
@ -55,13 +55,17 @@ public class ExceptionAnalysis {
try {
solver.solve(null);
} catch (CancelException e) {
// TODO Auto-generated catch block
e.printStackTrace();
throw new RuntimeException("Internal Error: Got Cancel Exception, "
+ "but didn't use Progressmonitor!", e);
}
}
public void solve(IProgressMonitor monitor) throws CancelException {
solver.solve(monitor);
}
public Set<TypeReference> getCGNodeExceptions(CGNode node) {
BitVectorVariable nodeResult = solver.getIn(node);
BitVectorVariable nodeResult = solver.getOut(node);
if (nodeResult != null) {
return transformer.computeExceptions(nodeResult);
} else {

View File

@ -1,63 +0,0 @@
/*******************************************************************************
* 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

@ -11,26 +11,29 @@
package com.ibm.wala.analysis.exceptionanalysis;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Set;
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.BitVectorUnionVector;
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.types.TypeReference;
import com.ibm.wala.util.intset.BitVector;
public class ExceptionTransferFunctionProvider implements ITransferFunctionProvider<CGNode, BitVectorVariable> {
private ExceptionToBitvectorTransformer transformer;
private Exception2BitvectorTransformer transformer;
private CallGraph cg;
private IntraproceduralResult intraResult;
private CGIntraproceduralExceptionAnalysis intraResult;
public ExceptionTransferFunctionProvider(IntraproceduralResult intraResult, CallGraph cg,
ExceptionToBitvectorTransformer transformer) {
public ExceptionTransferFunctionProvider(CGIntraproceduralExceptionAnalysis intraResult, CallGraph cg,
Exception2BitvectorTransformer transformer) {
this.cg = cg;
this.transformer = transformer;
this.intraResult = intraResult;
@ -38,7 +41,7 @@ public class ExceptionTransferFunctionProvider implements ITransferFunctionProvi
@Override
public boolean hasNodeTransferFunctions() {
return false;
return true;
}
@Override
@ -53,52 +56,40 @@ public class ExceptionTransferFunctionProvider implements ITransferFunctionProvi
@Override
public UnaryOperator<BitVectorVariable> getNodeTransferFunction(CGNode node) {
throw new UnsupportedOperationException();
Set<TypeReference> exceptions = intraResult.getAnalysis(node).getExceptions();
BitVector bitVector = transformer.computeBitVector(exceptions);
return new BitVectorUnionVector(bitVector);
}
@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
{
CGNode tmp = src;
src = dst;
dst = tmp;
public UnaryOperator<BitVectorVariable> getEdgeTransferFunction(CGNode dst, CGNode src) {
/*
* Note, that dst and src are swapped. For the data-flow-analysis we use
* called -> caller, but for the call graph we need caller -> called.
*/
Iterator<CallSiteReference> callsites = cg.getPossibleSites(src, dst);
BitVector filtered = new BitVector(transformer.getValues().getSize());
if (callsites.hasNext()) {
CallSiteReference callsite = callsites.next();
Iterator<CallSiteReference> callsites = cg.getPossibleSites(src, dst);
BitVector filtered = new BitVector(transformer.getValues().getSize());
if (callsites.hasNext()) {
CallSiteReference callsite = callsites.next();
filtered = transformer.computeBitVector(intraResult.getCaughtExceptions(src, callsite));
while (callsites.hasNext()) {
callsite = callsites.next();
BitVector bv = transformer.computeBitVector(intraResult.getCaughtExceptions(src, callsite));
filtered.and(bv);
}
return new BitVectorMinusVector(filtered);
} else {
return BitVectorIdentity.instance();
Set<TypeReference> caught = new LinkedHashSet<>();
caught.addAll(intraResult.getAnalysis(src).getCaughtExceptions(callsite));
while (callsites.hasNext()) {
callsite = callsites.next();
caught.retainAll(intraResult.getAnalysis(src).getCaughtExceptions(callsite));
}
filtered = transformer.computeBitVector(caught);
return new BitVectorMinusVector(filtered);
} else {
// This case should not happen, as we should only get src, dst pairs,
// which represent an edge in the call graph. For each edge in the call
// graph should be at least one call site.
throw new RuntimeException("Internal Error: Got call graph edge without call site.");
}
}
}

View File

@ -0,0 +1,44 @@
/*******************************************************************************
* 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 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.util.intset.BitVector;
public class InitializedBitVectorSolver extends BitVectorSolver<CGNode> {
public InitializedBitVectorSolver(IKilldallFramework<CGNode, BitVectorVariable> problem) {
super(problem);
}
@Override
protected BitVectorVariable makeNodeVariable(CGNode n, boolean IN) {
return newBV();
}
@Override
protected BitVectorVariable makeEdgeVariable(CGNode src, CGNode dst) {
return newBV();
}
private BitVectorVariable newBV(){
/*
* 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

@ -1,248 +0,0 @@
/*******************************************************************************
* 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.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import com.ibm.wala.classLoader.CallSiteReference;
import com.ibm.wala.classLoader.IClass;
import com.ibm.wala.ipa.callgraph.CGNode;
import com.ibm.wala.ipa.callgraph.CallGraph;
import com.ibm.wala.ipa.callgraph.propagation.InstanceKey;
import com.ibm.wala.ipa.callgraph.propagation.PointerAnalysis;
import com.ibm.wala.ipa.callgraph.propagation.PointerKey;
import com.ibm.wala.ipa.cfg.exceptionpruning.FilteredException;
import com.ibm.wala.ipa.cfg.exceptionpruning.interprocedural.InterproceduralExceptionFilter;
import com.ibm.wala.ipa.cha.ClassHierarchy;
import com.ibm.wala.ssa.IR;
import com.ibm.wala.ssa.ISSABasicBlock;
import com.ibm.wala.ssa.SSAInstruction;
import com.ibm.wala.ssa.SSAInstruction.Visitor;
import com.ibm.wala.ssa.SSAInvokeInstruction;
import com.ibm.wala.ssa.SSAThrowInstruction;
import com.ibm.wala.types.TypeReference;
import com.ibm.wala.util.intset.IntIterator;
import com.ibm.wala.util.intset.IntSet;
public class IntraproceduralResult {
private Set<TypeReference> exceptions;
private Map<CGNode, Set<TypeReference>> intraproceduralExceptions;
private CallGraph callGraph;
private PointerAnalysis<InstanceKey> pointerAnalysis;
private ClassHierarchy classHierachy;
private InterproceduralExceptionFilter<SSAInstruction> filter;
public IntraproceduralResult(CallGraph cg, PointerAnalysis<InstanceKey> pointerAnalysis, ClassHierarchy cha,
InterproceduralExceptionFilter<SSAInstruction> filter) {
this.callGraph = cg;
this.pointerAnalysis = pointerAnalysis;
this.classHierachy = cha;
this.filter = filter;
intraproceduralExceptions = new HashMap<>();
exceptions = new HashSet<>();
compute();
}
private void compute() {
for (final CGNode node : callGraph) {
intraproceduralExceptions.put(node, new HashSet<TypeReference>());
IR ir = node.getIR();
if (ir != null) {
for (ISSABasicBlock block : ir.getControlFlowGraph()) {
SSAInstruction throwingInstruction = getThrowingInstruction(block);
if (throwingInstruction != null) {
Set<TypeReference> thrownExceptions = collectThrownExceptions(node, throwingInstruction);
Set<TypeReference> caughtExceptions = collectCaughtExceptions(node, block);
Set<TypeReference> filteredExceptions = collectFilteredExceptions(node, throwingInstruction);
thrownExceptions.removeAll(filteredExceptions);
thrownExceptions.removeAll(caughtExceptions);
intraproceduralExceptions.get(node).addAll(thrownExceptions);
}
}
}
}
for (Set<TypeReference> exceptions : intraproceduralExceptions.values()) {
this.exceptions.addAll(exceptions);
}
}
private Set<TypeReference> collectFilteredExceptions(CGNode node, SSAInstruction throwingInstruction) {
if (filter != null) {
Set<TypeReference> filtered = new LinkedHashSet<>();
Collection<FilteredException> filters = filter.getFilter(node).filteredExceptions(throwingInstruction);
for (FilteredException filter : filters) {
if (filter.isSubclassFiltered()) {
for (IClass iclass : this.classHierachy.computeSubClasses(filter.getException())) {
filtered.add(iclass.getReference());
}
} else {
filtered.add(filter.getException());
}
}
return filtered;
} else {
return Collections.emptySet();
}
}
/**
* Returns a set of exceptions, which might be thrown from this instruction
* within this method.
*
* This does include exceptions dispatched by throw instructions, but not
* exceptions from method calls.
*
* @param node
* @param throwingInstruction
* @return a set of exceptions, which might be thrown from this instruction
* within this method
*/
private Set<TypeReference> collectThrownExceptions(final CGNode node, SSAInstruction throwingInstruction) {
final LinkedHashSet<TypeReference> result = new LinkedHashSet<>();
result.addAll(throwingInstruction.getExceptionTypes());
throwingInstruction.visit(new Visitor() {
@Override
public void visitThrow(SSAThrowInstruction instruction) {
addThrown(result, node, instruction);
}
});
return result;
}
/**
* Collects all exceptions, which could be dispatched by the throw
* instruction, by using the pointer analysis. Adds the collected exceptions
* to addTo.
*
* @param addTo
* set to add the result
* @param node
* node of the instruction
* @param instruction
* the throw instruction
*/
private void addThrown(LinkedHashSet<TypeReference> addTo, CGNode node, SSAThrowInstruction instruction) {
int exceptionVariable = instruction.getException();
PointerKey pointerKey = pointerAnalysis.getHeapModel().getPointerKeyForLocal(node, exceptionVariable);
Iterator it = pointerAnalysis.getHeapGraph().getSuccNodes(pointerKey);
while (it.hasNext()) {
Object next = it.next();
if (next instanceof InstanceKey) {
InstanceKey instanceKey = (InstanceKey) next;
IClass iclass = instanceKey.getConcreteType();
addTo.add(iclass.getReference());
} else {
throw new IllegalStateException("Internal error: Expected InstanceKey, got " + next.getClass().getName());
}
}
}
/**
*
* @param block
* @return an instruction which may throw exceptions, or null if this block
* can't throw exceptions
*/
private SSAInstruction getThrowingInstruction(ISSABasicBlock block) {
SSAInstruction result = null;
if (block.getLastInstructionIndex() >= 0) {
SSAInstruction lastInstruction = block.getLastInstruction();
if (lastInstruction != null) {
result = lastInstruction;
}
}
return result;
}
/**
* @param node
* @param block
* @return a set of all exceptions which will be caught, if thrown by the
* given block.
*/
private Set<TypeReference> collectCaughtExceptions(CGNode node, ISSABasicBlock block) {
LinkedHashSet<TypeReference> result = new LinkedHashSet<TypeReference>();
List<ISSABasicBlock> exceptionalSuccessors = node.getIR().getControlFlowGraph().getExceptionalSuccessors(block);
for (ISSABasicBlock succ : exceptionalSuccessors) {
if (succ.isCatchBlock()) {
Iterator<TypeReference> it = succ.getCaughtExceptionTypes();
while (it.hasNext()) {
result.add(it.next());
}
}
}
Set<TypeReference> subClasses = new LinkedHashSet<>();
for (TypeReference caught : result) {
for (IClass iclass : this.classHierachy.computeSubClasses(caught)) {
subClasses.add(iclass.getReference());
}
}
result.addAll(subClasses);
return result;
}
public Set<TypeReference> getCaughtExceptions(CGNode node, CallSiteReference callsite) {
Set<TypeReference> result = new LinkedHashSet<>();
IntSet iindices = node.getIR().getCallInstructionIndices(callsite);
IntIterator it = iindices.intIterator();
while (it.hasNext()) {
int iindex = it.next();
SSAInstruction instruction = node.getIR().getInstructions()[iindex];
if (!((instruction instanceof SSAInvokeInstruction))) {
throw new IllegalArgumentException("The given callsite dose not correspond to an invoke instruction." + instruction);
}
ISSABasicBlock block = node.getIR().getBasicBlockForInstruction(instruction);
if (result.isEmpty()) {
result.addAll(collectCaughtExceptions(node, block));
} else {
result.retainAll(collectCaughtExceptions(node, block));
}
}
return result;
}
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;
}
}