diff --git a/com.ibm.wala.core.testdata/src/dataflow/StaticDataflow.java b/com.ibm.wala.core.testdata/src/dataflow/StaticDataflow.java new file mode 100644 index 000000000..297bf9908 --- /dev/null +++ b/com.ibm.wala.core.testdata/src/dataflow/StaticDataflow.java @@ -0,0 +1,51 @@ +/******************************************************************************* + * Copyright (c) 2010 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 dataflow; + +/** + * test cases for dataflow analysis involving static fields. + */ +public class StaticDataflow { + + static int f; + + static int g; + + public static void test1() { + f = 3; + f = 3; + } + + public static void test2() { + f = 4; + g = 3; + if (f == 5) { + g = 2; + } else { + g = 7; + } + } + + public static void main(String[] args) { + testInterproc(); + } + + private static void testInterproc() { + f = 3; + m(); + g = 4; + m(); + } + + private static void m() { + f = 2; + } +} diff --git a/com.ibm.wala.core.tests/src/com/ibm/wala/examples/analysis/dataflow/BitVectorKillAll.java b/com.ibm.wala.core.tests/src/com/ibm/wala/examples/analysis/dataflow/BitVectorKillAll.java new file mode 100644 index 000000000..d6206bd92 --- /dev/null +++ b/com.ibm.wala.core.tests/src/com/ibm/wala/examples/analysis/dataflow/BitVectorKillAll.java @@ -0,0 +1,68 @@ +/******************************************************************************* + * Copyright (c) 2008 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.examples.analysis.dataflow; + +import com.ibm.wala.fixedpoint.impl.UnaryOperator; +import com.ibm.wala.fixpoint.BitVectorVariable; + +/** + * Just kills everything + */ +public class BitVectorKillAll extends UnaryOperator { + + private final static BitVectorKillAll SINGLETON = new BitVectorKillAll(); + + public static BitVectorKillAll instance() { + return SINGLETON; + } + + private BitVectorKillAll() { + } + + /* (non-Javadoc) + * @see com.ibm.wala.fixedpoint.impl.UnaryOperator#evaluate(com.ibm.wala.fixpoint.IVariable, com.ibm.wala.fixpoint.IVariable) + */ + @Override + public byte evaluate(BitVectorVariable lhs, BitVectorVariable rhs) { + BitVectorVariable empty = new BitVectorVariable(); + if (!lhs.sameValue(empty)) { + lhs.copyState(empty); + return CHANGED; + } else { + return NOT_CHANGED; + } + } + + /* (non-Javadoc) + * @see com.ibm.wala.fixedpoint.impl.AbstractOperator#equals(java.lang.Object) + */ + @Override + public boolean equals(Object o) { + return this == o; + } + + /* (non-Javadoc) + * @see com.ibm.wala.fixedpoint.impl.AbstractOperator#hashCode() + */ + @Override + public int hashCode() { + return 12423958; + } + + /* (non-Javadoc) + * @see com.ibm.wala.fixedpoint.impl.AbstractOperator#toString() + */ + @Override + public String toString() { + return "KillAll"; + } + +} diff --git a/com.ibm.wala.core.tests/src/com/ibm/wala/examples/analysis/dataflow/ContextInsensitiveReachingDefs.java b/com.ibm.wala.core.tests/src/com/ibm/wala/examples/analysis/dataflow/ContextInsensitiveReachingDefs.java new file mode 100644 index 000000000..d0f2b7c43 --- /dev/null +++ b/com.ibm.wala.core.tests/src/com/ibm/wala/examples/analysis/dataflow/ContextInsensitiveReachingDefs.java @@ -0,0 +1,173 @@ +/******************************************************************************* + * Copyright (c) 2008 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.examples.analysis.dataflow; + +import java.util.ArrayList; +import java.util.Map; + +import com.ibm.wala.classLoader.IField; +import com.ibm.wala.dataflow.graph.AbstractMeetOperator; +import com.ibm.wala.dataflow.graph.BitVectorFramework; +import com.ibm.wala.dataflow.graph.BitVectorIdentity; +import com.ibm.wala.dataflow.graph.BitVectorKillGen; +import com.ibm.wala.dataflow.graph.BitVectorSolver; +import com.ibm.wala.dataflow.graph.BitVectorUnion; +import com.ibm.wala.dataflow.graph.ITransferFunctionProvider; +import com.ibm.wala.fixedpoint.impl.UnaryOperator; +import com.ibm.wala.fixpoint.BitVectorVariable; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.cfg.BasicBlockInContext; +import com.ibm.wala.ipa.cfg.ExplodedInterproceduralCFG; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.ssa.IR; +import com.ibm.wala.ssa.SSAAbstractInvokeInstruction; +import com.ibm.wala.ssa.SSAInstruction; +import com.ibm.wala.ssa.SSAPutInstruction; +import com.ibm.wala.ssa.analysis.IExplodedBasicBlock; +import com.ibm.wala.util.CancelException; +import com.ibm.wala.util.collections.HashMapFactory; +import com.ibm.wala.util.collections.ObjectArrayMapping; +import com.ibm.wala.util.collections.Pair; +import com.ibm.wala.util.intset.BitVector; +import com.ibm.wala.util.intset.OrdinalSetMapping; + +/** + * Computes interprocedural reaching definitions for static fields in a context-insensitive manner. + */ +public class ContextInsensitiveReachingDefs { + + /** + * the exploded control-flow graph on which to compute the analysis + */ + private final ExplodedInterproceduralCFG icfg; + + /** + * maps method and instruction index of putstatic to more compact numbering for bitvectors + */ + private final OrdinalSetMapping> putInstrNumbering; + + private final IClassHierarchy cha; + + /** + * maps each static field to the numbers of the statements that define it + */ + private final Map staticField2DefStatements = HashMapFactory.make(); + + public ContextInsensitiveReachingDefs(ExplodedInterproceduralCFG icfg, IClassHierarchy cha) { + this.icfg = icfg; + this.cha = cha; + this.putInstrNumbering = numberPutStatics(); + } + + @SuppressWarnings("unchecked") + private OrdinalSetMapping> numberPutStatics() { + ArrayList> putInstrs = new ArrayList>(); + for (CGNode node : icfg.getCallGraph()) { + IR ir = node.getIR(); + if (ir == null) { + continue; + } + SSAInstruction[] instructions = ir.getInstructions(); + for (int i = 0; i < instructions.length; i++) { + SSAInstruction instruction = instructions[i]; + if (instruction instanceof SSAPutInstruction && ((SSAPutInstruction) instruction).isStatic()) { + SSAPutInstruction putInstr = (SSAPutInstruction) instruction; + int instrNum = putInstrs.size(); + putInstrs.add(Pair.make(node, i)); + IField field = cha.resolveField(putInstr.getDeclaredField()); + assert field != null; + BitVector bv = staticField2DefStatements.get(field); + if (bv == null) { + bv = new BitVector(); + staticField2DefStatements.put(field, bv); + } + bv.set(instrNum); + } + } + } + return new ObjectArrayMapping>(putInstrs.toArray(new Pair[putInstrs.size()])); + } + + private class TransferFunctions implements ITransferFunctionProvider, BitVectorVariable> { + + public AbstractMeetOperator getMeetOperator() { + // meet is union + return BitVectorUnion.instance(); + } + + public UnaryOperator getNodeTransferFunction(BasicBlockInContext node) { + IExplodedBasicBlock ebb = node.getDelegate(); + SSAInstruction instruction = ebb.getInstruction(); + int instructionIndex = ebb.getFirstInstructionIndex(); + CGNode cgNode = node.getNode(); + if (instruction instanceof SSAPutInstruction && ((SSAPutInstruction) instruction).isStatic()) { + // kill all defs of the same static field + final SSAPutInstruction putInstr = (SSAPutInstruction) instruction; + final IField field = cha.resolveField(putInstr.getDeclaredField()); + assert field != null; + BitVector kill = staticField2DefStatements.get(field); + BitVector gen = new BitVector(); + gen.set(putInstrNumbering.getMappedIndex(Pair.make(cgNode, instructionIndex))); + return new BitVectorKillGen(kill, gen); + } else { + // nothing defined + return BitVectorIdentity.instance(); + } + } + + public boolean hasEdgeTransferFunctions() { + return true; + } + + public boolean hasNodeTransferFunctions() { + return true; + } + + public UnaryOperator getEdgeTransferFunction(BasicBlockInContext src, + BasicBlockInContext dst) { + if (isCallToReturnEdge(src,dst)) { + return BitVectorKillAll.instance(); + } else { + return BitVectorIdentity.instance(); + } + } + + private boolean isCallToReturnEdge(BasicBlockInContext src, BasicBlockInContext dst) { + SSAInstruction srcInst = src.getDelegate().getInstruction(); + return srcInst instanceof SSAAbstractInvokeInstruction && src.getNode().equals(dst.getNode()); + } + + } + + public BitVectorSolver> analyze() { + BitVectorFramework, Pair> framework = new BitVectorFramework, Pair>( + icfg, new TransferFunctions(), putInstrNumbering); + BitVectorSolver> solver = new BitVectorSolver>( + framework); + try { + solver.solve(null); + } catch (CancelException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + for (BasicBlockInContext ebb : icfg) { + System.out.println(ebb); + System.out.println(ebb.getDelegate().getInstruction()); + System.out.println(solver.getIn(ebb)); + System.out.println(solver.getOut(ebb)); + } + return solver; + } + + public Pair getNodeAndInstrForNumber(int num) { + return putInstrNumbering.getMappedObject(num); + } +} diff --git a/com.ibm.wala.core.tests/src/com/ibm/wala/examples/analysis/dataflow/ContextSensitiveReachingDefs.java b/com.ibm.wala.core.tests/src/com/ibm/wala/examples/analysis/dataflow/ContextSensitiveReachingDefs.java new file mode 100644 index 000000000..e6627ae1f --- /dev/null +++ b/com.ibm.wala.core.tests/src/com/ibm/wala/examples/analysis/dataflow/ContextSensitiveReachingDefs.java @@ -0,0 +1,229 @@ +/******************************************************************************* + * Copyright (c) 2008 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.examples.analysis.dataflow; + +import java.util.Collection; + +import com.ibm.wala.classLoader.IField; +import com.ibm.wala.dataflow.IFDS.ICFGSupergraph; +import com.ibm.wala.dataflow.IFDS.IFlowFunction; +import com.ibm.wala.dataflow.IFDS.IMergeFunction; +import com.ibm.wala.dataflow.IFDS.IPartiallyBalancedFlowFunctions; +import com.ibm.wala.dataflow.IFDS.ISupergraph; +import com.ibm.wala.dataflow.IFDS.IUnaryFlowFunction; +import com.ibm.wala.dataflow.IFDS.IdentityFlowFunction; +import com.ibm.wala.dataflow.IFDS.KillEverything; +import com.ibm.wala.dataflow.IFDS.PartiallyBalancedTabulationProblem; +import com.ibm.wala.dataflow.IFDS.PartiallyBalancedTabulationSolver; +import com.ibm.wala.dataflow.IFDS.PathEdge; +import com.ibm.wala.dataflow.IFDS.TabulationDomain; +import com.ibm.wala.dataflow.IFDS.TabulationResult; +import com.ibm.wala.dataflow.IFDS.TabulationSolver; +import com.ibm.wala.ipa.callgraph.AnalysisCache; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.CallGraph; +import com.ibm.wala.ipa.cfg.BasicBlockInContext; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.ssa.SSAInstruction; +import com.ibm.wala.ssa.SSAPutInstruction; +import com.ibm.wala.ssa.analysis.IExplodedBasicBlock; +import com.ibm.wala.util.CancelException; +import com.ibm.wala.util.collections.HashSetFactory; +import com.ibm.wala.util.collections.Pair; +import com.ibm.wala.util.intset.IntSet; +import com.ibm.wala.util.intset.MutableMapping; +import com.ibm.wala.util.intset.MutableSparseIntSet; + +/** + * Computes interprocedural reaching definitions for static fields in a context-sensitive manner via {@link TabulationSolver + * tabulation}. + */ +public class ContextSensitiveReachingDefs { + + private final IClassHierarchy cha; + + private final ISupergraph, CGNode> supergraph; + + private ReachingDefsDomain domain = new ReachingDefsDomain(); + + public ContextSensitiveReachingDefs(CallGraph cg, AnalysisCache cache) { + this.cha = cg.getClassHierarchy(); + this.supergraph = ICFGSupergraph.make(cg, cache); + } + + private class ReachingDefsDomain extends MutableMapping> implements + TabulationDomain, BasicBlockInContext> { + + public boolean hasPriorityOver(PathEdge> p1, + PathEdge> p2) { + // don't worry about worklist priorities + return false; + } + + } + + private class ReachingDefsFlowFunctions implements IPartiallyBalancedFlowFunctions> { + + private final ReachingDefsDomain domain; + + protected ReachingDefsFlowFunctions(ReachingDefsDomain domain) { + this.domain = domain; + } + + public IFlowFunction getUnbalancedReturnFlowFunction(BasicBlockInContext src, + BasicBlockInContext dest) { + return IdentityFlowFunction.identity(); + } + + public IUnaryFlowFunction getCallFlowFunction(BasicBlockInContext src, + BasicBlockInContext dest, BasicBlockInContext ret) { + // just send the fact into the callee + return IdentityFlowFunction.identity(); + } + + public IUnaryFlowFunction getCallNoneToReturnFlowFunction(BasicBlockInContext src, + BasicBlockInContext dest) { + // if we're missing callees, just give up and kill everything + return KillEverything.singleton(); + } + + public IUnaryFlowFunction getCallToReturnFlowFunction(BasicBlockInContext src, + BasicBlockInContext dest) { + // kill everything; surviving facts should flow out of the callee + return KillEverything.singleton(); + } + + public IUnaryFlowFunction getNormalFlowFunction(final BasicBlockInContext src, + BasicBlockInContext dest) { + final IExplodedBasicBlock ebb = src.getDelegate(); + SSAInstruction instruction = ebb.getInstruction(); + if (instruction instanceof SSAPutInstruction) { + final SSAPutInstruction putInstr = (SSAPutInstruction) instruction; + if (putInstr.isStatic()) { + return new IUnaryFlowFunction() { + + public IntSet getTargets(int d1) { + int factNum = domain.getMappedIndex(Pair.make(src.getNode(), ebb.getFirstInstructionIndex())); + IField staticField = cha.resolveField(putInstr.getDeclaredField()); + assert staticField != null; + assert factNum != -1; + MutableSparseIntSet result = MutableSparseIntSet.makeEmpty(); + result.add(factNum); + if (d1 != factNum) { + Pair otherPutInstrAndNode = domain.getMappedObject(d1); + // if it writes the same field, kill it + SSAPutInstruction otherPutInstr = (SSAPutInstruction) otherPutInstrAndNode.fst.getIR().getInstructions()[otherPutInstrAndNode.snd]; + IField otherStaticField = cha.resolveField(otherPutInstr.getDeclaredField()); + if (!staticField.equals(otherStaticField)) { + result.add(d1); + } + } + return result; + } + + public String toString() { + return "Reaching Defs Normal Flow"; + } + }; + } + } + return IdentityFlowFunction.identity(); + } + + public IFlowFunction getReturnFlowFunction(BasicBlockInContext call, + BasicBlockInContext src, BasicBlockInContext dest) { + return IdentityFlowFunction.identity(); + } + + } + + private class ReachingDefsProblem implements + PartiallyBalancedTabulationProblem, CGNode, Pair> { + + private ReachingDefsFlowFunctions flowFunctions = new ReachingDefsFlowFunctions(domain); + + private Collection>> initialSeeds = collectInitialSeeds(); + + /** + * we use the entry block of the CGNode as the fake entry when propagating from callee to caller with unbalanced parens + */ + public BasicBlockInContext getFakeEntry(BasicBlockInContext node) { + final CGNode cgNode = node.getNode(); + return getFakeEntry(cgNode); + } + + /** + * we use the entry block of the CGNode as the fake entry when propagating from callee to caller with unbalanced parens + */ + private BasicBlockInContext getFakeEntry(final CGNode cgNode) { + BasicBlockInContext[] entriesForProcedure = supergraph.getEntriesForProcedure(cgNode); + assert entriesForProcedure.length == 1; + return entriesForProcedure[0]; + } + + private Collection>> collectInitialSeeds() { + Collection>> result = HashSetFactory.make(); + for (BasicBlockInContext bb : supergraph) { + IExplodedBasicBlock ebb = bb.getDelegate(); + SSAInstruction instruction = ebb.getInstruction(); + if (instruction instanceof SSAPutInstruction) { + SSAPutInstruction putInstr = (SSAPutInstruction) instruction; + if (putInstr.isStatic()) { + final CGNode cgNode = bb.getNode(); + Pair fact = Pair.make(cgNode, ebb.getFirstInstructionIndex()); + int factNum = domain.add(fact); + BasicBlockInContext fakeEntry = getFakeEntry(cgNode); + result.add(PathEdge.createPathEdge(fakeEntry, factNum, bb, factNum)); + + } + } + } + return result; + } + + public IPartiallyBalancedFlowFunctions> getFunctionMap() { + return flowFunctions; + } + + public TabulationDomain, BasicBlockInContext> getDomain() { + return domain; + } + + public IMergeFunction getMergeFunction() { + return null; + } + + public ISupergraph, CGNode> getSupergraph() { + return supergraph; + } + + public Collection>> initialSeeds() { + return initialSeeds; + } + + } + + public TabulationResult, CGNode, Pair> analyze() throws CancelException { + PartiallyBalancedTabulationSolver, CGNode, Pair> solver = PartiallyBalancedTabulationSolver + .createPartiallyBalancedTabulationSolver(new ReachingDefsProblem(), null); + TabulationResult, CGNode, Pair> result = solver.solve(); + return result; + + } + + public ISupergraph, CGNode> getSupergraph() { + return supergraph; + } + + public TabulationDomain, BasicBlockInContext> getDomain() { + return domain; + } +} diff --git a/com.ibm.wala.core.tests/src/com/ibm/wala/examples/analysis/dataflow/DataflowTest.java b/com.ibm.wala.core.tests/src/com/ibm/wala/examples/analysis/dataflow/DataflowTest.java new file mode 100644 index 000000000..0c8a7598a --- /dev/null +++ b/com.ibm.wala.core.tests/src/com/ibm/wala/examples/analysis/dataflow/DataflowTest.java @@ -0,0 +1,186 @@ +/******************************************************************************* + * Copyright (c) 2008 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.examples.analysis.dataflow; + +import junit.framework.Assert; + +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.Test; + +import com.ibm.wala.classLoader.IMethod; +import com.ibm.wala.core.tests.callGraph.CallGraphTestUtil; +import com.ibm.wala.core.tests.util.TestConstants; +import com.ibm.wala.core.tests.util.WalaTestCase; +import com.ibm.wala.dataflow.IFDS.ISupergraph; +import com.ibm.wala.dataflow.IFDS.TabulationResult; +import com.ibm.wala.dataflow.graph.BitVectorSolver; +import com.ibm.wala.ipa.callgraph.AnalysisCache; +import com.ibm.wala.ipa.callgraph.AnalysisOptions; +import com.ibm.wala.ipa.callgraph.AnalysisScope; +import com.ibm.wala.ipa.callgraph.CGNode; +import com.ibm.wala.ipa.callgraph.CallGraph; +import com.ibm.wala.ipa.callgraph.CallGraphBuilder; +import com.ibm.wala.ipa.callgraph.CallGraphBuilderCancelException; +import com.ibm.wala.ipa.callgraph.Entrypoint; +import com.ibm.wala.ipa.callgraph.impl.Util; +import com.ibm.wala.ipa.cfg.BasicBlockInContext; +import com.ibm.wala.ipa.cfg.ExplodedInterproceduralCFG; +import com.ibm.wala.ipa.cha.ClassHierarchy; +import com.ibm.wala.ipa.cha.ClassHierarchyException; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.ssa.IR; +import com.ibm.wala.ssa.analysis.ExplodedControlFlowGraph; +import com.ibm.wala.ssa.analysis.IExplodedBasicBlock; +import com.ibm.wala.types.ClassLoaderReference; +import com.ibm.wala.types.MethodReference; +import com.ibm.wala.util.CancelException; +import com.ibm.wala.util.collections.Pair; +import com.ibm.wala.util.config.AnalysisScopeReader; +import com.ibm.wala.util.intset.IntIterator; +import com.ibm.wala.util.intset.IntSet; +import com.ibm.wala.util.io.FileProvider; + +/** + * Tests of various flow analysis engines. + */ +public class DataflowTest extends WalaTestCase { + + private static AnalysisScope scope; + + private static IClassHierarchy cha; + + @BeforeClass + public static void beforeClass() throws Exception { + + scope = AnalysisScopeReader.readJavaScope(TestConstants.WALA_TESTDATA, + FileProvider.getFile("J2SEClassHierarchyExclusions.txt"), DataflowTest.class.getClassLoader()); + + try { + cha = ClassHierarchy.make(scope); + } catch (ClassHierarchyException e) { + throw new Exception(); + } + } + + /* + * (non-Javadoc) + * + * @see junit.framework.TestCase#tearDown() + */ + @AfterClass + public static void afterClass() throws Exception { + scope = null; + cha = null; + } + + @Test + public void testIntraproc1() { + AnalysisCache cache = new AnalysisCache(); + final MethodReference ref = MethodReference.findOrCreate(ClassLoaderReference.Application, "Ldataflow/StaticDataflow", "test1", + "()V"); + IMethod method = cha.resolveMethod(ref); + IR ir = cache.getIR(method); + ExplodedControlFlowGraph ecfg = ExplodedControlFlowGraph.make(ir); + IntraprocReachingDefs reachingDefs = new IntraprocReachingDefs(ecfg, cha); + BitVectorSolver solver = reachingDefs.analyze(); + for (IExplodedBasicBlock ebb : ecfg) { + if (ebb.getNumber() == 4) { + IntSet out = solver.getOut(ebb).getValue(); + Assert.assertEquals(1, out.size()); + Assert.assertTrue(out.contains(1)); + } + } + } + + @Test + public void testIntraproc2() { + AnalysisCache cache = new AnalysisCache(); + final MethodReference ref = MethodReference.findOrCreate(ClassLoaderReference.Application, "Ldataflow/StaticDataflow", "test2", + "()V"); + IMethod method = cha.resolveMethod(ref); + IR ir = cache.getIR(method); + ExplodedControlFlowGraph ecfg = ExplodedControlFlowGraph.make(ir); + IntraprocReachingDefs reachingDefs = new IntraprocReachingDefs(ecfg, cha); + BitVectorSolver solver = reachingDefs.analyze(); + for (IExplodedBasicBlock ebb : ecfg) { + if (ebb.getNumber() == 10) { + IntSet out = solver.getOut(ebb).getValue(); + Assert.assertEquals(2, out.size()); + Assert.assertTrue(out.contains(0)); + Assert.assertTrue(out.contains(2)); + } + } + } + + @Test + public void testContextInsensitive() throws IllegalArgumentException, CallGraphBuilderCancelException { + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, + "Ldataflow/StaticDataflow"); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + + CallGraphBuilder builder = Util.makeZeroOneCFABuilder(options, new AnalysisCache(), cha, scope); + CallGraph cg = builder.makeCallGraph(options, null); + ExplodedInterproceduralCFG icfg = ExplodedInterproceduralCFG.make(cg); + ContextInsensitiveReachingDefs reachingDefs = new ContextInsensitiveReachingDefs(icfg, cha); + BitVectorSolver> solver = reachingDefs.analyze(); + for (BasicBlockInContext bb : icfg) { + if (bb.getNode().toString().contains("testInterproc")) { + IExplodedBasicBlock delegate = bb.getDelegate(); + if (delegate.getNumber() == 4) { + IntSet solution = solver.getOut(bb).getValue(); + IntIterator intIterator = solution.intIterator(); + while (intIterator.hasNext()) { + int next = intIterator.next(); + System.out.println(reachingDefs.getNodeAndInstrForNumber(next)); + } + Assert.assertEquals(4, solution.size()); + } + } + } + } + + @Test + public void testContextSensitive() throws IllegalArgumentException, CancelException { + Iterable entrypoints = com.ibm.wala.ipa.callgraph.impl.Util.makeMainEntrypoints(scope, cha, + "Ldataflow/StaticDataflow"); + AnalysisOptions options = CallGraphTestUtil.makeAnalysisOptions(scope, entrypoints); + + CallGraphBuilder builder = Util.makeZeroOneCFABuilder(options, new AnalysisCache(), cha, scope); + CallGraph cg = builder.makeCallGraph(options, null); + AnalysisCache cache = new AnalysisCache(); + ContextSensitiveReachingDefs reachingDefs = new ContextSensitiveReachingDefs(cg, cache); + TabulationResult, CGNode, Pair> result = reachingDefs.analyze(); + ISupergraph, CGNode> supergraph = reachingDefs.getSupergraph(); + for (BasicBlockInContext bb : supergraph) { + if (bb.getNode().toString().contains("testInterproc")) { + IExplodedBasicBlock delegate = bb.getDelegate(); + if (delegate.getNumber() == 4) { + IntSet solution = result.getResult(bb); + IntIterator intIterator = solution.intIterator(); + while (intIterator.hasNext()) { + int next = intIterator.next(); + System.out.println(reachingDefs.getDomain().getMappedObject(next)); + } + Assert.assertEquals(3, solution.size()); + } + } + + } + + // ExplodedInterproceduralCFG icfg = ExplodedInterproceduralCFG.make(cg); + // ContextInsensitiveReachingDefs reachingDefs = new ContextInsensitiveReachingDefs(icfg , cha); + // BitVectorSolver> solver = reachingDefs.analyze(); + // for (BasicBlockInContext bb : icfg) { + // } + + } +} diff --git a/com.ibm.wala.core.tests/src/com/ibm/wala/examples/analysis/dataflow/IntraprocReachingDefs.java b/com.ibm.wala.core.tests/src/com/ibm/wala/examples/analysis/dataflow/IntraprocReachingDefs.java new file mode 100644 index 000000000..592595a2a --- /dev/null +++ b/com.ibm.wala.core.tests/src/com/ibm/wala/examples/analysis/dataflow/IntraprocReachingDefs.java @@ -0,0 +1,147 @@ +/******************************************************************************* + * Copyright (c) 2008 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.examples.analysis.dataflow; + +import java.util.ArrayList; +import java.util.Map; + +import com.ibm.wala.classLoader.IField; +import com.ibm.wala.dataflow.graph.AbstractMeetOperator; +import com.ibm.wala.dataflow.graph.BitVectorFramework; +import com.ibm.wala.dataflow.graph.BitVectorIdentity; +import com.ibm.wala.dataflow.graph.BitVectorKillGen; +import com.ibm.wala.dataflow.graph.BitVectorSolver; +import com.ibm.wala.dataflow.graph.BitVectorUnion; +import com.ibm.wala.dataflow.graph.ITransferFunctionProvider; +import com.ibm.wala.fixedpoint.impl.UnaryOperator; +import com.ibm.wala.fixpoint.BitVectorVariable; +import com.ibm.wala.ipa.cha.IClassHierarchy; +import com.ibm.wala.ssa.IR; +import com.ibm.wala.ssa.SSAInstruction; +import com.ibm.wala.ssa.SSAPutInstruction; +import com.ibm.wala.ssa.analysis.ExplodedControlFlowGraph; +import com.ibm.wala.ssa.analysis.IExplodedBasicBlock; +import com.ibm.wala.util.CancelException; +import com.ibm.wala.util.collections.HashMapFactory; +import com.ibm.wala.util.collections.ObjectArrayMapping; +import com.ibm.wala.util.intset.BitVector; +import com.ibm.wala.util.intset.OrdinalSetMapping; + +/** + * @author manu + * + */ +public class IntraprocReachingDefs { + + /** + * the exploded control-flow graph on which to compute the analysis + */ + private final ExplodedControlFlowGraph ecfg; + + /** + * maps instruction index of putstatic to more compact numbering for bitvectors + */ + private final OrdinalSetMapping putInstrNumbering; + + private final IClassHierarchy cha; + + /** + * maps each static field to the numbers of the statements that define it + */ + private final Map staticField2DefStatements = HashMapFactory.make(); + + public IntraprocReachingDefs(ExplodedControlFlowGraph ecfg, IClassHierarchy cha) { + this.ecfg = ecfg; + this.cha = cha; + this.putInstrNumbering = numberPutStatics(); + } + + private OrdinalSetMapping numberPutStatics() { + ArrayList putInstrs = new ArrayList(); + IR ir = ecfg.getIR(); + SSAInstruction[] instructions = ir.getInstructions(); + for (int i = 0; i < instructions.length; i++) { + SSAInstruction instruction = instructions[i]; + if (instruction instanceof SSAPutInstruction && ((SSAPutInstruction) instruction).isStatic()) { + SSAPutInstruction putInstr = (SSAPutInstruction) instruction; + int instrNum = putInstrs.size(); + putInstrs.add(i); + IField field = cha.resolveField(putInstr.getDeclaredField()); + assert field != null; + BitVector bv = staticField2DefStatements.get(field); + if (bv == null) { + bv = new BitVector(); + staticField2DefStatements.put(field, bv); + } + bv.set(instrNum); + } + } + return new ObjectArrayMapping(putInstrs.toArray(new Integer[putInstrs.size()])); + } + + private class TransferFunctions implements ITransferFunctionProvider { + + public UnaryOperator getEdgeTransferFunction(IExplodedBasicBlock src, IExplodedBasicBlock dst) { + throw new UnsupportedOperationException(); + } + + public AbstractMeetOperator getMeetOperator() { + // meet is union + return BitVectorUnion.instance(); + } + + public UnaryOperator getNodeTransferFunction(IExplodedBasicBlock node) { + SSAInstruction instruction = node.getInstruction(); + int instructionIndex = node.getFirstInstructionIndex(); + if (instruction instanceof SSAPutInstruction && ((SSAPutInstruction) instruction).isStatic()) { + // kill all defs of the same static field + final SSAPutInstruction putInstr = (SSAPutInstruction) instruction; + final IField field = cha.resolveField(putInstr.getDeclaredField()); + assert field != null; + BitVector kill = staticField2DefStatements.get(field); + BitVector gen = new BitVector(); + gen.set(putInstrNumbering.getMappedIndex(instructionIndex)); + return new BitVectorKillGen(kill, gen); + } else { + // nothing defined + return BitVectorIdentity.instance(); + } + } + + public boolean hasEdgeTransferFunctions() { + return false; + } + + public boolean hasNodeTransferFunctions() { + return true; + } + + } + + public BitVectorSolver analyze() { + BitVectorFramework framework = new BitVectorFramework( + ecfg, new TransferFunctions(), putInstrNumbering); + BitVectorSolver solver = new BitVectorSolver(framework); + try { + solver.solve(null); + } catch (CancelException e) { + // TODO Auto-generated catch block + e.printStackTrace(); + } + for (IExplodedBasicBlock ebb : ecfg) { + System.out.println(ebb); + System.out.println(ebb.getInstruction()); + System.out.println(solver.getIn(ebb)); + System.out.println(solver.getOut(ebb)); + } + return solver; + } +}