From c5c4799b35c30a2b6bd8a263b8b6c706e8399c5d Mon Sep 17 00:00:00 2001 From: Stephan Gocht Date: Fri, 20 Nov 2015 21:19:41 +0100 Subject: [PATCH] Added minimalistic implementation of an exceptio analyisis. (Not fully functional yet.) --- .../exceptionanalysis/ExceptionAnalysis.java | 57 +++++++++ .../ExceptionFlowSolver.java | 63 +++++++++ .../ExceptionToBitvectorTransformer.java | 88 +++++++++++++ .../ExceptionTransferFunctionProvider.java | 97 ++++++++++++++ .../IntraproceduralResult.java | 81 ++++++++++++ .../exceptionanalysis/package-info.java | 2 + .../graph/impl/SelfLoopAddedEdgeManager.java | 120 ++++++++++++++++++ .../util/graph/impl/SelfLoopAddedGraph.java | 30 +++++ 8 files changed, 538 insertions(+) create mode 100644 com.ibm.wala.core/src/com/ibm/wala/analysis/exceptionanalysis/ExceptionAnalysis.java create mode 100644 com.ibm.wala.core/src/com/ibm/wala/analysis/exceptionanalysis/ExceptionFlowSolver.java create mode 100644 com.ibm.wala.core/src/com/ibm/wala/analysis/exceptionanalysis/ExceptionToBitvectorTransformer.java create mode 100644 com.ibm.wala.core/src/com/ibm/wala/analysis/exceptionanalysis/ExceptionTransferFunctionProvider.java create mode 100644 com.ibm.wala.core/src/com/ibm/wala/analysis/exceptionanalysis/IntraproceduralResult.java create mode 100644 com.ibm.wala.core/src/com/ibm/wala/analysis/exceptionanalysis/package-info.java create mode 100644 com.ibm.wala.util/src/com/ibm/wala/util/graph/impl/SelfLoopAddedEdgeManager.java create mode 100644 com.ibm.wala.util/src/com/ibm/wala/util/graph/impl/SelfLoopAddedGraph.java diff --git a/com.ibm.wala.core/src/com/ibm/wala/analysis/exceptionanalysis/ExceptionAnalysis.java b/com.ibm.wala.core/src/com/ibm/wala/analysis/exceptionanalysis/ExceptionAnalysis.java new file mode 100644 index 000000000..e247b936b --- /dev/null +++ b/com.ibm.wala.core/src/com/ibm/wala/analysis/exceptionanalysis/ExceptionAnalysis.java @@ -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 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 graph = new SelfLoopAddedGraph<>(new InvertedGraph(callgraph)); + BitVectorFramework 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 getCGNodeExceptions(CGNode node){ + BitVectorVariable nodeResult = solver.getIn(node); + if (nodeResult != null) { + return transformer.computeExceptions(nodeResult); + } else { + return null; + } + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/analysis/exceptionanalysis/ExceptionFlowSolver.java b/com.ibm.wala.core/src/com/ibm/wala/analysis/exceptionanalysis/ExceptionFlowSolver.java new file mode 100644 index 000000000..a2a3677fe --- /dev/null +++ b/com.ibm.wala.core/src/com/ibm/wala/analysis/exceptionanalysis/ExceptionFlowSolver.java @@ -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 { + + private IntraproceduralResult intraResult; + private ExceptionToBitvectorTransformer transformer; + + public ExceptionFlowSolver(IKilldallFramework 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 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; + } + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/analysis/exceptionanalysis/ExceptionToBitvectorTransformer.java b/com.ibm.wala.core/src/com/ibm/wala/analysis/exceptionanalysis/ExceptionToBitvectorTransformer.java new file mode 100644 index 000000000..e1702ec1e --- /dev/null +++ b/com.ibm.wala.core/src/com/ibm/wala/analysis/exceptionanalysis/ExceptionToBitvectorTransformer.java @@ -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 includingExceptions; + private OrdinalSetMapping values; + + public OrdinalSetMapping getValues() { + return values; + } + + public ExceptionToBitvectorTransformer(Set exceptions) { + includingExceptions = new HashMap(); + createValues(exceptions); + for (TypeReference exception : exceptions) { + BitVector bv = new BitVector(values.getSize()); + bv.set(values.getMappedIndex(exception)); + includingExceptions.put(exception, bv); + } + } + + public ExceptionToBitvectorTransformer(Set exceptions, ClassHierarchy cha) { + // TODO + throw new UnsupportedOperationException(); + } + + private void createValues(Set exceptions) { + TypeReference[] exceptionsArray = new TypeReference[exceptions.size()]; + exceptions.toArray(exceptionsArray); + values = new ObjectArrayMapping(exceptionsArray); + } + + public BitVector computeBitVector(Set 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 computeExceptions(BitVector bitVector) { + assert bitVector.length() == values.getSize(); + Set result = new HashSet<>(); + for (int i = 0; i < bitVector.length(); i++) { + if (bitVector.get(i)){ + result.add(values.getMappedObject(i)); + } + } + return result; + } + + public Set computeExceptions(BitVectorVariable bitVector) { + Set result = new HashSet<>(); + for (int i = 0; i < values.getSize(); i++) { + if (bitVector.get(i)){ + result.add(values.getMappedObject(i)); + } + } + return result; + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/analysis/exceptionanalysis/ExceptionTransferFunctionProvider.java b/com.ibm.wala.core/src/com/ibm/wala/analysis/exceptionanalysis/ExceptionTransferFunctionProvider.java new file mode 100644 index 000000000..ef3e81627 --- /dev/null +++ b/com.ibm.wala.core/src/com/ibm/wala/analysis/exceptionanalysis/ExceptionTransferFunctionProvider.java @@ -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 { + 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 getMeetOperator() { + return BitVectorUnion.instance(); + } + + @Override + public UnaryOperator getNodeTransferFunction(CGNode node) { + throw new UnsupportedOperationException(); + } + + @Override + public UnaryOperator 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 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(); + } + } + } + +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/analysis/exceptionanalysis/IntraproceduralResult.java b/com.ibm.wala.core/src/com/ibm/wala/analysis/exceptionanalysis/IntraproceduralResult.java new file mode 100644 index 000000000..3a84a74b6 --- /dev/null +++ b/com.ibm.wala.core/src/com/ibm/wala/analysis/exceptionanalysis/IntraproceduralResult.java @@ -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 exceptions; + private Map> intraproceduralExceptions; + private CallGraph callGraph; + + public IntraproceduralResult(CallGraph cg) { + this.callGraph = cg; + intraproceduralExceptions = new HashMap>(); + exceptions = new HashSet<>(); + compute(); + } + + private void compute() { + for (CGNode node : callGraph) { + intraproceduralExceptions.put(node, new HashSet()); + + 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 exceptions :intraproceduralExceptions.values()) { + this.exceptions.addAll(exceptions); + } + } + + public Set getFilteredExceptions(CGNode node, CallSiteReference callsite) { + assert (node.getIR().getInstructions()[callsite.getProgramCounter()] instanceof SSAInvokeInstruction); + return Collections.emptySet(); + } + + public Set 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 result = intraproceduralExceptions.get(node); + if (result == null) { + throw new RuntimeException("Internal Error: No result for the given node."); + } + return result; + } + + public Set getExceptions() { + return exceptions; + } +} diff --git a/com.ibm.wala.core/src/com/ibm/wala/analysis/exceptionanalysis/package-info.java b/com.ibm.wala.core/src/com/ibm/wala/analysis/exceptionanalysis/package-info.java new file mode 100644 index 000000000..3a55eac45 --- /dev/null +++ b/com.ibm.wala.core/src/com/ibm/wala/analysis/exceptionanalysis/package-info.java @@ -0,0 +1,2 @@ + +package com.ibm.wala.analysis.exceptionanalysis; \ No newline at end of file diff --git a/com.ibm.wala.util/src/com/ibm/wala/util/graph/impl/SelfLoopAddedEdgeManager.java b/com.ibm.wala.util/src/com/ibm/wala/util/graph/impl/SelfLoopAddedEdgeManager.java new file mode 100644 index 000000000..7324af743 --- /dev/null +++ b/com.ibm.wala.util/src/com/ibm/wala/util/graph/impl/SelfLoopAddedEdgeManager.java @@ -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 implements EdgeManager { + private class PrependItterator implements Iterator{ + private boolean usedFirst = false; + private Iterator original; + private T first; + + public PrependItterator(Iterator 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 original; + + public SelfLoopAddedEdgeManager(EdgeManager original) { + if (original == null) { + throw new IllegalArgumentException("original is null"); + } + this.original = original; + } + + @Override + public Iterator 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 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); + } + } +} \ No newline at end of file diff --git a/com.ibm.wala.util/src/com/ibm/wala/util/graph/impl/SelfLoopAddedGraph.java b/com.ibm.wala.util/src/com/ibm/wala/util/graph/impl/SelfLoopAddedGraph.java new file mode 100644 index 000000000..acf9f9bfb --- /dev/null +++ b/com.ibm.wala.util/src/com/ibm/wala/util/graph/impl/SelfLoopAddedGraph.java @@ -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 extends AbstractGraph { + + final private NodeManager nodes; + + @Override + protected NodeManager getNodeManager() { + return nodes; + } + + final private EdgeManager edges; + + @Override + protected EdgeManager getEdgeManager() { + return edges; + } + + public SelfLoopAddedGraph(Graph G) { + nodes = G; + edges = new SelfLoopAddedEdgeManager(G); + } + +} +