├── .classpath ├── .github └── workflows │ └── ci.yml ├── .gitignore ├── .idea └── workspace.xml ├── .project ├── .settings ├── com.wdev91.eclipse.copyright.xml ├── edu.umd.cs.findbugs.core.prefs ├── org.eclipse.core.resources.prefs ├── org.eclipse.jdt.core.prefs └── org.eclipse.jdt.ui.prefs ├── LICENSE.txt ├── META-INF └── MANIFEST.MF ├── README.md ├── TODO.txt ├── ant.settings.jenkins ├── ant.settings.template ├── build.properties ├── build.xml ├── heros.iml ├── ivy.xml ├── ivysettings.xml ├── logo ├── heros-logo.graffle └── heros-logo.png ├── pom.xml ├── src └── heros │ ├── DefaultSeeds.java │ ├── DontSynchronize.java │ ├── EdgeFunction.java │ ├── EdgeFunctionCache.java │ ├── EdgeFunctions.java │ ├── FlowFunction.java │ ├── FlowFunctionCache.java │ ├── FlowFunctions.java │ ├── IDETabulationProblem.java │ ├── IFDSTabulationProblem.java │ ├── InterproceduralCFG.java │ ├── ItemPrinter.java │ ├── MeetLattice.java │ ├── MustSynchronize.java │ ├── ProfiledFlowFunctions.java │ ├── SolverConfiguration.java │ ├── SynchronizedBy.java │ ├── ThreadSafe.java │ ├── TwoElementSet.java │ ├── ZeroedFlowFunctions.java │ ├── edgefunc │ ├── AllBottom.java │ ├── AllTop.java │ └── EdgeIdentity.java │ ├── fieldsens │ ├── AccessPath.java │ ├── AccessPathHandler.java │ ├── BiDiFieldSensitiveIFDSSolver.java │ ├── CallEdge.java │ ├── CallEdgeResolver.java │ ├── Context.java │ ├── ControlFlowJoinResolver.java │ ├── Debugger.java │ ├── FactMergeHandler.java │ ├── FieldSensitiveIFDSSolver.java │ ├── FlowFunction.java │ ├── FlowFunctions.java │ ├── IFDSTabulationProblem.java │ ├── InterestCallback.java │ ├── MethodAnalyzer.java │ ├── MethodAnalyzerImpl.java │ ├── PerAccessPathMethodAnalyzer.java │ ├── Resolver.java │ ├── ResolverTemplate.java │ ├── ReturnSiteResolver.java │ ├── Scheduler.java │ ├── SourceStmtAnnotatedMethodAnalyzer.java │ ├── ZeroCallEdgeResolver.java │ ├── ZeroHandler.java │ └── structs │ │ ├── DeltaConstraint.java │ │ ├── FactAtStatement.java │ │ ├── ReturnEdge.java │ │ ├── WrappedFact.java │ │ └── WrappedFactAtStatement.java │ ├── flowfunc │ ├── Compose.java │ ├── Gen.java │ ├── Identity.java │ ├── Kill.java │ ├── KillAll.java │ ├── Transfer.java │ └── Union.java │ ├── solver │ ├── BiDiIDESolver.java │ ├── BiDiIFDSSolver.java │ ├── CountLatch.java │ ├── CountingThreadPoolExecutor.java │ ├── FlowFunctionDotExport.java │ ├── IDESolver.java │ ├── IFDSSolver.java │ ├── JoinHandlingNode.java │ ├── JoinHandlingNodesIFDSSolver.java │ ├── JumpFunctions.java │ ├── LinkedNode.java │ ├── NotesOnSummaryGeneration.txt │ ├── Pair.java │ ├── PathEdge.java │ └── PathTrackingIFDSSolver.java │ ├── template │ ├── DefaultIDETabulationProblem.java │ └── DefaultIFDSTabulationProblem.java │ ├── util │ └── SootThreadGroup.java │ └── utilities │ ├── DefaultValueMap.java │ ├── JsonArray.java │ └── JsonDocument.java └── test └── heros ├── BiDiIFDSSolverTest.java ├── IFDSSolverTest.java ├── fieldsens ├── AccessPathTest.java ├── BiDiFieldSensitiveIFDSSolverTest.java ├── ControlFlowJoinResolverTest.java ├── FieldSensitiveIFDSSolverTest.java └── ReturnSiteResolverTest.java └── utilities ├── Edge.java ├── EdgeBuilder.java ├── ExpectedFlowFunction.java ├── FieldSensitiveTestHelper.java ├── JoinableFact.java ├── Statement.java ├── TestDebugger.java ├── TestFact.java ├── TestHelper.java └── TestMethod.java /.classpath: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | # This workflow will build a Java project with Maven 2 | # For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven 3 | 4 | name: Heros CI 5 | on: 6 | push: 7 | pull_request: 8 | 9 | jobs: 10 | 11 | BuildAndTest: 12 | name: Build and Test with java 13 | runs-on: ubuntu-latest 14 | steps: 15 | - name: Checkout 16 | uses: actions/checkout@v2 17 | - name: Use Java 8 18 | uses: actions/setup-java@v1 19 | with: 20 | java-version: '8' 21 | - name: Build and test Java 8 22 | run: | 23 | mvn -B clean test 24 | 25 | DeployArtifacts: 26 | name: Deploy artifacts to Maven Central 27 | if: github.ref == 'refs/heads/master' || github.ref == 'refs/heads/develop' 28 | needs: [BuildAndTest] 29 | runs-on: ubuntu-latest 30 | steps: 31 | - name: Checkout 32 | uses: actions/checkout@v2 33 | - name: Use Java 8 34 | uses: actions/setup-java@v1 35 | with: 36 | java-version: '8' 37 | - name: Deploy artifacts 38 | uses: samuelmeuli/action-maven-publish@v1 39 | with: 40 | gpg_private_key: ${{ secrets.gpg_private_key }} 41 | gpg_passphrase: ${{ secrets.gpg_passphrase }} 42 | nexus_username: ${{ secrets.nexus_username }} 43 | nexus_password: ${{ secrets.nexus_password }} 44 | maven_args: "-DskipTests" 45 | 46 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.class 2 | 3 | # Package Files # 4 | *.war 5 | *.ear 6 | /ant.settings 7 | bin 8 | heros-trunk.jar 9 | /javadoc 10 | /reports 11 | /debug 12 | /target/ 13 | -------------------------------------------------------------------------------- /.project: -------------------------------------------------------------------------------- 1 | 2 | 3 | heros 4 | 5 | 6 | 7 | 8 | 9 | org.eclipse.jdt.core.javabuilder 10 | 11 | 12 | 13 | 14 | org.eclipse.pde.ManifestBuilder 15 | 16 | 17 | 18 | 19 | org.eclipse.pde.SchemaBuilder 20 | 21 | 22 | 23 | 24 | edu.umd.cs.findbugs.plugin.eclipse.findbugsBuilder 25 | 26 | 27 | 28 | 29 | org.eclipse.m2e.core.maven2Builder 30 | 31 | 32 | 33 | 34 | 35 | org.eclipse.m2e.core.maven2Nature 36 | org.eclipse.jdt.core.javanature 37 | org.eclipse.pde.PluginNature 38 | edu.umd.cs.findbugs.plugin.eclipse.findbugsNature 39 | 40 | 41 | -------------------------------------------------------------------------------- /.settings/com.wdev91.eclipse.copyright.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | Eric Bodden 4 | 5 | -------------------------------------------------------------------------------- /.settings/org.eclipse.core.resources.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | encoding/=UTF-8 3 | encoding/src=UTF-8 4 | encoding/test=UTF-8 5 | -------------------------------------------------------------------------------- /.settings/org.eclipse.jdt.core.prefs: -------------------------------------------------------------------------------- 1 | eclipse.preferences.version=1 2 | org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled 3 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6 4 | org.eclipse.jdt.core.compiler.compliance=1.6 5 | org.eclipse.jdt.core.compiler.problem.assertIdentifier=error 6 | org.eclipse.jdt.core.compiler.problem.enumIdentifier=error 7 | org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning 8 | org.eclipse.jdt.core.compiler.release=disabled 9 | org.eclipse.jdt.core.compiler.source=1.6 10 | -------------------------------------------------------------------------------- /META-INF/MANIFEST.MF: -------------------------------------------------------------------------------- 1 | Manifest-Version: 1.0 2 | Bundle-ManifestVersion: 2 3 | Bundle-Name: soot-ifds 4 | Bundle-SymbolicName: heros 5 | Bundle-Version: 1.0.0.qualifier 6 | Bundle-ClassPath: soot-ifds.jar, 7 | guava-13.0.jar, 8 | soot-trunk.jar 9 | Export-Package: heros, 10 | heros.edgefunc, 11 | heros.flowfunc, 12 | heros.solver, 13 | heros.template 14 | Import-Package: com.google.common.cache 15 | -------------------------------------------------------------------------------- /TODO.txt: -------------------------------------------------------------------------------- 1 | IFDS: 2 | Have simpler templates for flow functions. 3 | Should be efficient, do not create too many sets. 4 | Create binary sets. 5 | Separate normal return from throw flow functions? 6 | Useful templates 7 | Template for local-variable tracking analyses 8 | Performance optimizations 9 | Implement subsumtion as in CC'10 paper 10 | 11 | Notes: 12 | Could it be that RHS even works for infinite domains? 13 | -------------------------------------------------------------------------------- /ant.settings.jenkins: -------------------------------------------------------------------------------- 1 | heros.version=trunk 2 | 3 | guava.jar=guava-18.0.jar 4 | slf4j-api.jar=slf4j-api-1.7.5.jar 5 | slf4j-simple.jar=slf4j-simple-1.7.5.jar 6 | 7 | mockito.jar=mockito-all-1.9.5.jar 8 | hamcrest.jar=org.hamcrest.core_1.3.0.jar 9 | junit.jar=junit.jar 10 | -------------------------------------------------------------------------------- /ant.settings.template: -------------------------------------------------------------------------------- 1 | heros.version=trunk 2 | 3 | guava.jar=guava-18.0.jar 4 | slf4j-api.jar=slf4j-api-1.7.5.jar 5 | slf4j-simple.jar=slf4j-simple-1.7.5.jar 6 | 7 | mockito.jar=mockito-all-1.9.5.jar 8 | hamcrest.jar=org.hamcrest.core_1.3.0.jar 9 | junit.jar=junit.jar 10 | -------------------------------------------------------------------------------- /build.properties: -------------------------------------------------------------------------------- 1 | source.soot-ifds.jar = src/ 2 | bin.includes = META-INF/,\ 3 | soot-ifds.jar,\ 4 | soot-trunk.jar,\ 5 | guava-14.0.1.jar 6 | -------------------------------------------------------------------------------- /heros.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /ivy.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 22 | -------------------------------------------------------------------------------- /ivysettings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /logo/heros-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soot-oss/heros/4aaa90ce4cde75bd650886ef51e4d9915dae48af/logo/heros-logo.png -------------------------------------------------------------------------------- /src/heros/DefaultSeeds.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2012 Eric Bodden. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Eric Bodden - initial API and implementation 10 | ******************************************************************************/ 11 | package heros; 12 | 13 | import java.util.Collections; 14 | import java.util.HashMap; 15 | import java.util.Map; 16 | import java.util.Set; 17 | 18 | /** 19 | * A utility class for creating default seeds that cause an analysis to simply start at a given statement. 20 | * This is useful if seeding is performed entirely through flow functions as used to be the case in 21 | * earlier versions of Heros. 22 | */ 23 | public class DefaultSeeds { 24 | 25 | public static Map> make(Iterable units, D zeroNode) { 26 | Map> res = new HashMap>(); 27 | for (N n : units) { 28 | res.put(n, Collections.singleton(zeroNode)); 29 | } 30 | return res; 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /src/heros/DontSynchronize.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2012 Eric Bodden. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Eric Bodden - initial API and implementation 10 | ******************************************************************************/ 11 | package heros; 12 | 13 | import static java.lang.annotation.ElementType.FIELD; 14 | 15 | import java.lang.annotation.Target; 16 | 17 | /** Semantic annotation stating that the annotated field can remain unsynchronized. 18 | * This annotation is meant as a structured comment only, and has no immediate effect. */ 19 | @Target(FIELD) 20 | public @interface DontSynchronize{ String value() default ""; } 21 | -------------------------------------------------------------------------------- /src/heros/EdgeFunction.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2012 Eric Bodden. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Eric Bodden - initial API and implementation 10 | ******************************************************************************/ 11 | package heros; 12 | 13 | 14 | /** 15 | * An edge function computes how a V-type value changes when flowing from one 16 | * super-graph node to another. See Sagiv, Reps, Horwitz 1996. 17 | * 18 | * NOTE: Methods defined on this type may be called simultaneously by different threads. 19 | * Hence, classes implementing this interface should synchronize accesses to 20 | * any mutable shared state. 21 | * 22 | * @param The type of values to be computed along flow edges. 23 | */ 24 | public interface EdgeFunction { 25 | 26 | /** 27 | * Computes the value resulting from applying this function to source. 28 | */ 29 | V computeTarget(V source); 30 | 31 | /** 32 | * Composes this function with the secondFunction, effectively returning 33 | * a summary function that maps sources to targets exactly as if 34 | * first this function had been applied and then the secondFunction. 35 | */ 36 | EdgeFunction composeWith(EdgeFunction secondFunction); 37 | 38 | /** 39 | * Returns a function that represents that (element-wise) meet 40 | * of this function with otherFunction. Naturally, this is a 41 | * symmetric operation. 42 | * @see MeetLattice#meet(Object, Object) 43 | */ 44 | EdgeFunction meetWith(EdgeFunction otherFunction); 45 | 46 | /** 47 | * Returns true is this function represents exactly the same 48 | * source to target mapping as other. 49 | */ 50 | public boolean equalTo(EdgeFunction other); 51 | 52 | } 53 | -------------------------------------------------------------------------------- /src/heros/EdgeFunctions.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2012 Eric Bodden. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Eric Bodden - initial API and implementation 10 | ******************************************************************************/ 11 | package heros; 12 | 13 | /** 14 | * Classes implementing this interface provide a range of edge functions used to 15 | * compute a V-type value for each of the finitely many D-type values reachable 16 | * in the program. 17 | * 18 | * @param 19 | * The type of nodes in the interprocedural control-flow graph. 20 | * Typically {@link Unit}. 21 | * @param 22 | * The type of data-flow facts to be computed by the tabulation 23 | * problem. 24 | * @param 25 | * The type of objects used to represent methods. Typically 26 | * {@link SootMethod}. 27 | * @param 28 | * The type of values to be computed along flow edges. 29 | */ 30 | public interface EdgeFunctions { 31 | 32 | /** 33 | * Returns the function that computes how the V-typed value changes when 34 | * being propagated from srcNode at statement src to tgtNode at statement 35 | * tgt. 36 | * 37 | * @param curr 38 | * The statement from which the flow originates. 39 | * @param currNode 40 | * The D-type value with which the source value is associated. 41 | * @param succ 42 | * The target statement of the flow. 43 | * @param succNode 44 | * The D-type value with which the target value will be 45 | * associated. 46 | */ 47 | public EdgeFunction getNormalEdgeFunction(N curr, D currNode, N succ, D succNode); 48 | 49 | /** 50 | * Returns the function that computes how the V-typed value changes when 51 | * being propagated along a method call. 52 | * 53 | * @param callStmt 54 | * The call statement from which the flow originates. 55 | * @param srcNode 56 | * The D-type value with which the source value is associated. 57 | * @param destinationMethod 58 | * A concrete destination method of the call. 59 | * @param destNode 60 | * The D-type value with which the target value will be 61 | * associated at the side of the callee. 62 | */ 63 | public EdgeFunction getCallEdgeFunction(N callStmt, D srcNode, M destinationMethod, D destNode); 64 | 65 | /** 66 | * Returns the function that computes how the V-typed value changes when 67 | * being propagated along a method exit (return or throw). 68 | * 69 | * @param callSite 70 | * One of all the call sites in the program that called the 71 | * method from which the exitStmt is actually returning. This 72 | * information can be exploited to compute a value that depend on 73 | * information from before the call. 74 | * Note: This value might be null if 75 | * using a tabulation problem with {@link IFDSTabulationProblem#followReturnsPastSeeds()} 76 | * returning true in a situation where the call graph 77 | * does not contain a caller for the method that is returned from. 78 | * @param calleeMethod 79 | * The method from which we are exiting. 80 | * @param exitStmt 81 | * The exit statement from which the flow originates. 82 | * @param exitNode 83 | * The D-type value with which the source value is associated. 84 | * @param returnSite 85 | * One of the possible successor statements of a caller to the 86 | * method we are exiting from. 87 | * Note: This value might be null if 88 | * using a tabulation problem with {@link IFDSTabulationProblem#followReturnsPastSeeds()} 89 | * returning true in a situation where the call graph 90 | * does not contain a caller for the method that is returned from. 91 | * @param tgtNode 92 | * The D-type value with which the target value will be 93 | * associated at the returnSite. 94 | */ 95 | public EdgeFunction getReturnEdgeFunction(N callSite, M calleeMethod, N exitStmt, D exitNode, N returnSite, D retNode); 96 | 97 | /** 98 | * Returns the function that computes how the V-typed value changes when 99 | * being propagated from a method call to one of its intraprocedural 100 | * successor. 101 | * 102 | * @param callSite 103 | * The call statement from which the flow originates. 104 | * @param callNode 105 | * The D-type value with which the source value is associated. 106 | * @param returnSite 107 | * One of the possible successor statements of a call statement. 108 | * @param returnSideNode 109 | * The D-type value with which the target value will be 110 | * associated at the returnSite. 111 | */ 112 | public EdgeFunction getCallToReturnEdgeFunction(N callSite, D callNode, N returnSite, D returnSideNode); 113 | 114 | } 115 | -------------------------------------------------------------------------------- /src/heros/FlowFunction.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2012 Eric Bodden. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Eric Bodden - initial API and implementation 10 | ******************************************************************************/ 11 | package heros; 12 | 13 | import java.util.LinkedHashSet; 14 | import java.util.Set; 15 | 16 | /** 17 | * A flow function computes which of the finitely many D-type values are reachable 18 | * from the current source values. Typically there will be one such function 19 | * associated with every possible control flow. 20 | * 21 | * NOTE: To be able to produce deterministic benchmarking results, we have found that 22 | * it helps to return {@link LinkedHashSet}s from {@link #computeTargets(Object)}. This is 23 | * because the duration of IDE's fixed point iteration may depend on the iteration order. 24 | * Within the solver, we have tried to fix this order as much as possible, but the 25 | * order, in general, does also depend on the order in which the result set 26 | * of {@link #computeTargets(Object)} is traversed. 27 | * 28 | * NOTE: Methods defined on this type may be called simultaneously by different threads. 29 | * Hence, classes implementing this interface should synchronize accesses to 30 | * any mutable shared state. 31 | * 32 | * @param The type of data-flow facts to be computed by the tabulation problem. 33 | */ 34 | public interface FlowFunction { 35 | 36 | /** 37 | * Returns the target values reachable from the source. 38 | */ 39 | Set computeTargets(D source); 40 | } 41 | -------------------------------------------------------------------------------- /src/heros/FlowFunctions.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2012 Eric Bodden. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Eric Bodden - initial API and implementation 10 | ******************************************************************************/ 11 | package heros; 12 | 13 | /** 14 | * Classes implementing this interface provide a factory for a 15 | * range of flow functions used to compute which D-type values 16 | * are reachable along the program's control flow. 17 | * 18 | * @param 19 | * The type of nodes in the interprocedural control-flow graph. 20 | * Typically {@link Unit}. 21 | * @param 22 | * The type of data-flow facts to be computed by the tabulation 23 | * problem. 24 | * @param 25 | * The type of objects used to represent methods. Typically 26 | * {@link SootMethod}. 27 | */ 28 | public interface FlowFunctions { 29 | 30 | /** 31 | * Returns the flow function that computes the flow for a normal statement, 32 | * i.e., a statement that is neither a call nor an exit statement. 33 | * 34 | * @param curr 35 | * The current statement. 36 | * @param succ 37 | * The successor for which the flow is computed. This value can 38 | * be used to compute a branched analysis that propagates 39 | * different values depending on where control0flow branches. 40 | */ 41 | public FlowFunction getNormalFlowFunction(N curr, N succ); 42 | 43 | /** 44 | * Returns the flow function that computes the flow for a call statement. 45 | * 46 | * @param callStmt 47 | * The statement containing the invoke expression giving rise to 48 | * this call. 49 | * @param destinationMethod 50 | * The concrete target method for which the flow is computed. 51 | */ 52 | public FlowFunction getCallFlowFunction(N callStmt, M destinationMethod); 53 | 54 | /** 55 | * Returns the flow function that computes the flow for a an exit from a 56 | * method. An exit can be a return or an exceptional exit. 57 | * 58 | * @param callSite 59 | * One of all the call sites in the program that called the 60 | * method from which the exitStmt is actually returning. This 61 | * information can be exploited to compute a value that depends on 62 | * information from before the call. 63 | * Note: This value might be null if 64 | * using a tabulation problem with {@link IFDSTabulationProblem#followReturnsPastSeeds()} 65 | * returning true in a situation where the call graph 66 | * does not contain a caller for the method that is returned from. 67 | * @param calleeMethod 68 | * The method from which exitStmt returns. 69 | * @param exitStmt 70 | * The statement exiting the method, typically a return or throw 71 | * statement. 72 | * @param returnSite 73 | * One of the successor statements of the callSite. There may be 74 | * multiple successors in case of possible exceptional flow. This 75 | * method will be called for each such successor. 76 | * Note: This value might be null if 77 | * using a tabulation problem with {@link IFDSTabulationProblem#followReturnsPastSeeds()} 78 | * returning true in a situation where the call graph 79 | * does not contain a caller for the method that is returned from. 80 | * @return 81 | */ 82 | public FlowFunction getReturnFlowFunction(N callSite, M calleeMethod, N exitStmt, N returnSite); 83 | 84 | /** 85 | * Returns the flow function that computes the flow from a call site to a 86 | * successor statement just after the call. There may be multiple successors 87 | * in case of exceptional control flow. In this case this method will be 88 | * called for every such successor. Typically, one will propagate into a 89 | * method call, using {@link #getCallFlowFunction(Object, Object)}, only 90 | * such information that actually concerns the callee method. All other 91 | * information, e.g. information that cannot be modified by the call, is 92 | * passed along this call-return edge. 93 | * 94 | * @param callSite 95 | * The statement containing the invoke expression giving rise to 96 | * this call. 97 | * @param returnSite 98 | * The return site to which the information is propagated. For 99 | * exceptional flow, this may actually be the start of an 100 | * exception handler. 101 | */ 102 | public FlowFunction getCallToReturnFlowFunction(N callSite, N returnSite); 103 | 104 | } 105 | -------------------------------------------------------------------------------- /src/heros/IDETabulationProblem.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2012 Eric Bodden. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Eric Bodden - initial API and implementation 10 | ******************************************************************************/ 11 | package heros; 12 | 13 | /** 14 | * Defines an IDE tabulation problem as presented in the Sagiv, Reps, Horwitz 1996 15 | * (SRH96) paper. An IDE tabulation problem extends an {@link IFDSTabulationProblem} 16 | * by allowing additional values to be computed along flow functions: each domain value 17 | * of type D maps at any program point to a value of type V. The functions describe how 18 | * values are transformed when moving from one statement to another. 19 | * 20 | * The problem further defines a {@link MeetLattice}, which describes how values of 21 | * type V are merged (via a meet operation) when multiple values are possible. 22 | * 23 | * @param The type of nodes in the interprocedural control-flow graph. Typically {@link Unit}. 24 | * @param The type of data-flow facts to be computed by the tabulation problem. 25 | * @param The type of objects used to represent methods. Typically {@link SootMethod}. 26 | * @param The type of values to be computed along flow edges. 27 | * @param The type of inter-procedural control-flow graph being used. 28 | */ 29 | public interface IDETabulationProblem> extends IFDSTabulationProblem{ 30 | 31 | /** 32 | * Returns the edge functions that describe how V-values are transformed along 33 | * flow function edges. 34 | */ 35 | EdgeFunctions edgeFunctions(); 36 | 37 | /** 38 | * Returns the lattice describing how to compute the meet of two V values. 39 | */ 40 | MeetLattice meetLattice(); 41 | 42 | /** 43 | * Returns a function mapping everything to top. 44 | */ 45 | EdgeFunction allTopFunction(); 46 | } 47 | -------------------------------------------------------------------------------- /src/heros/IFDSTabulationProblem.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2012 Eric Bodden. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Eric Bodden - initial API and implementation 10 | ******************************************************************************/ 11 | package heros; 12 | 13 | import heros.solver.IFDSSolver; 14 | 15 | import java.util.Map; 16 | import java.util.Set; 17 | 18 | 19 | 20 | /** 21 | * A tabulation problem for solving in an {@link IFDSSolver} as described 22 | * by the Reps, Horwitz, Sagiv 1995 (RHS95) paper. 23 | * 24 | * @param The type of nodes in the interprocedural control-flow graph. Typically {@link Unit}. 25 | * @param The type of data-flow facts to be computed by the tabulation problem. 26 | * @param The type of objects used to represent methods. Typically {@link SootMethod}. 27 | * @param The type of inter-procedural control-flow graph being used. 28 | */ 29 | public interface IFDSTabulationProblem> extends SolverConfiguration { 30 | 31 | /** 32 | * Returns a set of flow functions. Those functions are used to compute data-flow facts 33 | * along the various kinds of control flows. 34 | * 35 | * NOTE: this method could be called many times. Implementations of this 36 | * interface should therefore cache the return value! 37 | */ 38 | FlowFunctions flowFunctions(); 39 | 40 | /** 41 | * Returns the interprocedural control-flow graph which this problem is computed over. 42 | * 43 | * NOTE: this method could be called many times. Implementations of this 44 | * interface should therefore cache the return value! 45 | */ 46 | I interproceduralCFG(); 47 | 48 | /** 49 | * Returns initial seeds to be used for the analysis. This is a mapping of statements to initial analysis facts. 50 | */ 51 | Map> initialSeeds(); 52 | 53 | /** 54 | * This must be a data-flow fact of type {@link D}, but must not 55 | * be part of the domain of data-flow facts. Typically this will be a 56 | * singleton object of type {@link D} that is used for nothing else. 57 | * It must holds that this object does not equals any object 58 | * within the domain. 59 | * 60 | * NOTE: this method could be called many times. Implementations of this 61 | * interface should therefore cache the return value! 62 | */ 63 | D zeroValue(); 64 | 65 | } 66 | -------------------------------------------------------------------------------- /src/heros/InterproceduralCFG.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2012 Eric Bodden. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Eric Bodden - initial API and implementation 10 | ******************************************************************************/ 11 | package heros; 12 | 13 | import java.util.Collection; 14 | import java.util.List; 15 | import java.util.Set; 16 | 17 | /** 18 | * An interprocedural control-flow graph. 19 | * 20 | * @param Nodes in the CFG, typically {@link Unit} or {@link Block} 21 | * @param Method representation 22 | */ 23 | public interface InterproceduralCFG { 24 | 25 | /** 26 | * Returns the method containing a node. 27 | * @param n The node for which to get the parent method 28 | */ 29 | public M getMethodOf(N n); 30 | 31 | public List getPredsOf(N u); 32 | 33 | /** 34 | * Returns the successor nodes. 35 | */ 36 | public List getSuccsOf(N n); 37 | 38 | /** 39 | * Returns all callee methods for a given call. 40 | */ 41 | public Collection getCalleesOfCallAt(N n); 42 | 43 | /** 44 | * Returns all caller statements/nodes of a given method. 45 | */ 46 | public Collection getCallersOf(M m); 47 | 48 | /** 49 | * Returns all call sites within a given method. 50 | */ 51 | public Set getCallsFromWithin(M m); 52 | 53 | /** 54 | * Returns all start points of a given method. There may be 55 | * more than one start point in case of a backward analysis. 56 | */ 57 | public Collection getStartPointsOf(M m); 58 | 59 | /** 60 | * Returns all statements to which a call could return. 61 | * In the RHS paper, for every call there is just one return site. 62 | * We, however, use as return site the successor statements, of which 63 | * there can be many in case of exceptional flow. 64 | */ 65 | public Collection getReturnSitesOfCallAt(N n); 66 | 67 | /** 68 | * Returns true if the given statement is a call site. 69 | */ 70 | public boolean isCallStmt(N stmt); 71 | 72 | /** 73 | * Returns true if the given statement leads to a method return 74 | * (exceptional or not). For backward analyses may also be start statements. 75 | */ 76 | public boolean isExitStmt(N stmt); 77 | 78 | /** 79 | * Returns true is this is a method's start statement. For backward analyses 80 | * those may also be return or throws statements. 81 | */ 82 | public boolean isStartPoint(N stmt); 83 | 84 | /** 85 | * Returns the set of all nodes that are neither call nor start nodes. 86 | */ 87 | public Set allNonCallStartNodes(); 88 | 89 | /** 90 | * Returns whether succ is the fall-through successor of stmt, 91 | * i.e., the unique successor that is be reached when stmt 92 | * does not branch. 93 | */ 94 | public boolean isFallThroughSuccessor(N stmt, N succ); 95 | 96 | /** 97 | * Returns whether succ is a branch target of stmt. 98 | */ 99 | public boolean isBranchTarget(N stmt, N succ); 100 | 101 | } 102 | -------------------------------------------------------------------------------- /src/heros/ItemPrinter.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2015 Eric Bodden. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * John Toman - initial API and implementation 10 | ******************************************************************************/ 11 | package heros; 12 | 13 | /** 14 | * Interface for creating string representations of nodes, facts, 15 | * and methods in the IDE/IFDS problem. 16 | * 17 | * @param The type of nodes in the interprocedural control-flow graph. 18 | * @param The type of data-flow facts to computed by the tabulation problem. 19 | * @param The type of objects used to represent methods. 20 | */ 21 | public interface ItemPrinter { 22 | public String printNode(N node, M parentMethod); 23 | public String printFact(D fact); 24 | public String printMethod(M method); 25 | public static final ItemPrinter DEFAULT_PRINTER = new ItemPrinter() { 26 | @Override 27 | public String printNode(Object node, Object parentMethod) { 28 | return node.toString(); 29 | } 30 | 31 | @Override 32 | public String printFact(Object fact) { 33 | return fact.toString(); 34 | } 35 | 36 | @Override 37 | public String printMethod(Object method) { 38 | return method.toString(); 39 | } 40 | }; 41 | } 42 | -------------------------------------------------------------------------------- /src/heros/MeetLattice.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2012 Eric Bodden. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Eric Bodden - initial API and implementation 10 | ******************************************************************************/ 11 | package heros; 12 | 13 | /** 14 | * This class defines a lattice in terms of its top and bottom elements 15 | * and a meet operation. This is meant to be a complete lattice, with a unique top and bottom element. 16 | * 17 | * @param The domain type for this lattice. 18 | */ 19 | public interface MeetLattice { 20 | 21 | /** 22 | * Returns the unique top element of this lattice. 23 | */ 24 | V topElement(); 25 | 26 | /** 27 | * Returns the unique bottom element of this lattice. 28 | */ 29 | V bottomElement(); 30 | 31 | /** 32 | * Computes the meet of left and right. Note that
meet(top,x) = meet(x,top) = x
and 33 | *
meet(bottom,x) = meet(x,bottom) = bottom
. 34 | */ 35 | V meet(V left, V right); 36 | 37 | } 38 | -------------------------------------------------------------------------------- /src/heros/MustSynchronize.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2012 Eric Bodden. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Eric Bodden - initial API and implementation 10 | ******************************************************************************/ 11 | package heros; 12 | 13 | import static java.lang.annotation.ElementType.FIELD; 14 | 15 | import java.lang.annotation.Target; 16 | 17 | /** Semantic annotation stating that the annotated field must be synchronized. 18 | * This annotation is meant as a structured comment only, and has no immediate effect. */ 19 | @Target(FIELD) 20 | public @interface MustSynchronize{ String value() default ""; } 21 | -------------------------------------------------------------------------------- /src/heros/ProfiledFlowFunctions.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2012 Eric Bodden. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Eric Bodden - initial API and implementation 10 | ******************************************************************************/ 11 | package heros; 12 | 13 | /** 14 | * A wrapper that can be used to profile flow functions. 15 | */ 16 | public class ProfiledFlowFunctions implements FlowFunctions { 17 | 18 | protected final FlowFunctions delegate; 19 | 20 | public long durationNormal, durationCall, durationReturn, durationCallReturn; 21 | 22 | public ProfiledFlowFunctions(FlowFunctions delegate) { 23 | this.delegate = delegate; 24 | } 25 | 26 | public FlowFunction getNormalFlowFunction(N curr, N succ) { 27 | long before = System.currentTimeMillis(); 28 | FlowFunction ret = delegate.getNormalFlowFunction(curr, succ); 29 | long duration = System.currentTimeMillis() - before; 30 | durationNormal += duration; 31 | return ret; 32 | } 33 | 34 | public FlowFunction getCallFlowFunction(N callStmt, M destinationMethod) { 35 | long before = System.currentTimeMillis(); 36 | FlowFunction res = delegate.getCallFlowFunction(callStmt, destinationMethod); 37 | long duration = System.currentTimeMillis() - before; 38 | durationCall += duration; 39 | return res; 40 | } 41 | 42 | public FlowFunction getReturnFlowFunction(N callSite, M calleeMethod, N exitStmt, N returnSite) { 43 | long before = System.currentTimeMillis(); 44 | FlowFunction res = delegate.getReturnFlowFunction(callSite, calleeMethod, exitStmt, returnSite); 45 | long duration = System.currentTimeMillis() - before; 46 | durationReturn += duration; 47 | return res; 48 | } 49 | 50 | public FlowFunction getCallToReturnFlowFunction(N callSite, N returnSite) { 51 | long before = System.currentTimeMillis(); 52 | FlowFunction res = delegate.getCallToReturnFlowFunction(callSite, returnSite); 53 | long duration = System.currentTimeMillis() - before; 54 | durationCallReturn += duration; 55 | return res; 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /src/heros/SolverConfiguration.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2012 Eric Bodden. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Eric Bodden - initial API and implementation 10 | * John Toman - adds recordEdge option 11 | ******************************************************************************/ 12 | package heros; 13 | 14 | import heros.solver.IDESolver; 15 | 16 | /** 17 | * Configuration parameters for {@link IDESolver}. 18 | */ 19 | public interface SolverConfiguration { 20 | 21 | 22 | /** 23 | * If true, the analysis will compute a partially unbalanced analysis problem in which 24 | * function returns are followed also further up the call stack than where the initial seeds 25 | * started. 26 | * 27 | * If this is enabled, when reaching the exit of a method that is nowhere called, in order 28 | * to avoid not at all processing the exit statement, the {@link IDESolver} will call 29 | * the return flow function with a null call site and return site. 30 | */ 31 | boolean followReturnsPastSeeds(); 32 | 33 | /** 34 | * If true, the solver will automatically add the zero value to each flow-function call's result set. 35 | * @see #zeroValue() 36 | */ 37 | boolean autoAddZero(); 38 | 39 | /** 40 | * Returns the number of threads to be used by the solver. 41 | */ 42 | int numThreads(); 43 | 44 | /** 45 | * If false, then the solver will only compute the exploded super graph but not propagate values. 46 | * This can save time for IFDS problems where all of the interesting results are collected already 47 | * during the computation of the super graph. 48 | */ 49 | boolean computeValues(); 50 | 51 | /** 52 | * Returns true if the solver should record the intermediate flow edges 53 | * created by calling the methods on {@link IFDSTabulationProblem#flowFunctions()}. 54 | * These nodes are not used by the solver, but may be useful for debugging the solver 55 | * or flow functions (see {@link FlowFunctionDotExport}). 56 | */ 57 | boolean recordEdges(); 58 | } 59 | -------------------------------------------------------------------------------- /src/heros/SynchronizedBy.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2012 Eric Bodden. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Eric Bodden - initial API and implementation 10 | ******************************************************************************/ 11 | package heros; 12 | 13 | import static java.lang.annotation.ElementType.FIELD; 14 | 15 | import java.lang.annotation.Target; 16 | 17 | /** Semantic annotation that the annotated field is synchronized. 18 | * This annotation is meant as a structured comment only, and has no immediate effect. */ 19 | @Target(FIELD) 20 | public @interface SynchronizedBy{ String value() default ""; } 21 | -------------------------------------------------------------------------------- /src/heros/ThreadSafe.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2012 Eric Bodden. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Eric Bodden - initial API and implementation 10 | ******************************************************************************/ 11 | package heros; 12 | 13 | /** 14 | * This annotation tells that the class was designed to be used by multiple threads, with concurrent updates. 15 | */ 16 | public @interface ThreadSafe { 17 | 18 | String value() default ""; 19 | 20 | } 21 | -------------------------------------------------------------------------------- /src/heros/TwoElementSet.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2013 Eric Bodden. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Eric Bodden - initial API and implementation 10 | ******************************************************************************/ 11 | package heros; 12 | 13 | import java.util.AbstractSet; 14 | import java.util.Iterator; 15 | import java.util.NoSuchElementException; 16 | 17 | /** 18 | * An unmodifiable set holding exactly two elements. Particularly useful within flow functions. 19 | * 20 | * @param 21 | * @see FlowFunction 22 | */ 23 | public class TwoElementSet extends AbstractSet { 24 | 25 | protected final E first, second; 26 | 27 | public TwoElementSet(E first, E second) { 28 | this.first = first; 29 | this.second = second; 30 | } 31 | 32 | public static TwoElementSet twoElementSet(E first, E second) { 33 | return new TwoElementSet(first, second); 34 | } 35 | 36 | @Override 37 | public Iterator iterator() { 38 | return new Iterator() { 39 | int elementsRead = 0; 40 | 41 | @Override 42 | public boolean hasNext() { 43 | return elementsRead<2; 44 | } 45 | 46 | @Override 47 | public E next() { 48 | switch(elementsRead) { 49 | case 0: 50 | elementsRead++; 51 | return first; 52 | case 1: 53 | elementsRead++; 54 | return second; 55 | default: 56 | throw new NoSuchElementException(); 57 | } 58 | } 59 | 60 | @Override 61 | public void remove() { 62 | throw new UnsupportedOperationException(); 63 | } 64 | }; 65 | } 66 | 67 | @Override 68 | public int size() { 69 | return 2; 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /src/heros/ZeroedFlowFunctions.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2012 Eric Bodden. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Eric Bodden - initial API and implementation 10 | ******************************************************************************/ 11 | package heros; 12 | 13 | import java.util.HashSet; 14 | import java.util.LinkedHashSet; 15 | import java.util.Set; 16 | 17 | public class ZeroedFlowFunctions implements FlowFunctions { 18 | 19 | protected final FlowFunctions delegate; 20 | protected final D zeroValue; 21 | 22 | public ZeroedFlowFunctions(FlowFunctions delegate, D zeroValue) { 23 | this.delegate = delegate; 24 | this.zeroValue = zeroValue; 25 | } 26 | 27 | public FlowFunction getNormalFlowFunction(N curr, N succ) { 28 | return new ZeroedFlowFunction(delegate.getNormalFlowFunction(curr, succ)); 29 | } 30 | 31 | public FlowFunction getCallFlowFunction(N callStmt, M destinationMethod) { 32 | return new ZeroedFlowFunction(delegate.getCallFlowFunction(callStmt, destinationMethod)); 33 | } 34 | 35 | public FlowFunction getReturnFlowFunction(N callSite, M calleeMethod, N exitStmt, N returnSite) { 36 | return new ZeroedFlowFunction(delegate.getReturnFlowFunction(callSite, calleeMethod, exitStmt, returnSite)); 37 | } 38 | 39 | public FlowFunction getCallToReturnFlowFunction(N callSite, N returnSite) { 40 | return new ZeroedFlowFunction(delegate.getCallToReturnFlowFunction(callSite, returnSite)); 41 | } 42 | 43 | protected class ZeroedFlowFunction implements FlowFunction { 44 | 45 | protected FlowFunction del; 46 | 47 | private ZeroedFlowFunction(FlowFunction del) { 48 | this.del = del; 49 | } 50 | 51 | @Override 52 | public Set computeTargets(D source) { 53 | if(source==zeroValue) { 54 | HashSet res = new LinkedHashSet(del.computeTargets(source)); 55 | res.add(zeroValue); 56 | return res; 57 | } else { 58 | return del.computeTargets(source); 59 | } 60 | } 61 | 62 | } 63 | 64 | 65 | } 66 | -------------------------------------------------------------------------------- /src/heros/edgefunc/AllBottom.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2012 Eric Bodden. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Eric Bodden - initial API and implementation 10 | ******************************************************************************/ 11 | package heros.edgefunc; 12 | 13 | import heros.EdgeFunction; 14 | import heros.solver.IFDSSolver; 15 | 16 | 17 | /** 18 | * This class implements an edge function that maps every input to the stated bottom element. This class is normally useful only 19 | * in the context of an {@link IFDSSolver}, which uses AllBottom to model reachability. Consequently, this class should normally not be useful 20 | * in the context of custom IDE problems. 21 | * 22 | * @author Eric Bodden 23 | * 24 | * @param 25 | */ 26 | public class AllBottom implements EdgeFunction { 27 | 28 | private final V bottomElement; 29 | 30 | public AllBottom(V bottomElement){ 31 | this.bottomElement = bottomElement; 32 | } 33 | 34 | public V computeTarget(V source) { 35 | return bottomElement; 36 | } 37 | 38 | public EdgeFunction composeWith(EdgeFunction secondFunction) { 39 | //note: this only makes sense within IFDS, see here: 40 | //https://github.com/Sable/heros/issues/37 41 | if (secondFunction instanceof EdgeIdentity) 42 | return this; 43 | return secondFunction; 44 | } 45 | 46 | public EdgeFunction meetWith(EdgeFunction otherFunction) { 47 | if(otherFunction == this || otherFunction.equalTo(this)) return this; 48 | if(otherFunction instanceof AllTop) { 49 | return this; 50 | } 51 | if(otherFunction instanceof EdgeIdentity) { 52 | return this; 53 | } 54 | throw new IllegalStateException("unexpected edge function: "+otherFunction); 55 | } 56 | 57 | public boolean equalTo(EdgeFunction other) { 58 | if(other instanceof AllBottom) { 59 | @SuppressWarnings("rawtypes") 60 | AllBottom allBottom = (AllBottom) other; 61 | return allBottom.bottomElement.equals(bottomElement); 62 | } 63 | return false; 64 | } 65 | 66 | public String toString() { 67 | return "allbottom"; 68 | } 69 | 70 | } 71 | -------------------------------------------------------------------------------- /src/heros/edgefunc/AllTop.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2012 Eric Bodden. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Eric Bodden - initial API and implementation 10 | ******************************************************************************/ 11 | package heros.edgefunc; 12 | 13 | import heros.EdgeFunction; 14 | import heros.solver.IFDSSolver; 15 | 16 | 17 | /** 18 | * This is an internal class implementing an edge function for use in {@link IFDSSolver}. 19 | * This edge function sets everything to the top value. 20 | * 21 | * @author Eric Bodden 22 | * 23 | * @param 24 | */ 25 | public class AllTop implements EdgeFunction { 26 | 27 | private final V topElement; 28 | 29 | public AllTop(V topElement){ 30 | this.topElement = topElement; 31 | } 32 | 33 | public V computeTarget(V source) { 34 | return topElement; 35 | } 36 | 37 | public EdgeFunction composeWith(EdgeFunction secondFunction) { 38 | return this; 39 | } 40 | 41 | public EdgeFunction meetWith(EdgeFunction otherFunction) { 42 | return otherFunction; 43 | } 44 | 45 | public boolean equalTo(EdgeFunction other) { 46 | if(other instanceof AllTop) { 47 | @SuppressWarnings("rawtypes") 48 | AllTop allTop = (AllTop) other; 49 | return allTop.topElement.equals(topElement); 50 | } 51 | return false; 52 | } 53 | 54 | public String toString() { 55 | return "alltop"; 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /src/heros/edgefunc/EdgeIdentity.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2012 Eric Bodden. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Eric Bodden - initial API and implementation 10 | ******************************************************************************/ 11 | package heros.edgefunc; 12 | 13 | import heros.EdgeFunction; 14 | 15 | /** 16 | * The identity function on graph edges 17 | * @param The type of values to be computed along flow edges. 18 | */ 19 | public class EdgeIdentity implements EdgeFunction { 20 | 21 | @SuppressWarnings("rawtypes") 22 | private final static EdgeIdentity instance = new EdgeIdentity(); 23 | 24 | private EdgeIdentity(){} //use v() instead 25 | 26 | public V computeTarget(V source) { 27 | return source; 28 | } 29 | 30 | public EdgeFunction composeWith(EdgeFunction secondFunction) { 31 | return secondFunction; 32 | } 33 | 34 | public EdgeFunction meetWith(EdgeFunction otherFunction) { 35 | if(otherFunction == this || otherFunction.equalTo(this)) return this; 36 | if(otherFunction instanceof AllBottom) { 37 | return otherFunction; 38 | } 39 | if(otherFunction instanceof AllTop) { 40 | return this; 41 | } 42 | //do not know how to meet; hence ask other function to decide on this 43 | return otherFunction.meetWith(this); 44 | } 45 | 46 | public boolean equalTo(EdgeFunction other) { 47 | //singleton 48 | return other==this; 49 | } 50 | 51 | @SuppressWarnings("unchecked") 52 | public static EdgeIdentity v() { 53 | return instance; 54 | } 55 | 56 | public String toString() { 57 | return "id"; 58 | } 59 | 60 | 61 | } 62 | -------------------------------------------------------------------------------- /src/heros/fieldsens/AccessPathHandler.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2015 Johannes Lerch. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Johannes Lerch - initial API and implementation 10 | ******************************************************************************/ 11 | package heros.fieldsens; 12 | 13 | import heros.fieldsens.FlowFunction.ConstrainedFact; 14 | import heros.fieldsens.FlowFunction.ReadFieldConstraint; 15 | import heros.fieldsens.FlowFunction.WriteFieldConstraint; 16 | import heros.fieldsens.structs.WrappedFact; 17 | 18 | public class AccessPathHandler { 19 | 20 | private AccessPath accessPath; 21 | private Resolver resolver; 22 | private Debugger debugger; 23 | 24 | public AccessPathHandler(AccessPath accessPath, Resolver resolver, Debugger debugger) { 25 | this.accessPath = accessPath; 26 | this.resolver = resolver; 27 | this.debugger = debugger; 28 | } 29 | 30 | public boolean canRead(Field field) { 31 | return accessPath.canRead(field); 32 | } 33 | 34 | public boolean mayCanRead(Field field) { 35 | return accessPath.canRead(field) || (accessPath.hasEmptyAccessPath() && !accessPath.isAccessInExclusions(field)); 36 | } 37 | 38 | public boolean mayBeEmpty() { 39 | return accessPath.hasEmptyAccessPath(); 40 | } 41 | 42 | public ConstrainedFact generate(Fact fact) { 43 | return new ConstrainedFact(new WrappedFact(fact, accessPath, resolver)); 44 | } 45 | 46 | public ConstrainedFact generateWithEmptyAccessPath(Fact fact, ZeroHandler zeroHandler) { 47 | return new ConstrainedFact(new WrappedFact(fact, new AccessPath(), new ZeroCallEdgeResolver(resolver.analyzer, zeroHandler, debugger))); 48 | } 49 | 50 | public ResultBuilder prepend(final Field field) { 51 | return new ResultBuilder() { 52 | @Override 53 | public ConstrainedFact generate(Fact fact) { 54 | return new ConstrainedFact(new WrappedFact(fact, accessPath.prepend(field), resolver)); 55 | } 56 | }; 57 | } 58 | 59 | public ResultBuilder read(final Field field) { 60 | if(mayCanRead(field)) { 61 | return new ResultBuilder() { 62 | @Override 63 | public ConstrainedFact generate(Fact fact) { 64 | if(canRead(field)) 65 | return new ConstrainedFact(new WrappedFact(fact, accessPath.removeFirst(), resolver)); 66 | else 67 | return new ConstrainedFact(new WrappedFact(fact, new AccessPath(), resolver), new ReadFieldConstraint(field)); 68 | } 69 | }; 70 | } 71 | else 72 | throw new IllegalArgumentException("Cannot read field "+field); 73 | } 74 | 75 | public ResultBuilder overwrite(final Field field) { 76 | if(mayBeEmpty()) 77 | return new ResultBuilder() { 78 | @SuppressWarnings("unchecked") 79 | @Override 80 | public ConstrainedFact generate(Fact fact) { 81 | if(accessPath.isAccessInExclusions(field)) 82 | return new ConstrainedFact(new WrappedFact(fact, accessPath, resolver)); 83 | else 84 | return new ConstrainedFact(new WrappedFact(fact, accessPath.appendExcludedFieldReference(field), resolver), new WriteFieldConstraint(field)); 85 | } 86 | }; 87 | else 88 | throw new IllegalArgumentException("Cannot write field "+field); 89 | } 90 | 91 | public static interface ResultBuilder { 92 | public ConstrainedFact generate(FactAbstraction fact); 93 | } 94 | 95 | } 96 | -------------------------------------------------------------------------------- /src/heros/fieldsens/BiDiFieldSensitiveIFDSSolver.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2015 Johannes Lerch. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Johannes Lerch - initial API and implementation 10 | ******************************************************************************/ 11 | package heros.fieldsens; 12 | 13 | 14 | import heros.InterproceduralCFG; 15 | import heros.fieldsens.SourceStmtAnnotatedMethodAnalyzer.Synchronizer; 16 | 17 | import java.util.Set; 18 | 19 | import com.google.common.collect.HashMultimap; 20 | import com.google.common.collect.Sets; 21 | 22 | 23 | public class BiDiFieldSensitiveIFDSSolver> { 24 | 25 | private FieldSensitiveIFDSSolver forwardSolver; 26 | private FieldSensitiveIFDSSolver backwardSolver; 27 | private Scheduler scheduler; 28 | private SynchronizerImpl forwardSynchronizer; 29 | private SynchronizerImpl backwardSynchronizer; 30 | 31 | public BiDiFieldSensitiveIFDSSolver(IFDSTabulationProblem forwardProblem, 32 | IFDSTabulationProblem backwardProblem, 33 | FactMergeHandler factHandler, 34 | Debugger debugger, 35 | Scheduler scheduler) { 36 | 37 | this.scheduler = scheduler; 38 | 39 | forwardSynchronizer = new SynchronizerImpl(); 40 | backwardSynchronizer = new SynchronizerImpl(); 41 | forwardSynchronizer.otherSynchronizer = backwardSynchronizer; 42 | backwardSynchronizer.otherSynchronizer = forwardSynchronizer; 43 | 44 | forwardSolver = createSolver(forwardProblem, factHandler, debugger, forwardSynchronizer); 45 | backwardSolver = createSolver(backwardProblem, factHandler, debugger, backwardSynchronizer); 46 | } 47 | 48 | private FieldSensitiveIFDSSolver createSolver(IFDSTabulationProblem problem, 49 | FactMergeHandler factHandler, Debugger debugger, final SynchronizerImpl synchronizer) { 50 | return new FieldSensitiveIFDSSolver(problem, factHandler, debugger, scheduler) { 51 | @Override 52 | protected MethodAnalyzer createMethodAnalyzer(Method method) { 53 | return new SourceStmtAnnotatedMethodAnalyzer(method, context, synchronizer, debugger); 54 | } 55 | }; 56 | } 57 | 58 | private static class SynchronizerImpl implements Synchronizer { 59 | 60 | private SynchronizerImpl otherSynchronizer; 61 | private Set leakedSources = Sets.newHashSet(); 62 | private HashMultimap pausedJobs = HashMultimap.create(); 63 | 64 | @Override 65 | public void synchronizeOnStmt(Stmt stmt, Runnable job) { 66 | leakedSources.add(stmt); 67 | if(otherSynchronizer.leakedSources.contains(stmt)) { 68 | job.run(); 69 | for(Runnable runnable : otherSynchronizer.pausedJobs.get(stmt)) { 70 | runnable.run(); 71 | } 72 | otherSynchronizer.pausedJobs.removeAll(stmt); 73 | } 74 | else { 75 | pausedJobs.put(stmt, job); 76 | } 77 | } 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/heros/fieldsens/CallEdge.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2014 Johannes Lerch. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Johannes Lerch - initial API and implementation 10 | ******************************************************************************/ 11 | package heros.fieldsens; 12 | 13 | import heros.fieldsens.AccessPath.Delta; 14 | import heros.fieldsens.AccessPath.PrefixTestResult; 15 | import heros.fieldsens.structs.DeltaConstraint; 16 | import heros.fieldsens.structs.WrappedFact; 17 | import heros.fieldsens.structs.WrappedFactAtStatement; 18 | 19 | public class CallEdge { 20 | 21 | private WrappedFact calleeSourceFact; 22 | private PerAccessPathMethodAnalyzer callerAnalyzer; 23 | private WrappedFactAtStatement factAtCallSite; 24 | 25 | public CallEdge(PerAccessPathMethodAnalyzer callerAnalyzer, 26 | WrappedFactAtStatement factAtCallSite, 27 | WrappedFact calleeSourceFact) { 28 | this.callerAnalyzer = callerAnalyzer; 29 | this.factAtCallSite = factAtCallSite; 30 | this.calleeSourceFact = calleeSourceFact; 31 | } 32 | 33 | public WrappedFact getCalleeSourceFact() { 34 | return calleeSourceFact; 35 | } 36 | 37 | public WrappedFact getCallerCallSiteFact() { 38 | return factAtCallSite.getWrappedFact(); 39 | } 40 | 41 | public WrappedFact getCallerSourceFact() { 42 | return callerAnalyzer.wrappedSource(); 43 | } 44 | 45 | public Stmt getCallSite() { 46 | return factAtCallSite.getStatement(); 47 | } 48 | 49 | public PerAccessPathMethodAnalyzer getCallerAnalyzer() { 50 | return callerAnalyzer; 51 | } 52 | 53 | public void registerInterestCallback(final PerAccessPathMethodAnalyzer interestedAnalyzer) { 54 | final Delta delta = calleeSourceFact.getAccessPath().getDeltaTo(interestedAnalyzer.getAccessPath()); 55 | 56 | if(!factAtCallSite.canDeltaBeApplied(delta)) 57 | return; 58 | 59 | factAtCallSite.getWrappedFact().getResolver().resolve(new DeltaConstraint(delta), new InterestCallback() { 60 | 61 | @Override 62 | public void interest(PerAccessPathMethodAnalyzer analyzer, Resolver resolver) { 63 | WrappedFact calleeSourceFactWithDelta = new WrappedFact(calleeSourceFact.getFact(), delta.applyTo(calleeSourceFact.getAccessPath()), resolver); 64 | assert interestedAnalyzer.getAccessPath().isPrefixOf(calleeSourceFactWithDelta.getAccessPath()) == PrefixTestResult.GUARANTEED_PREFIX; 65 | 66 | CallEdge newCallEdge = new CallEdge(analyzer, 67 | new WrappedFactAtStatement(factAtCallSite.getStatement(), 68 | new WrappedFact(factAtCallSite.getWrappedFact().getFact(), 69 | delta.applyTo(factAtCallSite.getWrappedFact().getAccessPath()), 70 | resolver)), 71 | calleeSourceFactWithDelta); 72 | 73 | if (resolver instanceof ZeroCallEdgeResolver) { 74 | interestedAnalyzer.getCallEdgeResolver().incomingEdges.add(newCallEdge); 75 | interestedAnalyzer.getCallEdgeResolver().interest(((ZeroCallEdgeResolver) resolver).copyWithAnalyzer(interestedAnalyzer)); 76 | interestedAnalyzer.getCallEdgeResolver().processIncomingGuaranteedPrefix(newCallEdge); 77 | } 78 | else 79 | interestedAnalyzer.addIncomingEdge(newCallEdge); 80 | } 81 | 82 | @Override 83 | public void canBeResolvedEmpty() { 84 | callerAnalyzer.getCallEdgeResolver().resolve(new DeltaConstraint(delta), this); 85 | } 86 | }); 87 | } 88 | 89 | @Override 90 | public String toString() { 91 | return "[IncEdge CSite:"+getCallSite()+", Caller-Edge: "+getCallerSourceFact()+"->"+getCallerCallSiteFact()+", CalleeFact: "+calleeSourceFact+"]"; 92 | } 93 | 94 | @Override 95 | public int hashCode() { 96 | final int prime = 31; 97 | int result = 1; 98 | result = prime * result + ((calleeSourceFact == null) ? 0 : calleeSourceFact.hashCode()); 99 | result = prime * result + ((callerAnalyzer == null) ? 0 : callerAnalyzer.hashCode()); 100 | result = prime * result + ((factAtCallSite == null) ? 0 : factAtCallSite.hashCode()); 101 | return result; 102 | } 103 | 104 | @Override 105 | public boolean equals(Object obj) { 106 | if (this == obj) 107 | return true; 108 | if (obj == null) 109 | return false; 110 | if (getClass() != obj.getClass()) 111 | return false; 112 | CallEdge other = (CallEdge) obj; 113 | if (calleeSourceFact == null) { 114 | if (other.calleeSourceFact != null) 115 | return false; 116 | } else if (!calleeSourceFact.equals(other.calleeSourceFact)) 117 | return false; 118 | if (callerAnalyzer == null) { 119 | if (other.callerAnalyzer != null) 120 | return false; 121 | } else if (!callerAnalyzer.equals(other.callerAnalyzer)) 122 | return false; 123 | if (factAtCallSite == null) { 124 | if (other.factAtCallSite != null) 125 | return false; 126 | } else if (!factAtCallSite.equals(other.factAtCallSite)) 127 | return false; 128 | return true; 129 | } 130 | 131 | 132 | } 133 | -------------------------------------------------------------------------------- /src/heros/fieldsens/CallEdgeResolver.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2015 Johannes Lerch. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Johannes Lerch - initial API and implementation 10 | ******************************************************************************/ 11 | package heros.fieldsens; 12 | 13 | import heros.fieldsens.structs.WrappedFactAtStatement; 14 | 15 | import com.google.common.collect.Lists; 16 | 17 | 18 | class CallEdgeResolver extends ResolverTemplate> { 19 | 20 | public CallEdgeResolver(PerAccessPathMethodAnalyzer analyzer, Debugger debugger) { 21 | this(analyzer, debugger, null); 22 | } 23 | 24 | public CallEdgeResolver(PerAccessPathMethodAnalyzer analyzer, Debugger debugger, CallEdgeResolver parent) { 25 | super(analyzer, analyzer.getAccessPath(), parent, debugger); 26 | } 27 | 28 | @Override 29 | protected AccessPath getAccessPathOf(CallEdge inc) { 30 | return inc.getCalleeSourceFact().getAccessPath(); 31 | } 32 | 33 | @Override 34 | protected void processIncomingGuaranteedPrefix(CallEdge inc) { 35 | analyzer.applySummaries(inc); 36 | } 37 | 38 | @Override 39 | protected void processIncomingPotentialPrefix(CallEdge inc) { 40 | lock(); 41 | inc.registerInterestCallback(analyzer); 42 | unlock(); 43 | } 44 | 45 | @Override 46 | protected ResolverTemplate> createNestedResolver(AccessPath newAccPath) { 47 | return analyzer.createWithAccessPath(newAccPath).getCallEdgeResolver(); 48 | } 49 | 50 | public void applySummaries(WrappedFactAtStatement factAtStmt) { 51 | for(CallEdge incEdge : Lists.newLinkedList(incomingEdges)) { 52 | analyzer.applySummary(incEdge, factAtStmt); 53 | } 54 | } 55 | 56 | @Override 57 | public String toString() { 58 | return "<"+analyzer.getAccessPath()+":"+analyzer.getMethod()+">"; 59 | } 60 | 61 | @Override 62 | protected void log(String message) { 63 | analyzer.log(message); 64 | } 65 | 66 | public boolean hasIncomingEdges() { 67 | return !incomingEdges.isEmpty(); 68 | } 69 | 70 | 71 | } -------------------------------------------------------------------------------- /src/heros/fieldsens/Context.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2015 Johannes Lerch. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Johannes Lerch - initial API and implementation 10 | ******************************************************************************/ 11 | package heros.fieldsens; 12 | 13 | import heros.InterproceduralCFG; 14 | 15 | public abstract class Context { 16 | 17 | public final InterproceduralCFG icfg; 18 | public final Scheduler scheduler; 19 | public final Fact zeroValue; 20 | public final boolean followReturnsPastSeeds; 21 | public final FactMergeHandler factHandler; 22 | public final ZeroHandler zeroHandler; 23 | public final FlowFunctions flowFunctions; 24 | 25 | Context(IFDSTabulationProblem> tabulationProblem, 26 | Scheduler scheduler, FactMergeHandler factHandler) { 27 | this.icfg = tabulationProblem.interproceduralCFG(); 28 | this.flowFunctions = tabulationProblem.flowFunctions(); 29 | this.scheduler = scheduler; 30 | this.zeroValue = tabulationProblem.zeroValue(); 31 | this.followReturnsPastSeeds = tabulationProblem.followReturnsPastSeeds(); 32 | this.factHandler = factHandler; 33 | this.zeroHandler = tabulationProblem.zeroHandler(); 34 | } 35 | 36 | public abstract MethodAnalyzer getAnalyzer(Method method); 37 | } 38 | -------------------------------------------------------------------------------- /src/heros/fieldsens/ControlFlowJoinResolver.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2015 Johannes Lerch. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Johannes Lerch - initial API and implementation 10 | ******************************************************************************/ 11 | package heros.fieldsens; 12 | 13 | import heros.fieldsens.AccessPath.Delta; 14 | import heros.fieldsens.structs.DeltaConstraint; 15 | import heros.fieldsens.structs.WrappedFact; 16 | import heros.fieldsens.structs.WrappedFactAtStatement; 17 | 18 | public class ControlFlowJoinResolver extends ResolverTemplate> { 19 | 20 | private Stmt joinStmt; 21 | private boolean propagated = false; 22 | private Fact sourceFact; 23 | private FactMergeHandler factMergeHandler; 24 | 25 | public ControlFlowJoinResolver(FactMergeHandler factMergeHandler, PerAccessPathMethodAnalyzer analyzer, Stmt joinStmt, Debugger debugger) { 26 | this(factMergeHandler, analyzer, joinStmt, null, new AccessPath(), debugger, null); 27 | this.factMergeHandler = factMergeHandler; 28 | propagated=false; 29 | } 30 | 31 | private ControlFlowJoinResolver(FactMergeHandler factMergeHandler, PerAccessPathMethodAnalyzer analyzer, 32 | Stmt joinStmt, Fact sourceFact, AccessPath resolvedAccPath, Debugger debugger, ControlFlowJoinResolver parent) { 33 | super(analyzer, resolvedAccPath, parent, debugger); 34 | this.factMergeHandler = factMergeHandler; 35 | this.joinStmt = joinStmt; 36 | this.sourceFact = sourceFact; 37 | propagated=true; 38 | } 39 | 40 | @Override 41 | protected AccessPath getAccessPathOf(WrappedFact inc) { 42 | return inc.getAccessPath(); 43 | } 44 | 45 | protected void processIncomingGuaranteedPrefix(heros.fieldsens.structs.WrappedFact fact) { 46 | if(propagated) { 47 | factMergeHandler.merge(sourceFact, fact.getFact()); 48 | } 49 | else { 50 | propagated=true; 51 | sourceFact = fact.getFact(); 52 | analyzer.processFlowFromJoinStmt(new WrappedFactAtStatement(joinStmt, new WrappedFact( 53 | fact.getFact(), new AccessPath(), this))); 54 | } 55 | }; 56 | 57 | private boolean isNullOrCallEdgeResolver(Resolver resolver) { 58 | if(resolver == null) 59 | return true; 60 | if(resolver instanceof CallEdgeResolver) { 61 | return !(resolver instanceof ZeroCallEdgeResolver); 62 | } 63 | return false; 64 | } 65 | 66 | @Override 67 | protected void processIncomingPotentialPrefix(final WrappedFact fact) { 68 | if(isNullOrCallEdgeResolver(fact.getResolver())) { 69 | canBeResolvedEmpty(); 70 | } 71 | else { 72 | lock(); 73 | Delta delta = fact.getAccessPath().getDeltaTo(resolvedAccessPath); 74 | fact.getResolver().resolve(new DeltaConstraint(delta), new InterestCallback() { 75 | @Override 76 | public void interest(PerAccessPathMethodAnalyzer analyzer, 77 | Resolver resolver) { 78 | ControlFlowJoinResolver.this.interest(resolver); 79 | } 80 | 81 | @Override 82 | public void canBeResolvedEmpty() { 83 | ControlFlowJoinResolver.this.canBeResolvedEmpty(); 84 | } 85 | }); 86 | unlock(); 87 | } 88 | } 89 | 90 | @Override 91 | protected ResolverTemplate> createNestedResolver(AccessPath newAccPath) { 92 | return new ControlFlowJoinResolver(factMergeHandler, analyzer, joinStmt, sourceFact, newAccPath, debugger, this); 93 | } 94 | 95 | @Override 96 | protected void log(String message) { 97 | analyzer.log("Join Stmt "+toString()+": "+message); 98 | } 99 | 100 | @Override 101 | public String toString() { 102 | return "<"+resolvedAccessPath+":"+joinStmt+" in "+analyzer.getMethod()+">"; 103 | } 104 | 105 | public Stmt getJoinStmt() { 106 | return joinStmt; 107 | } 108 | } 109 | -------------------------------------------------------------------------------- /src/heros/fieldsens/Debugger.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2015 Johannes Lerch. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Johannes Lerch - initial API and implementation 10 | ******************************************************************************/ 11 | package heros.fieldsens; 12 | 13 | import heros.InterproceduralCFG; 14 | import heros.fieldsens.FlowFunction.Constraint; 15 | import heros.fieldsens.structs.WrappedFactAtStatement; 16 | 17 | public interface Debugger { 18 | 19 | public void setICFG(InterproceduralCFG icfg); 20 | public void initialSeed(Stmt stmt); 21 | public void edgeTo(PerAccessPathMethodAnalyzer analyzer, WrappedFactAtStatement factAtStmt); 22 | public void newResolver(PerAccessPathMethodAnalyzer analyzer, Resolver resolver); 23 | public void newJob(PerAccessPathMethodAnalyzer analyzer, WrappedFactAtStatement factAtStmt); 24 | public void jobStarted(PerAccessPathMethodAnalyzer analyzer, WrappedFactAtStatement factAtStmt); 25 | public void jobFinished(PerAccessPathMethodAnalyzer analyzer, WrappedFactAtStatement factAtStmt); 26 | public void askedToResolve(Resolver resolver, Constraint constraint); 27 | 28 | public static class NullDebugger implements Debugger { 29 | 30 | @Override 31 | public void setICFG(InterproceduralCFG icfg) { 32 | 33 | } 34 | 35 | @Override 36 | public void initialSeed(Stmt stmt) { 37 | 38 | } 39 | 40 | @Override 41 | public void edgeTo(PerAccessPathMethodAnalyzer analyzer, 42 | WrappedFactAtStatement factAtStmt) { 43 | 44 | } 45 | 46 | @Override 47 | public void newResolver(PerAccessPathMethodAnalyzer analyzer, Resolver resolver) { 48 | 49 | } 50 | 51 | @Override 52 | public void newJob(PerAccessPathMethodAnalyzer analyzer, 53 | WrappedFactAtStatement factAtStmt) { 54 | 55 | } 56 | 57 | @Override 58 | public void jobStarted(PerAccessPathMethodAnalyzer analyzer, 59 | WrappedFactAtStatement factAtStmt) { 60 | 61 | } 62 | 63 | @Override 64 | public void jobFinished(PerAccessPathMethodAnalyzer analyzer, 65 | WrappedFactAtStatement factAtStmt) { 66 | 67 | } 68 | 69 | @Override 70 | public void askedToResolve(Resolver resolver, Constraint constraint) { 71 | 72 | } 73 | 74 | } 75 | } -------------------------------------------------------------------------------- /src/heros/fieldsens/FactMergeHandler.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2015 Johannes Lerch. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Johannes Lerch - initial API and implementation 10 | ******************************************************************************/ 11 | package heros.fieldsens; 12 | 13 | public interface FactMergeHandler { 14 | 15 | /** 16 | * Called when propagating a Fact to a statement at which an equal Fact was already propagated to. 17 | * @param previousFact The Fact instance that was propagated to the statement first. 18 | * @param currentFact The Fact that was propagated to the statement last. 19 | */ 20 | void merge(Fact previousFact, Fact currentFact); 21 | 22 | /** 23 | * Called on Facts being propagated over a return edge. Via this method context can be restored that was abstracted when propagating over the call edge. 24 | * @param factAtReturnSite The fact being propagated over the return edge. 25 | * @param factAtCallSite The Fact that was present at the call site, i.e., the Fact used as input to the call flow function. 26 | */ 27 | void restoreCallingContext(Fact factAtReturnSite, Fact factAtCallSite); 28 | } 29 | -------------------------------------------------------------------------------- /src/heros/fieldsens/FieldSensitiveIFDSSolver.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2014 Johannes Lerch, Johannes Spaeth. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Johannes Lerch, Johannes Spaeth - initial API and implementation 10 | ******************************************************************************/ 11 | 12 | package heros.fieldsens; 13 | 14 | import heros.InterproceduralCFG; 15 | import heros.utilities.DefaultValueMap; 16 | 17 | import java.util.Map.Entry; 18 | import java.util.Set; 19 | 20 | import org.slf4j.Logger; 21 | import org.slf4j.LoggerFactory; 22 | 23 | public class FieldSensitiveIFDSSolver> { 24 | 25 | protected static final Logger logger = LoggerFactory.getLogger(FieldSensitiveIFDSSolver.class); 26 | 27 | private DefaultValueMap> methodAnalyzers = new DefaultValueMap>() { 28 | @Override 29 | protected MethodAnalyzer createItem(M key) { 30 | return createMethodAnalyzer(key); 31 | } 32 | }; 33 | 34 | private IFDSTabulationProblem tabulationProblem; 35 | protected Context context; 36 | protected Debugger debugger; 37 | private Scheduler scheduler; 38 | 39 | public FieldSensitiveIFDSSolver(IFDSTabulationProblem tabulationProblem, FactMergeHandler factHandler, Debugger debugger, Scheduler scheduler) { 40 | this.tabulationProblem = tabulationProblem; 41 | this.scheduler = scheduler; 42 | this.debugger = debugger == null ? new Debugger.NullDebugger() : debugger; 43 | this.debugger.setICFG(tabulationProblem.interproceduralCFG()); 44 | context = initContext(tabulationProblem, factHandler); 45 | submitInitialSeeds(); 46 | } 47 | 48 | private Context initContext(IFDSTabulationProblem tabulationProblem, FactMergeHandler factHandler) { 49 | return new Context(tabulationProblem, scheduler, factHandler) { 50 | @Override 51 | public MethodAnalyzer getAnalyzer(M method) { 52 | if(method == null) 53 | throw new IllegalArgumentException("Method must be not null"); 54 | return methodAnalyzers.getOrCreate(method); 55 | } 56 | }; 57 | } 58 | 59 | protected MethodAnalyzer createMethodAnalyzer(M method) { 60 | return new MethodAnalyzerImpl(method, context, debugger); 61 | } 62 | 63 | /** 64 | * Schedules the processing of initial seeds, initiating the analysis. 65 | */ 66 | private void submitInitialSeeds() { 67 | for(Entry> seed: tabulationProblem.initialSeeds().entrySet()) { 68 | N startPoint = seed.getKey(); 69 | MethodAnalyzer analyzer = methodAnalyzers.getOrCreate(tabulationProblem.interproceduralCFG().getMethodOf(startPoint)); 70 | for(D val: seed.getValue()) { 71 | analyzer.addInitialSeed(startPoint, val); 72 | debugger.initialSeed(startPoint); 73 | } 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/heros/fieldsens/FlowFunctions.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2012 Eric Bodden. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Eric Bodden - initial API and implementation 10 | * Johannes Lerch, Johannes Spaeth - extension for field sensitivity 11 | ******************************************************************************/ 12 | package heros.fieldsens; 13 | 14 | 15 | /** 16 | * Classes implementing this interface provide a factory for a 17 | * range of flow functions used to compute which D-type values 18 | * are reachable along the program's control flow. 19 | * 20 | * @param 21 | * The type of nodes in the interprocedural control-flow graph. 22 | * Typically {@link Unit}. 23 | * @param 24 | * The type of data-flow facts to be computed by the tabulation 25 | * problem. 26 | * @param 27 | * The type of objects used to represent methods. Typically 28 | * {@link SootMethod}. 29 | */ 30 | public interface FlowFunctions { 31 | 32 | /** 33 | * Returns the flow function that computes the flow for a normal statement, 34 | * i.e., a statement that is neither a call nor an exit statement. 35 | * 36 | * @param curr 37 | * The current statement. 38 | */ 39 | public FlowFunction getNormalFlowFunction(Stmt curr); 40 | 41 | 42 | /** 43 | * Returns the flow function that computes the flow for a call statement. 44 | * 45 | * @param callStmt 46 | * The statement containing the invoke expression giving rise to 47 | * this call. 48 | * @param destinationMethod 49 | * The concrete target method for which the flow is computed. 50 | */ 51 | public FlowFunction getCallFlowFunction(Stmt callStmt, Method destinationMethod); 52 | 53 | /** 54 | * Returns the flow function that computes the flow for a an exit from a 55 | * method. An exit can be a return or an exceptional exit. 56 | * 57 | * @param callSite 58 | * One of all the call sites in the program that called the 59 | * method from which the exitStmt is actually returning. This 60 | * information can be exploited to compute a value that depends on 61 | * information from before the call. 62 | * Note: This value might be null if 63 | * using a tabulation problem with {@link IFDSTabulationProblem#followReturnsPastSeeds()} 64 | * returning true in a situation where the call graph 65 | * does not contain a caller for the method that is returned from. 66 | * @param calleeMethod 67 | * The method from which exitStmt returns. 68 | * @param exitStmt 69 | * The statement exiting the method, typically a return or throw 70 | * statement. 71 | * @param returnSite 72 | * One of the successor statements of the callSite. There may be 73 | * multiple successors in case of possible exceptional flow. This 74 | * method will be called for each such successor. 75 | * Note: This value might be null if 76 | * using a tabulation problem with {@link IFDSTabulationProblem#followReturnsPastSeeds()} 77 | * returning true in a situation where the call graph 78 | * does not contain a caller for the method that is returned from. 79 | * @return 80 | */ 81 | public FlowFunction getReturnFlowFunction(Stmt callSite, Method calleeMethod, Stmt exitStmt, Stmt returnSite); 82 | 83 | /** 84 | * Returns the flow function that computes the flow from a call site to a 85 | * successor statement just after the call. There may be multiple successors 86 | * in case of exceptional control flow. In this case this method will be 87 | * called for every such successor. Typically, one will propagate into a 88 | * method call, using {@link #getCallFlowFunction(Object, Object)}, only 89 | * such information that actually concerns the callee method. All other 90 | * information, e.g. information that cannot be modified by the call, is 91 | * passed along this call-return edge. 92 | * 93 | * @param callSite 94 | * The statement containing the invoke expression giving rise to 95 | * this call. 96 | * @param returnSite 97 | * The return site to which the information is propagated. For 98 | * exceptional flow, this may actually be the start of an 99 | * exception handler. 100 | */ 101 | public FlowFunction getCallToReturnFlowFunction(Stmt callSite, Stmt returnSite); 102 | 103 | 104 | 105 | } 106 | -------------------------------------------------------------------------------- /src/heros/fieldsens/IFDSTabulationProblem.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2012 Eric Bodden. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Eric Bodden - initial API and implementation 10 | ******************************************************************************/ 11 | package heros.fieldsens; 12 | 13 | import heros.InterproceduralCFG; 14 | import heros.SolverConfiguration; 15 | import heros.solver.IFDSSolver; 16 | import heros.solver.Pair; 17 | 18 | import java.util.Map; 19 | import java.util.Set; 20 | 21 | 22 | 23 | /** 24 | * A tabulation problem for solving in an {@link IFDSSolver} as described 25 | * by the Reps, Horwitz, Sagiv 1995 (RHS95) paper. 26 | * 27 | * @param The type of nodes in the interprocedural control-flow graph. Typically {@link Unit}. 28 | * @param The type of data-flow facts to be computed by the tabulation problem. 29 | * @param The type of objects used to represent methods. Typically {@link SootMethod}. 30 | * @param The type of inter-procedural control-flow graph being used. 31 | */ 32 | public interface IFDSTabulationProblem> extends SolverConfiguration { 33 | 34 | /** 35 | * Returns a set of flow functions. Those functions are used to compute data-flow facts 36 | * along the various kinds of control flows. 37 | * 38 | * NOTE: this method could be called many times. Implementations of this 39 | * interface should therefore cache the return value! 40 | */ 41 | FlowFunctions flowFunctions(); 42 | 43 | /** 44 | * Returns the interprocedural control-flow graph which this problem is computed over. 45 | * 46 | * NOTE: this method could be called many times. Implementations of this 47 | * interface should therefore cache the return value! 48 | */ 49 | I interproceduralCFG(); 50 | 51 | /** 52 | * Returns initial seeds to be used for the analysis. This is a mapping of statements to initial analysis facts. 53 | */ 54 | Map> initialSeeds(); 55 | 56 | /** 57 | * This must be a data-flow fact of type {@link D}, but must not 58 | * be part of the domain of data-flow facts. Typically this will be a 59 | * singleton object of type {@link D} that is used for nothing else. 60 | * It must holds that this object does not equals any object 61 | * within the domain. 62 | * 63 | * NOTE: this method could be called many times. Implementations of this 64 | * interface should therefore cache the return value! 65 | */ 66 | D zeroValue(); 67 | 68 | ZeroHandler zeroHandler(); 69 | 70 | } 71 | -------------------------------------------------------------------------------- /src/heros/fieldsens/InterestCallback.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2015 Johannes Lerch. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Johannes Lerch - initial API and implementation 10 | ******************************************************************************/ 11 | package heros.fieldsens; 12 | 13 | 14 | public interface InterestCallback { 15 | 16 | void interest(PerAccessPathMethodAnalyzer analyzer, Resolver resolver); 17 | 18 | void canBeResolvedEmpty(); 19 | } 20 | -------------------------------------------------------------------------------- /src/heros/fieldsens/MethodAnalyzer.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2015 Johannes Lerch. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Johannes Lerch - initial API and implementation 10 | ******************************************************************************/ 11 | package heros.fieldsens; 12 | 13 | import heros.fieldsens.structs.WrappedFactAtStatement; 14 | 15 | public interface MethodAnalyzer { 16 | 17 | public void addIncomingEdge(CallEdge incEdge); 18 | 19 | public void addInitialSeed(Stmt startPoint, Fact val); 20 | 21 | public void addUnbalancedReturnFlow(WrappedFactAtStatement target, Stmt callSite); 22 | } 23 | -------------------------------------------------------------------------------- /src/heros/fieldsens/MethodAnalyzerImpl.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2015 Johannes Lerch. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Johannes Lerch - initial API and implementation 10 | ******************************************************************************/ 11 | package heros.fieldsens; 12 | 13 | import heros.fieldsens.structs.WrappedFact; 14 | import heros.fieldsens.structs.WrappedFactAtStatement; 15 | import heros.utilities.DefaultValueMap; 16 | 17 | public class MethodAnalyzerImpl 18 | implements MethodAnalyzer { 19 | 20 | private Method method; 21 | private DefaultValueMap> perSourceAnalyzer = 22 | new DefaultValueMap>() { 23 | @Override 24 | protected PerAccessPathMethodAnalyzer createItem(Fact key) { 25 | return new PerAccessPathMethodAnalyzer(method, key, context, debugger); 26 | } 27 | }; 28 | private Context context; 29 | private Debugger debugger; 30 | 31 | MethodAnalyzerImpl(Method method, Context context, Debugger debugger) { 32 | this.method = method; 33 | this.context = context; 34 | this.debugger = debugger; 35 | } 36 | 37 | @Override 38 | public void addIncomingEdge(CallEdge incEdge) { 39 | WrappedFact calleeSourceFact = incEdge.getCalleeSourceFact(); 40 | PerAccessPathMethodAnalyzer analyzer = perSourceAnalyzer.getOrCreate(calleeSourceFact.getFact()); 41 | analyzer.addIncomingEdge(incEdge); 42 | } 43 | 44 | @Override 45 | public void addInitialSeed(Stmt startPoint, Fact val) { 46 | perSourceAnalyzer.getOrCreate(val).addInitialSeed(startPoint); 47 | } 48 | 49 | @Override 50 | public void addUnbalancedReturnFlow(WrappedFactAtStatement target, Stmt callSite) { 51 | perSourceAnalyzer.getOrCreate(context.zeroValue).scheduleUnbalancedReturnEdgeTo(target); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/heros/fieldsens/Resolver.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2015 Johannes Lerch. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Johannes Lerch - initial API and implementation 10 | ******************************************************************************/ 11 | package heros.fieldsens; 12 | 13 | import heros.fieldsens.FlowFunction.Constraint; 14 | 15 | import java.util.List; 16 | import java.util.Set; 17 | 18 | import com.google.common.collect.Lists; 19 | import com.google.common.collect.Sets; 20 | 21 | public abstract class Resolver { 22 | 23 | private Set> interest = Sets.newHashSet(); 24 | private List> interestCallbacks = Lists.newLinkedList(); 25 | protected PerAccessPathMethodAnalyzer analyzer; 26 | private boolean canBeResolvedEmpty = false; 27 | 28 | public Resolver(PerAccessPathMethodAnalyzer analyzer) { 29 | this.analyzer = analyzer; 30 | } 31 | 32 | public abstract void resolve(Constraint constraint, InterestCallback callback); 33 | 34 | public void interest(Resolver resolver) { 35 | if(!interest.add(resolver)) 36 | return; 37 | 38 | log("Interest given by: "+resolver); 39 | for(InterestCallback callback : Lists.newLinkedList(interestCallbacks)) { 40 | callback.interest(analyzer, resolver); 41 | } 42 | } 43 | 44 | protected void canBeResolvedEmpty() { 45 | if(canBeResolvedEmpty) 46 | return; 47 | 48 | canBeResolvedEmpty = true; 49 | for(InterestCallback callback : Lists.newLinkedList(interestCallbacks)) { 50 | callback.canBeResolvedEmpty(); 51 | } 52 | } 53 | 54 | public boolean isInterestGiven() { 55 | return !interest.isEmpty(); 56 | } 57 | 58 | protected void registerCallback(InterestCallback callback) { 59 | if(!interest.isEmpty()) { 60 | for(Resolver resolver : Lists.newLinkedList(interest)) 61 | callback.interest(analyzer, resolver); 62 | } 63 | log("Callback registered"); 64 | interestCallbacks.add(callback); 65 | 66 | if(canBeResolvedEmpty) 67 | callback.canBeResolvedEmpty(); 68 | } 69 | 70 | protected abstract void log(String message); 71 | 72 | } 73 | -------------------------------------------------------------------------------- /src/heros/fieldsens/ResolverTemplate.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2015 Johannes Lerch. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Johannes Lerch - initial API and implementation 10 | ******************************************************************************/ 11 | package heros.fieldsens; 12 | 13 | import java.util.Map; 14 | import java.util.Set; 15 | 16 | import com.google.common.collect.Lists; 17 | import com.google.common.collect.Maps; 18 | import com.google.common.collect.Sets; 19 | 20 | import heros.fieldsens.AccessPath.PrefixTestResult; 21 | import heros.fieldsens.FlowFunction.Constraint; 22 | 23 | 24 | public abstract class ResolverTemplate extends Resolver { 25 | 26 | private boolean recursionLock = false; 27 | protected Set incomingEdges = Sets.newHashSet(); 28 | private ResolverTemplate parent; 29 | private Map, ResolverTemplate> nestedResolvers = Maps.newHashMap(); 30 | private Map, ResolverTemplate> allResolversInExclHierarchy; 31 | protected AccessPath resolvedAccessPath; 32 | protected Debugger debugger; 33 | 34 | public ResolverTemplate(PerAccessPathMethodAnalyzer analyzer, 35 | AccessPath resolvedAccessPath, 36 | ResolverTemplate parent, 37 | Debugger debugger) { 38 | super(analyzer); 39 | this.resolvedAccessPath = resolvedAccessPath; 40 | this.parent = parent; 41 | this.debugger = debugger; 42 | if(parent == null || resolvedAccessPath.getExclusions().isEmpty()) { 43 | allResolversInExclHierarchy = Maps.newHashMap(); 44 | } 45 | else { 46 | allResolversInExclHierarchy = parent.allResolversInExclHierarchy; 47 | } 48 | debugger.newResolver(analyzer, this); 49 | } 50 | 51 | protected boolean isLocked() { 52 | if(recursionLock) 53 | return true; 54 | if(parent == null) 55 | return false; 56 | return parent.isLocked(); 57 | } 58 | 59 | protected void lock() { 60 | recursionLock = true; 61 | } 62 | 63 | protected void unlock() { 64 | recursionLock = false; 65 | } 66 | 67 | protected abstract AccessPath getAccessPathOf(Incoming inc); 68 | 69 | public void addIncoming(Incoming inc) { 70 | if(resolvedAccessPath.isPrefixOf(getAccessPathOf(inc)) == PrefixTestResult.GUARANTEED_PREFIX) { 71 | log("Incoming Edge: "+inc); 72 | if(!incomingEdges.add(inc)) 73 | return; 74 | 75 | interest(this); 76 | 77 | for(ResolverTemplate nestedResolver : Lists.newLinkedList(nestedResolvers.values())) { 78 | nestedResolver.addIncoming(inc); 79 | } 80 | 81 | processIncomingGuaranteedPrefix(inc); 82 | } 83 | else if(getAccessPathOf(inc).isPrefixOf(resolvedAccessPath).atLeast(PrefixTestResult.POTENTIAL_PREFIX)) { 84 | processIncomingPotentialPrefix(inc); 85 | } 86 | } 87 | 88 | protected abstract void processIncomingPotentialPrefix(Incoming inc); 89 | 90 | protected abstract void processIncomingGuaranteedPrefix(Incoming inc); 91 | 92 | @Override 93 | public void resolve(Constraint constraint, InterestCallback callback) { 94 | log("Resolve: "+constraint); 95 | debugger.askedToResolve(this, constraint); 96 | if(constraint.canBeAppliedTo(resolvedAccessPath) && !isLocked()) { 97 | AccessPath newAccPath = constraint.applyToAccessPath(resolvedAccessPath); 98 | ResolverTemplate nestedResolver = getOrCreateNestedResolver(newAccPath); 99 | assert nestedResolver.resolvedAccessPath.equals(constraint.applyToAccessPath(resolvedAccessPath)); 100 | nestedResolver.registerCallback(callback); 101 | } 102 | } 103 | 104 | protected ResolverTemplate getOrCreateNestedResolver(AccessPath newAccPath) { 105 | if(resolvedAccessPath.equals(newAccPath)) 106 | return this; 107 | 108 | if(!nestedResolvers.containsKey(newAccPath)) { 109 | assert resolvedAccessPath.getDeltaTo(newAccPath).accesses.length <= 1; 110 | if(allResolversInExclHierarchy.containsKey(newAccPath)) { 111 | return allResolversInExclHierarchy.get(newAccPath); 112 | } 113 | else { 114 | ResolverTemplate nestedResolver = createNestedResolver(newAccPath); 115 | if(!resolvedAccessPath.getExclusions().isEmpty() || !newAccPath.getExclusions().isEmpty()) 116 | allResolversInExclHierarchy.put(newAccPath, nestedResolver); 117 | nestedResolvers.put(newAccPath, nestedResolver); 118 | for(Incoming inc : Lists.newLinkedList(incomingEdges)) { 119 | nestedResolver.addIncoming(inc); 120 | } 121 | return nestedResolver; 122 | } 123 | } 124 | return nestedResolvers.get(newAccPath); 125 | } 126 | 127 | protected abstract ResolverTemplate createNestedResolver(AccessPath newAccPath); 128 | } -------------------------------------------------------------------------------- /src/heros/fieldsens/Scheduler.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2015 Johannes Lerch. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Johannes Lerch - initial API and implementation 10 | ******************************************************************************/ 11 | package heros.fieldsens; 12 | 13 | import java.util.LinkedList; 14 | import com.google.common.collect.Lists; 15 | 16 | public class Scheduler { 17 | 18 | private LinkedList worklist = Lists.newLinkedList(); 19 | 20 | public void schedule(Runnable job) { 21 | worklist.add(job); 22 | } 23 | 24 | public void runAndAwaitCompletion() { 25 | while(!worklist.isEmpty()) { 26 | worklist.removeLast().run(); 27 | } 28 | } 29 | 30 | } 31 | -------------------------------------------------------------------------------- /src/heros/fieldsens/SourceStmtAnnotatedMethodAnalyzer.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2015 Johannes Lerch. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Johannes Lerch - initial API and implementation 10 | ******************************************************************************/ 11 | package heros.fieldsens; 12 | 13 | import heros.fieldsens.structs.WrappedFact; 14 | import heros.fieldsens.structs.WrappedFactAtStatement; 15 | import heros.utilities.DefaultValueMap; 16 | 17 | 18 | public class SourceStmtAnnotatedMethodAnalyzer 19 | implements MethodAnalyzer { 20 | 21 | private Method method; 22 | private DefaultValueMap, PerAccessPathMethodAnalyzer> perSourceAnalyzer = 23 | new DefaultValueMap, PerAccessPathMethodAnalyzer>() { 24 | 25 | @Override 26 | protected PerAccessPathMethodAnalyzer createItem(Key key) { 27 | return new PerAccessPathMethodAnalyzer(method, key.fact, context, debugger); 28 | } 29 | }; 30 | private Context context; 31 | private Synchronizer synchronizer; 32 | private Debugger debugger; 33 | 34 | public SourceStmtAnnotatedMethodAnalyzer(Method method, Context context, Synchronizer synchronizer, Debugger debugger) { 35 | this.method = method; 36 | this.context = context; 37 | this.synchronizer = synchronizer; 38 | this.debugger = debugger; 39 | } 40 | 41 | @Override 42 | public void addIncomingEdge(CallEdge incEdge) { 43 | WrappedFact calleeSourceFact = incEdge.getCalleeSourceFact(); 44 | Key key = new Key(calleeSourceFact.getFact(), null); 45 | PerAccessPathMethodAnalyzer analyzer = perSourceAnalyzer.getOrCreate(key); 46 | analyzer.addIncomingEdge(incEdge); 47 | } 48 | 49 | @Override 50 | public void addInitialSeed(Stmt startPoint, Fact val) { 51 | Key key = new Key(val, startPoint); 52 | perSourceAnalyzer.getOrCreate(key).addInitialSeed(startPoint); 53 | } 54 | 55 | @Override 56 | public void addUnbalancedReturnFlow(final WrappedFactAtStatement target, final Stmt callSite) { 57 | synchronizer.synchronizeOnStmt(callSite, new Runnable() { 58 | @Override 59 | public void run() { 60 | Key key = new Key(context.zeroValue, callSite); 61 | perSourceAnalyzer.getOrCreate(key).scheduleUnbalancedReturnEdgeTo(target); 62 | } 63 | }); 64 | } 65 | 66 | public static interface Synchronizer { 67 | void synchronizeOnStmt(Stmt stmt, Runnable job); 68 | } 69 | 70 | private static class Key { 71 | private Fact fact; 72 | private Stmt stmt; 73 | 74 | private Key(Fact fact, Stmt stmt) { 75 | this.fact = fact; 76 | this.stmt = stmt; 77 | } 78 | 79 | @Override 80 | public int hashCode() { 81 | final int prime = 31; 82 | int result = 1; 83 | result = prime * result + ((fact == null) ? 0 : fact.hashCode()); 84 | result = prime * result + ((stmt == null) ? 0 : stmt.hashCode()); 85 | return result; 86 | } 87 | 88 | @Override 89 | public boolean equals(Object obj) { 90 | if (this == obj) 91 | return true; 92 | if (obj == null) 93 | return false; 94 | if (getClass() != obj.getClass()) 95 | return false; 96 | Key other = (Key) obj; 97 | if (fact == null) { 98 | if (other.fact != null) 99 | return false; 100 | } else if (!fact.equals(other.fact)) 101 | return false; 102 | if (stmt == null) { 103 | if (other.stmt != null) 104 | return false; 105 | } else if (!stmt.equals(other.stmt)) 106 | return false; 107 | return true; 108 | } 109 | } 110 | } -------------------------------------------------------------------------------- /src/heros/fieldsens/ZeroCallEdgeResolver.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2015 Johannes Lerch. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Johannes Lerch - initial API and implementation 10 | ******************************************************************************/ 11 | package heros.fieldsens; 12 | 13 | import heros.fieldsens.FlowFunction.Constraint; 14 | 15 | public class ZeroCallEdgeResolver extends CallEdgeResolver { 16 | 17 | private ZeroHandler zeroHandler; 18 | 19 | public ZeroCallEdgeResolver(PerAccessPathMethodAnalyzer analyzer, ZeroHandler zeroHandler, Debugger debugger) { 20 | super(analyzer, debugger); 21 | this.zeroHandler = zeroHandler; 22 | } 23 | 24 | ZeroCallEdgeResolver copyWithAnalyzer(PerAccessPathMethodAnalyzer analyzer) { 25 | return new ZeroCallEdgeResolver(analyzer, zeroHandler, debugger); 26 | } 27 | 28 | @Override 29 | public void resolve(Constraint constraint, InterestCallback callback) { 30 | if(zeroHandler.shouldGenerateAccessPath(constraint.applyToAccessPath(new AccessPath()))) 31 | callback.interest(analyzer, this); 32 | } 33 | 34 | @Override 35 | public void interest(Resolver resolver) { 36 | } 37 | 38 | @Override 39 | protected ZeroCallEdgeResolver getOrCreateNestedResolver(AccessPath newAccPath) { 40 | return this; 41 | } 42 | 43 | @Override 44 | public String toString() { 45 | return "[0-Resolver"+super.toString()+"]"; 46 | } 47 | 48 | @Override 49 | public int hashCode() { 50 | final int prime = 31; 51 | int result = 1; 52 | result = prime * result + ((zeroHandler == null) ? 0 : zeroHandler.hashCode()); 53 | return result; 54 | } 55 | 56 | @Override 57 | public boolean equals(Object obj) { 58 | if (this == obj) 59 | return true; 60 | if (obj == null) 61 | return false; 62 | if (getClass() != obj.getClass()) 63 | return false; 64 | ZeroCallEdgeResolver other = (ZeroCallEdgeResolver) obj; 65 | if (zeroHandler == null) { 66 | if (other.zeroHandler != null) 67 | return false; 68 | } else if (!zeroHandler.equals(other.zeroHandler)) 69 | return false; 70 | return true; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/heros/fieldsens/ZeroHandler.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2015 Johannes Lerch. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Johannes Lerch - initial API and implementation 10 | ******************************************************************************/ 11 | package heros.fieldsens; 12 | 13 | 14 | public interface ZeroHandler { 15 | 16 | /** 17 | * If reading fields on a fact abstraction directly connected to a Zero fact, this handler is consulted 18 | * to decide if the field may be read. 19 | * @param accPath The AccessPath consisting of fields already read in addition to a new field to be read. 20 | * @return true if the AccessPath can be generated from within the Zero fact, false otherwise. 21 | */ 22 | boolean shouldGenerateAccessPath(AccessPath accPath); 23 | } 24 | -------------------------------------------------------------------------------- /src/heros/fieldsens/structs/DeltaConstraint.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2015 Johannes Lerch. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Johannes Lerch - initial API and implementation 10 | ******************************************************************************/ 11 | package heros.fieldsens.structs; 12 | 13 | import heros.fieldsens.AccessPath; 14 | import heros.fieldsens.FlowFunction; 15 | import heros.fieldsens.AccessPath.Delta; 16 | import heros.fieldsens.FlowFunction.Constraint; 17 | 18 | public class DeltaConstraint implements Constraint { 19 | 20 | private Delta delta; 21 | 22 | public DeltaConstraint(AccessPath accPathAtCaller, AccessPath accPathAtCallee) { 23 | delta = accPathAtCaller.getDeltaTo(accPathAtCallee); 24 | } 25 | 26 | public DeltaConstraint(Delta delta) { 27 | this.delta = delta; 28 | } 29 | 30 | @Override 31 | public AccessPath applyToAccessPath(AccessPath accPath) { 32 | return delta.applyTo(accPath); 33 | } 34 | 35 | @Override 36 | public boolean canBeAppliedTo(AccessPath accPath) { 37 | return delta.canBeAppliedTo(accPath); 38 | } 39 | 40 | @Override 41 | public String toString() { 42 | return delta.toString(); 43 | } 44 | 45 | @Override 46 | public int hashCode() { 47 | final int prime = 31; 48 | int result = 1; 49 | result = prime * result + ((delta == null) ? 0 : delta.hashCode()); 50 | return result; 51 | } 52 | 53 | @Override 54 | public boolean equals(Object obj) { 55 | if (this == obj) 56 | return true; 57 | if (obj == null) 58 | return false; 59 | if (getClass() != obj.getClass()) 60 | return false; 61 | DeltaConstraint other = (DeltaConstraint) obj; 62 | if (delta == null) { 63 | if (other.delta != null) 64 | return false; 65 | } else if (!delta.equals(other.delta)) 66 | return false; 67 | return true; 68 | } 69 | 70 | 71 | } 72 | -------------------------------------------------------------------------------- /src/heros/fieldsens/structs/FactAtStatement.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2015 Johannes Lerch. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Johannes Lerch - initial API and implementation 10 | ******************************************************************************/ 11 | package heros.fieldsens.structs; 12 | 13 | public class FactAtStatement { 14 | 15 | public final Fact fact; 16 | public final Stmt stmt; 17 | 18 | public FactAtStatement(Fact fact, Stmt stmt) { 19 | this.fact = fact; 20 | this.stmt = stmt; 21 | } 22 | 23 | @Override 24 | public int hashCode() { 25 | final int prime = 31; 26 | int result = 1; 27 | result = prime * result + ((fact == null) ? 0 : fact.hashCode()); 28 | result = prime * result + ((stmt == null) ? 0 : stmt.hashCode()); 29 | return result; 30 | } 31 | 32 | @Override 33 | public boolean equals(Object obj) { 34 | if (this == obj) 35 | return true; 36 | if (obj == null) 37 | return false; 38 | if (getClass() != obj.getClass()) 39 | return false; 40 | FactAtStatement other = (FactAtStatement) obj; 41 | if (fact == null) { 42 | if (other.fact != null) 43 | return false; 44 | } else if (!fact.equals(other.fact)) 45 | return false; 46 | if (stmt == null) { 47 | if (other.stmt != null) 48 | return false; 49 | } else if (!stmt.equals(other.stmt)) 50 | return false; 51 | return true; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/heros/fieldsens/structs/ReturnEdge.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2015 Johannes Lerch. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Johannes Lerch - initial API and implementation 10 | ******************************************************************************/ 11 | package heros.fieldsens.structs; 12 | 13 | import heros.fieldsens.AccessPath; 14 | import heros.fieldsens.Resolver; 15 | import heros.fieldsens.AccessPath.Delta; 16 | import heros.fieldsens.AccessPath.PrefixTestResult; 17 | 18 | public class ReturnEdge { 19 | 20 | public final Fact incFact; 21 | public final Resolver resolverAtCaller; 22 | public final Delta callDelta; 23 | public final AccessPath incAccessPath; 24 | public final Resolver incResolver; 25 | public final Delta usedAccessPathOfIncResolver; 26 | 27 | public ReturnEdge(WrappedFact fact, 28 | Resolver resolverAtCaller, 29 | Delta callDelta) { 30 | this(fact.getFact(), fact.getAccessPath(), fact.getResolver(), resolverAtCaller, callDelta, Delta.empty()); 31 | } 32 | 33 | private ReturnEdge(Fact incFact, 34 | AccessPath incAccessPath, 35 | Resolver incResolver, 36 | Resolver resolverAtCaller, 37 | Delta callDelta, 38 | Delta usedAccessPathOfIncResolver) { 39 | this.incFact = incFact; 40 | this.incAccessPath = incAccessPath; 41 | this.incResolver = incResolver; 42 | this.resolverAtCaller = resolverAtCaller; 43 | this.callDelta = callDelta; 44 | this.usedAccessPathOfIncResolver = usedAccessPathOfIncResolver; 45 | } 46 | 47 | public ReturnEdge copyWithIncomingResolver( 48 | Resolver incResolver, Delta usedAccessPathOfIncResolver) { 49 | return new ReturnEdge(incFact, incAccessPath, incResolver, resolverAtCaller, callDelta, usedAccessPathOfIncResolver); 50 | } 51 | 52 | public ReturnEdge copyWithResolverAtCaller( 53 | Resolver resolverAtCaller, Delta usedAccessPathOfIncResolver) { 54 | return new ReturnEdge(incFact, incAccessPath, null, resolverAtCaller, callDelta, usedAccessPathOfIncResolver); 55 | } 56 | 57 | @Override 58 | public String toString() { 59 | return String.format("IncFact: %s%s, Delta: %s, IncResolver: <%s:%s>, ResolverAtCallSite: %s", incFact, incAccessPath, callDelta, usedAccessPathOfIncResolver, incResolver, resolverAtCaller); 60 | } 61 | 62 | 63 | } -------------------------------------------------------------------------------- /src/heros/fieldsens/structs/WrappedFact.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2015 Johannes Lerch. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Johannes Lerch - initial API and implementation 10 | ******************************************************************************/ 11 | package heros.fieldsens.structs; 12 | 13 | import heros.fieldsens.AccessPath; 14 | import heros.fieldsens.FlowFunction; 15 | import heros.fieldsens.Resolver; 16 | import heros.fieldsens.AccessPath.Delta; 17 | import heros.fieldsens.FlowFunction.Constraint; 18 | 19 | public class WrappedFact{ 20 | 21 | private final Fact fact; 22 | private final AccessPath accessPath; 23 | private final Resolver resolver; 24 | 25 | public WrappedFact(Fact fact, AccessPath accessPath, Resolver resolver) { 26 | assert fact != null; 27 | assert accessPath != null; 28 | assert resolver != null; 29 | 30 | this.fact = fact; 31 | this.accessPath = accessPath; 32 | this.resolver = resolver; 33 | } 34 | 35 | public Fact getFact() { 36 | return fact; 37 | } 38 | 39 | public WrappedFact applyDelta(AccessPath.Delta delta) { 40 | return new WrappedFact(fact, delta.applyTo(accessPath), resolver); //TODO keep resolver? 41 | } 42 | 43 | public AccessPath getAccessPath() { 44 | return accessPath; 45 | } 46 | 47 | public WrappedFact applyConstraint(Constraint constraint, Fact zeroValue) { 48 | if(fact.equals(zeroValue)) 49 | return this; 50 | else 51 | return new WrappedFact(fact, constraint.applyToAccessPath(accessPath), resolver); 52 | } 53 | 54 | @Override 55 | public String toString() { 56 | String result = fact.toString()+accessPath; 57 | if(resolver != null) 58 | result+=resolver.toString(); 59 | return result; 60 | } 61 | 62 | @Override 63 | public int hashCode() { 64 | final int prime = 31; 65 | int result = 1; 66 | result = prime * result + ((accessPath == null) ? 0 : accessPath.hashCode()); 67 | result = prime * result + ((fact == null) ? 0 : fact.hashCode()); 68 | result = prime * result + ((resolver == null) ? 0 : resolver.hashCode()); 69 | return result; 70 | } 71 | 72 | @Override 73 | public boolean equals(Object obj) { 74 | if (this == obj) 75 | return true; 76 | if (obj == null) 77 | return false; 78 | if (getClass() != obj.getClass()) 79 | return false; 80 | WrappedFact other = (WrappedFact) obj; 81 | if (accessPath == null) { 82 | if (other.accessPath != null) 83 | return false; 84 | } else if (!accessPath.equals(other.accessPath)) 85 | return false; 86 | if (fact == null) { 87 | if (other.fact != null) 88 | return false; 89 | } else if (!fact.equals(other.fact)) 90 | return false; 91 | if (resolver == null) { 92 | if (other.resolver != null) 93 | return false; 94 | } else if (!resolver.equals(other.resolver)) 95 | return false; 96 | return true; 97 | } 98 | 99 | public Resolver getResolver() { 100 | return resolver; 101 | } 102 | 103 | 104 | } 105 | -------------------------------------------------------------------------------- /src/heros/fieldsens/structs/WrappedFactAtStatement.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2015 Johannes Lerch. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Johannes Lerch - initial API and implementation 10 | ******************************************************************************/ 11 | package heros.fieldsens.structs; 12 | 13 | import heros.fieldsens.AccessPath; 14 | import heros.fieldsens.Resolver; 15 | import heros.fieldsens.AccessPath.Delta; 16 | 17 | 18 | public class WrappedFactAtStatement { 19 | 20 | private WrappedFact fact; 21 | private Stmt stmt; 22 | 23 | public WrappedFactAtStatement(Stmt stmt, WrappedFact fact) { 24 | this.stmt = stmt; 25 | this.fact = fact; 26 | } 27 | 28 | public WrappedFact getWrappedFact() { 29 | return fact; 30 | } 31 | 32 | public Fact getFact() { 33 | return fact.getFact(); 34 | } 35 | 36 | public AccessPath getAccessPath() { 37 | return fact.getAccessPath(); 38 | } 39 | 40 | public Resolver getResolver() { 41 | return fact.getResolver(); 42 | } 43 | 44 | public Stmt getStatement() { 45 | return stmt; 46 | } 47 | 48 | public FactAtStatement getAsFactAtStatement() { 49 | return new FactAtStatement(fact.getFact(), stmt); 50 | } 51 | 52 | public boolean canDeltaBeApplied(AccessPath.Delta delta) { 53 | return delta.canBeAppliedTo(fact.getAccessPath()); 54 | } 55 | 56 | @Override 57 | public String toString() { 58 | return fact+" @ "+stmt; 59 | } 60 | 61 | @Override 62 | public int hashCode() { 63 | final int prime = 31; 64 | int result = 1; 65 | result = prime * result + ((fact == null) ? 0 : fact.hashCode()); 66 | result = prime * result + ((stmt == null) ? 0 : stmt.hashCode()); 67 | return result; 68 | } 69 | 70 | @Override 71 | public boolean equals(Object obj) { 72 | if (this == obj) 73 | return true; 74 | if (obj == null) 75 | return false; 76 | if (getClass() != obj.getClass()) 77 | return false; 78 | WrappedFactAtStatement other = (WrappedFactAtStatement) obj; 79 | if (fact == null) { 80 | if (other.fact != null) 81 | return false; 82 | } else if (!fact.equals(other.fact)) 83 | return false; 84 | if (stmt == null) { 85 | if (other.stmt != null) 86 | return false; 87 | } else if (!stmt.equals(other.stmt)) 88 | return false; 89 | return true; 90 | } 91 | 92 | } 93 | -------------------------------------------------------------------------------- /src/heros/flowfunc/Compose.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2012 Eric Bodden. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Eric Bodden - initial API and implementation 10 | ******************************************************************************/ 11 | package heros.flowfunc; 12 | 13 | import heros.FlowFunction; 14 | 15 | import java.util.ArrayList; 16 | import java.util.List; 17 | import java.util.Set; 18 | 19 | import com.google.common.collect.Sets; 20 | 21 | 22 | /** 23 | * Represents the ordered composition of a set of flow functions. 24 | */ 25 | public class Compose implements FlowFunction { 26 | 27 | private final FlowFunction[] funcs; 28 | 29 | private Compose(FlowFunction... funcs){ 30 | this.funcs = funcs; 31 | } 32 | 33 | public Set computeTargets(D source) { 34 | Set curr = Sets.newHashSet(); 35 | curr.add(source); 36 | for (FlowFunction func : funcs) { 37 | Set next = Sets.newHashSet(); 38 | for(D d: curr) 39 | next.addAll(func.computeTargets(d)); 40 | curr = next; 41 | } 42 | return curr; 43 | } 44 | 45 | @SuppressWarnings({ "rawtypes", "unchecked" }) 46 | public static FlowFunction compose(FlowFunction... funcs) { 47 | List> list = new ArrayList>(); 48 | for (FlowFunction f : funcs) { 49 | if(f!=Identity.v()) { 50 | list.add(f); 51 | } 52 | } 53 | if(list.size()==1) return list.get(0); 54 | else if(list.isEmpty()) return Identity.v(); 55 | return new Compose(list.toArray(new FlowFunction[list.size()])); 56 | } 57 | 58 | } 59 | -------------------------------------------------------------------------------- /src/heros/flowfunc/Gen.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2012 Eric Bodden. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Eric Bodden - initial API and implementation 10 | ******************************************************************************/ 11 | package heros.flowfunc; 12 | 13 | import static heros.TwoElementSet.twoElementSet; 14 | import static java.util.Collections.singleton; 15 | import heros.FlowFunction; 16 | 17 | import java.util.Set; 18 | 19 | 20 | 21 | /** 22 | * Function that creates a new value (e.g. returns a set containing a fixed value when given 23 | * a specific parameter), but acts like the identity function for all other parameters. 24 | * 25 | * @param The type of data-flow facts to be computed by the tabulation problem. 26 | */ 27 | public class Gen implements FlowFunction { 28 | 29 | private final D genValue; 30 | private final D zeroValue; 31 | 32 | public Gen(D genValue, D zeroValue){ 33 | this.genValue = genValue; 34 | this.zeroValue = zeroValue; 35 | } 36 | 37 | public Set computeTargets(D source) { 38 | if(source.equals(zeroValue)) { 39 | return twoElementSet(source, genValue); 40 | } else { 41 | return singleton(source); 42 | } 43 | } 44 | 45 | } 46 | -------------------------------------------------------------------------------- /src/heros/flowfunc/Identity.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2012 Eric Bodden. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Eric Bodden - initial API and implementation 10 | ******************************************************************************/ 11 | package heros.flowfunc; 12 | 13 | import static java.util.Collections.singleton; 14 | import heros.FlowFunction; 15 | 16 | import java.util.Set; 17 | 18 | 19 | 20 | public class Identity implements FlowFunction { 21 | 22 | @SuppressWarnings("rawtypes") 23 | private final static Identity instance = new Identity(); 24 | 25 | private Identity(){} //use v() instead 26 | 27 | public Set computeTargets(D source) { 28 | return singleton(source); 29 | } 30 | 31 | @SuppressWarnings("unchecked") 32 | public static Identity v() { 33 | return instance; 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /src/heros/flowfunc/Kill.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2012 Eric Bodden. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Eric Bodden - initial API and implementation 10 | ******************************************************************************/ 11 | package heros.flowfunc; 12 | 13 | import static java.util.Collections.emptySet; 14 | import static java.util.Collections.singleton; 15 | import heros.FlowFunction; 16 | 17 | import java.util.Set; 18 | 19 | 20 | 21 | /** 22 | * Function that kills a specific value (i.e. returns an empty set for when given this 23 | * value as an argument), but behaves like the identity function for all other values. 24 | * 25 | * @param The type of data-flow facts to be computed by the tabulation problem. 26 | */ 27 | public class Kill implements FlowFunction { 28 | 29 | private final D killValue; 30 | 31 | public Kill(D killValue){ 32 | this.killValue = killValue; 33 | } 34 | 35 | public Set computeTargets(D source) { 36 | if(source.equals(killValue)) { 37 | return emptySet(); 38 | } else { 39 | return singleton(source); 40 | } 41 | } 42 | 43 | } 44 | -------------------------------------------------------------------------------- /src/heros/flowfunc/KillAll.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2012 Eric Bodden. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Eric Bodden - initial API and implementation 10 | ******************************************************************************/ 11 | package heros.flowfunc; 12 | 13 | import static java.util.Collections.emptySet; 14 | import heros.FlowFunction; 15 | 16 | import java.util.Set; 17 | 18 | 19 | 20 | /** 21 | * The empty function, i.e. a function which returns an empty set for all points 22 | * in the definition space. 23 | * 24 | * @param The type of data-flow facts to be computed by the tabulation problem. 25 | */ 26 | public class KillAll implements FlowFunction { 27 | 28 | @SuppressWarnings("rawtypes") 29 | private final static KillAll instance = new KillAll(); 30 | 31 | private KillAll(){} //use v() instead 32 | 33 | public Set computeTargets(D source) { 34 | return emptySet(); 35 | } 36 | 37 | @SuppressWarnings("unchecked") 38 | public static KillAll v() { 39 | return instance; 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /src/heros/flowfunc/Transfer.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2012 Eric Bodden. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Eric Bodden - initial API and implementation 10 | ******************************************************************************/ 11 | package heros.flowfunc; 12 | 13 | import static heros.TwoElementSet.twoElementSet; 14 | import heros.FlowFunction; 15 | 16 | import java.util.Collections; 17 | import java.util.Set; 18 | 19 | 20 | 21 | public class Transfer implements FlowFunction { 22 | 23 | private final D toValue; 24 | private final D fromValue; 25 | 26 | public Transfer(D toValue, D fromValue){ 27 | this.toValue = toValue; 28 | this.fromValue = fromValue; 29 | } 30 | 31 | public Set computeTargets(D source) { 32 | if(source.equals(fromValue)) { 33 | return twoElementSet(source, toValue); 34 | } else if(source.equals(toValue)) { 35 | return Collections.emptySet(); 36 | } else { 37 | return Collections.singleton(source); 38 | } 39 | } 40 | 41 | } 42 | -------------------------------------------------------------------------------- /src/heros/flowfunc/Union.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2012 Eric Bodden. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Eric Bodden - initial API and implementation 10 | ******************************************************************************/ 11 | package heros.flowfunc; 12 | 13 | import static com.google.common.collect.Sets.newHashSet; 14 | import heros.FlowFunction; 15 | 16 | import java.util.ArrayList; 17 | import java.util.List; 18 | import java.util.Set; 19 | 20 | 21 | /** 22 | * Represents the union of a set of flow functions. 23 | */ 24 | public class Union implements FlowFunction { 25 | 26 | private final FlowFunction[] funcs; 27 | 28 | private Union(FlowFunction... funcs){ 29 | this.funcs = funcs; 30 | } 31 | 32 | public Set computeTargets(D source) { 33 | Set res = newHashSet(); 34 | for (FlowFunction func : funcs) { 35 | res.addAll(func.computeTargets(source)); 36 | } 37 | return res; 38 | } 39 | 40 | @SuppressWarnings({ "rawtypes", "unchecked" }) 41 | public static FlowFunction union(FlowFunction... funcs) { 42 | List> list = new ArrayList>(); 43 | for (FlowFunction f : funcs) { 44 | if(f!=Identity.v()) { 45 | list.add(f); 46 | } 47 | } 48 | if(list.size()==1) return list.get(0); 49 | else if(list.isEmpty()) return Identity.v(); 50 | return new Union(list.toArray(new FlowFunction[list.size()])); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /src/heros/solver/BiDiIFDSSolver.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2012 Eric Bodden. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Eric Bodden - initial API and implementation 10 | ******************************************************************************/ 11 | package heros.solver; 12 | 13 | import heros.EdgeFunction; 14 | import heros.FlowFunction; 15 | import heros.FlowFunctions; 16 | import heros.IFDSTabulationProblem; 17 | import heros.InterproceduralCFG; 18 | import heros.solver.IFDSSolver.BinaryDomain; 19 | 20 | import java.util.Collections; 21 | import java.util.HashMap; 22 | import java.util.HashSet; 23 | import java.util.Map; 24 | import java.util.Map.Entry; 25 | import java.util.Set; 26 | import java.util.concurrent.ConcurrentMap; 27 | import java.util.concurrent.LinkedBlockingQueue; 28 | import java.util.concurrent.TimeUnit; 29 | 30 | import com.google.common.collect.Maps; 31 | 32 | /** 33 | * This is a special IFDS solver that solves the analysis problem inside out, i.e., from further down the call stack to 34 | * further up the call stack. This can be useful, for instance, for taint analysis problems that track flows in two directions. 35 | * 36 | * The solver is instantiated with two analyses, one to be computed forward and one to be computed backward. Both analysis problems 37 | * must be unbalanced, i.e., must return true for {@link IFDSTabulationProblem#followReturnsPastSeeds()}. 38 | * The solver then executes both analyses in lockstep, i.e., when one of the analyses reaches an unbalanced return edge (signified 39 | * by a ZERO source value) then the solver pauses this analysis until the other analysis reaches the same unbalanced return (if ever). 40 | * The result is that the analyses will never diverge, i.e., will ultimately always only propagate into contexts in which both their 41 | * computed paths are realizable at the same time. 42 | * 43 | * This solver requires data-flow abstractions that implement the {@link LinkedNode} interface such that data-flow values can be linked to form 44 | * reportable paths. 45 | * 46 | * @param see {@link IFDSSolver} 47 | * @param A data-flow abstraction that must implement the {@link LinkedNode} interface such that data-flow values can be linked to form 48 | * reportable paths. 49 | * @param see {@link IFDSSolver} 50 | * @param see {@link IFDSSolver} 51 | */ 52 | public class BiDiIFDSSolver, M, I extends InterproceduralCFG> extends BiDiIDESolver { 53 | 54 | 55 | /** 56 | * Instantiates a {@link BiDiIFDSSolver} with the associated forward and backward problem. 57 | */ 58 | public BiDiIFDSSolver(IFDSTabulationProblem forwardProblem, IFDSTabulationProblem backwardProblem) { 59 | super(IFDSSolver.createIDETabulationProblem(forwardProblem), IFDSSolver.createIDETabulationProblem(backwardProblem)); 60 | } 61 | 62 | public Set fwIFDSResultAt(N stmt) { 63 | return extractResults(fwSolver.resultsAt(stmt).keySet()); 64 | } 65 | 66 | public Set bwIFDSResultAt(N stmt) { 67 | return extractResults(bwSolver.resultsAt(stmt).keySet()); 68 | } 69 | 70 | private Set extractResults(Set annotatedResults) { 71 | Set res = new HashSet(); 72 | for (AbstractionWithSourceStmt abstractionWithSourceStmt : annotatedResults) { 73 | res.add(abstractionWithSourceStmt.getAbstraction()); 74 | } 75 | return res; 76 | } 77 | 78 | } 79 | -------------------------------------------------------------------------------- /src/heros/solver/CountLatch.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2012 Eric Bodden. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Eric Bodden - initial API and implementation 10 | ******************************************************************************/ 11 | package heros.solver; 12 | 13 | import java.util.concurrent.CountDownLatch; 14 | import java.util.concurrent.TimeUnit; 15 | import java.util.concurrent.locks.AbstractQueuedSynchronizer; 16 | 17 | /** 18 | * A synchronization aid similar to {@link CountDownLatch} but with the ability 19 | * to also count up. This is useful to wait until a variable number of tasks 20 | * have completed. {@link #awaitZero()} will block until the count reaches zero. 21 | */ 22 | public class CountLatch { 23 | 24 | @SuppressWarnings("serial") 25 | private static final class Sync extends AbstractQueuedSynchronizer { 26 | 27 | Sync(int count) { 28 | setState(count); 29 | } 30 | 31 | int getCount() { 32 | return getState(); 33 | } 34 | 35 | void reset() { 36 | setState(0); 37 | } 38 | 39 | @Override 40 | protected int tryAcquireShared(int acquires) { 41 | return (getState() == 0) ? 1 : -1; 42 | } 43 | 44 | protected int acquireNonBlocking(int acquires) { 45 | // increment count 46 | for (;;) { 47 | int c = getState(); 48 | int nextc = c + 1; 49 | if (compareAndSetState(c, nextc)) 50 | return 1; 51 | } 52 | } 53 | 54 | @Override 55 | protected boolean tryReleaseShared(int releases) { 56 | // Decrement count; signal when transition to zero 57 | for (;;) { 58 | int c = getState(); 59 | if (c == 0) 60 | return false; 61 | int nextc = c - 1; 62 | if (compareAndSetState(c, nextc)) 63 | return nextc == 0; 64 | } 65 | } 66 | } 67 | 68 | private final Sync sync; 69 | 70 | public CountLatch(int count) { 71 | this.sync = new Sync(count); 72 | } 73 | 74 | public void awaitZero() throws InterruptedException { 75 | sync.acquireShared(1); 76 | } 77 | 78 | public boolean awaitZero(long timeout, TimeUnit unit) throws InterruptedException { 79 | return sync.tryAcquireSharedNanos(1, unit.toNanos(timeout)); 80 | } 81 | 82 | public void increment() { 83 | sync.acquireNonBlocking(1); 84 | } 85 | 86 | public void decrement() { 87 | sync.releaseShared(1); 88 | } 89 | 90 | /** 91 | * Resets the counter to zero. But waiting threads won't be released somehow. 92 | * So this interrupts the threads so that they escape from their waiting state. 93 | */ 94 | public void resetAndInterrupt(){ 95 | sync.reset(); 96 | for (int i = 0; i < 3; i++) //Because it is a best effort thing, do it three times and hope for the best. 97 | for (Thread t : sync.getQueuedThreads()) 98 | t.interrupt(); 99 | sync.reset(); //Just in case a thread would've incremented the counter again. 100 | } 101 | 102 | public String toString() { 103 | return super.toString() + "[Count = " + sync.getCount() + "]"; 104 | } 105 | 106 | /** 107 | * Gets whether this counting latch has arrived at zero 108 | * @return True if this counting latch has arrived at zero, otherwise 109 | * false 110 | */ 111 | public boolean isAtZero() { 112 | return sync.getCount() == 0; 113 | } 114 | 115 | } 116 | -------------------------------------------------------------------------------- /src/heros/solver/CountingThreadPoolExecutor.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2012 Eric Bodden. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Eric Bodden - initial API and implementation 10 | ******************************************************************************/ 11 | package heros.solver; 12 | 13 | import heros.util.SootThreadGroup; 14 | 15 | import java.util.concurrent.BlockingQueue; 16 | import java.util.concurrent.RejectedExecutionException; 17 | import java.util.concurrent.ThreadFactory; 18 | import java.util.concurrent.ThreadPoolExecutor; 19 | import java.util.concurrent.TimeUnit; 20 | 21 | import org.slf4j.Logger; 22 | import org.slf4j.LoggerFactory; 23 | 24 | /** 25 | * A {@link ThreadPoolExecutor} which keeps track of the number of spawned 26 | * tasks to allow clients to await their completion. 27 | */ 28 | public class CountingThreadPoolExecutor extends ThreadPoolExecutor { 29 | 30 | protected static final Logger logger = LoggerFactory.getLogger(CountingThreadPoolExecutor.class); 31 | 32 | protected final CountLatch numRunningTasks = new CountLatch(0); 33 | 34 | protected volatile Throwable exception = null; 35 | 36 | public CountingThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, 37 | BlockingQueue workQueue) { 38 | super(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue, new ThreadFactory() { 39 | 40 | @Override 41 | public Thread newThread(Runnable r) { 42 | return new Thread(new SootThreadGroup(), r); 43 | } 44 | }); 45 | } 46 | 47 | @Override 48 | public void execute(Runnable command) { 49 | try { 50 | numRunningTasks.increment(); 51 | super.execute(command); 52 | } 53 | catch (RejectedExecutionException ex) { 54 | // If we were unable to submit the task, we may not count it! 55 | numRunningTasks.decrement(); 56 | throw ex; 57 | } 58 | } 59 | 60 | @Override 61 | protected void afterExecute(Runnable r, Throwable t) { 62 | if(t!=null) { 63 | exception = t; 64 | logger.error("Worker thread execution failed: " + t.getMessage(), t); 65 | 66 | shutdownNow(); 67 | numRunningTasks.resetAndInterrupt(); 68 | } 69 | else { 70 | numRunningTasks.decrement(); 71 | } 72 | super.afterExecute(r, t); 73 | } 74 | 75 | /** 76 | * Awaits the completion of all spawned tasks. 77 | */ 78 | public void awaitCompletion() throws InterruptedException { 79 | numRunningTasks.awaitZero(); 80 | } 81 | 82 | /** 83 | * Awaits the completion of all spawned tasks. 84 | */ 85 | public void awaitCompletion(long timeout, TimeUnit unit) throws InterruptedException { 86 | numRunningTasks.awaitZero(timeout, unit); 87 | } 88 | 89 | /** 90 | * Returns the exception thrown during task execution (if any). 91 | */ 92 | public Throwable getException() { 93 | return exception; 94 | } 95 | 96 | } -------------------------------------------------------------------------------- /src/heros/solver/IFDSSolver.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2012 Eric Bodden. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Eric Bodden - initial API and implementation 10 | ******************************************************************************/ 11 | package heros.solver; 12 | 13 | import static heros.solver.IFDSSolver.BinaryDomain.BOTTOM; 14 | import static heros.solver.IFDSSolver.BinaryDomain.TOP; 15 | import heros.EdgeFunction; 16 | import heros.EdgeFunctions; 17 | import heros.FlowFunctions; 18 | import heros.IDETabulationProblem; 19 | import heros.IFDSTabulationProblem; 20 | import heros.InterproceduralCFG; 21 | import heros.MeetLattice; 22 | import heros.edgefunc.AllBottom; 23 | import heros.edgefunc.AllTop; 24 | import heros.edgefunc.EdgeIdentity; 25 | 26 | import java.util.Map; 27 | import java.util.Set; 28 | 29 | /** 30 | * A solver for an {@link IFDSTabulationProblem}. This solver in effect uses the {@link IDESolver} 31 | * to solve the problem, as any IFDS problem can be intepreted as a special case of an IDE problem. 32 | * See Section 5.4.1 of the SRH96 paper. In effect, the IFDS problem is solved by solving an IDE 33 | * problem in which the environments (D to N mappings) represent the set's characteristic function. 34 | * 35 | * @param The type of nodes in the interprocedural control-flow graph. Typically {@link Unit}. 36 | * @param The type of data-flow facts to be computed by the tabulation problem. 37 | * @param The type of objects used to represent methods. Typically {@link SootMethod}. 38 | * @param The type of inter-procedural control-flow graph being used. 39 | * @see IFDSTabulationProblem 40 | */ 41 | public class IFDSSolver> extends IDESolver { 42 | 43 | protected static enum BinaryDomain { TOP,BOTTOM } 44 | 45 | private final static EdgeFunction ALL_BOTTOM = new AllBottom(BOTTOM); 46 | 47 | /** 48 | * Creates a solver for the given problem. The solver must then be started by calling 49 | * {@link #solve()}. 50 | */ 51 | public IFDSSolver(final IFDSTabulationProblem ifdsProblem) { 52 | super(createIDETabulationProblem(ifdsProblem)); 53 | } 54 | 55 | static > IDETabulationProblem createIDETabulationProblem( 56 | final IFDSTabulationProblem ifdsProblem) { 57 | return new IDETabulationProblem() { 58 | 59 | public FlowFunctions flowFunctions() { 60 | return ifdsProblem.flowFunctions(); 61 | } 62 | 63 | public I interproceduralCFG() { 64 | return ifdsProblem.interproceduralCFG(); 65 | } 66 | 67 | public Map> initialSeeds() { 68 | return ifdsProblem.initialSeeds(); 69 | } 70 | 71 | public D zeroValue() { 72 | return ifdsProblem.zeroValue(); 73 | } 74 | 75 | public EdgeFunctions edgeFunctions() { 76 | return new IFDSEdgeFunctions(); 77 | } 78 | 79 | public MeetLattice meetLattice() { 80 | return new MeetLattice() { 81 | 82 | public BinaryDomain topElement() { 83 | return BinaryDomain.TOP; 84 | } 85 | 86 | public BinaryDomain bottomElement() { 87 | return BinaryDomain.BOTTOM; 88 | } 89 | 90 | public BinaryDomain meet(BinaryDomain left, BinaryDomain right) { 91 | if(left==TOP && right==TOP) { 92 | return TOP; 93 | } else { 94 | return BOTTOM; 95 | } 96 | } 97 | }; 98 | } 99 | 100 | @Override 101 | public EdgeFunction allTopFunction() { 102 | return new AllTop(TOP); 103 | } 104 | 105 | @Override 106 | public boolean followReturnsPastSeeds() { 107 | return ifdsProblem.followReturnsPastSeeds(); 108 | } 109 | 110 | @Override 111 | public boolean autoAddZero() { 112 | return ifdsProblem.autoAddZero(); 113 | } 114 | 115 | @Override 116 | public int numThreads() { 117 | return ifdsProblem.numThreads(); 118 | } 119 | 120 | @Override 121 | public boolean computeValues() { 122 | return ifdsProblem.computeValues(); 123 | } 124 | 125 | class IFDSEdgeFunctions implements EdgeFunctions { 126 | 127 | public EdgeFunction getNormalEdgeFunction(N src,D srcNode,N tgt,D tgtNode) { 128 | if(srcNode==ifdsProblem.zeroValue()) return ALL_BOTTOM; 129 | return EdgeIdentity.v(); 130 | } 131 | 132 | public EdgeFunction getCallEdgeFunction(N callStmt,D srcNode,M destinationMethod,D destNode) { 133 | if(srcNode==ifdsProblem.zeroValue()) return ALL_BOTTOM; 134 | return EdgeIdentity.v(); 135 | } 136 | 137 | public EdgeFunction getReturnEdgeFunction(N callSite, M calleeMethod,N exitStmt,D exitNode,N returnSite,D retNode) { 138 | if(exitNode==ifdsProblem.zeroValue()) return ALL_BOTTOM; 139 | return EdgeIdentity.v(); 140 | } 141 | 142 | public EdgeFunction getCallToReturnEdgeFunction(N callStmt,D callNode,N returnSite,D returnSideNode) { 143 | if(callNode==ifdsProblem.zeroValue()) return ALL_BOTTOM; 144 | return EdgeIdentity.v(); 145 | } 146 | } 147 | 148 | @Override 149 | public boolean recordEdges() { 150 | return ifdsProblem.recordEdges(); 151 | } 152 | 153 | }; 154 | } 155 | 156 | /** 157 | * Returns the set of facts that hold at the given statement. 158 | */ 159 | public Set ifdsResultsAt(N statement) { 160 | return resultsAt(statement).keySet(); 161 | } 162 | 163 | } 164 | -------------------------------------------------------------------------------- /src/heros/solver/JoinHandlingNode.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2014 Johannes Lerch. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Johannes Lerch - initial API and implementation 10 | ******************************************************************************/ 11 | package heros.solver; 12 | 13 | import java.util.Arrays; 14 | 15 | 16 | public interface JoinHandlingNode { 17 | 18 | /** 19 | * 20 | * @param joiningNode the node abstraction that was propagated to the same target after {@code this} node. 21 | * @return true if the join could be handled and no further propagation of the {@code joiningNode} is necessary, otherwise false meaning 22 | * the node should be propagated by the solver. 23 | */ 24 | public boolean handleJoin(T joiningNode); 25 | 26 | /** 27 | * 28 | * @return a JoinKey object used to identify which node abstractions require manual join handling. 29 | * For nodes with {@code equal} JoinKey instances {@link #handleJoin(JoinHandlingNode)} will be called. 30 | */ 31 | public JoinKey createJoinKey(); 32 | 33 | public void setCallingContext(T callingContext); 34 | 35 | public static class JoinKey { 36 | private Object[] elements; 37 | 38 | /** 39 | * 40 | * @param elements Passed elements must be immutable with respect to their hashCode and equals implementations. 41 | */ 42 | public JoinKey(Object... elements) { 43 | this.elements = elements; 44 | } 45 | 46 | @Override 47 | public int hashCode() { 48 | final int prime = 31; 49 | int result = 1; 50 | result = prime * result + Arrays.hashCode(elements); 51 | return result; 52 | } 53 | 54 | @Override 55 | public boolean equals(Object obj) { 56 | if (this == obj) 57 | return true; 58 | if (obj == null) 59 | return false; 60 | if (getClass() != obj.getClass()) 61 | return false; 62 | JoinKey other = (JoinKey) obj; 63 | if (!Arrays.equals(elements, other.elements)) 64 | return false; 65 | return true; 66 | } 67 | } 68 | } 69 | -------------------------------------------------------------------------------- /src/heros/solver/JoinHandlingNodesIFDSSolver.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2013Johannes Lerch. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Johannes Lerch - initial API and implementation 10 | ******************************************************************************/ 11 | package heros.solver; 12 | 13 | import heros.EdgeFunction; 14 | import heros.IFDSTabulationProblem; 15 | import heros.InterproceduralCFG; 16 | import heros.solver.JoinHandlingNode.JoinKey; 17 | 18 | import java.util.Map; 19 | 20 | import com.google.common.collect.Maps; 21 | 22 | /** 23 | * An {@link IFDSSolver} that tracks paths for reporting. To do so, it requires that data-flow abstractions implement the LinkedNode interface. 24 | * The solver implements a cache of data-flow facts for each statement and source value. If for the same statement and source value the same 25 | * target value is seen again (as determined through a cache hit), then the solver propagates the cached value but at the same time links 26 | * both target values with one another. 27 | * 28 | * @author Johannes Lerch 29 | */ 30 | public class JoinHandlingNodesIFDSSolver, M, I extends InterproceduralCFG> extends IFDSSolver { 31 | 32 | public JoinHandlingNodesIFDSSolver(IFDSTabulationProblem ifdsProblem) { 33 | super(ifdsProblem); 34 | } 35 | 36 | protected final Map> cache = Maps.newHashMap(); 37 | 38 | @Override 39 | protected void propagate(D sourceVal, N target, D targetVal, EdgeFunction f, N relatedCallSite, boolean isUnbalancedReturn) { 40 | CacheEntry currentCacheEntry = new CacheEntry(target, sourceVal.createJoinKey(), targetVal.createJoinKey()); 41 | 42 | boolean propagate = false; 43 | synchronized (this) { 44 | if (cache.containsKey(currentCacheEntry)) { 45 | JoinHandlingNode existingTargetVal = cache.get(currentCacheEntry); 46 | if(!existingTargetVal.handleJoin(targetVal)) { 47 | propagate = true; 48 | } 49 | } else { 50 | cache.put(currentCacheEntry, targetVal); 51 | propagate = true; 52 | } 53 | } 54 | 55 | if (propagate) 56 | super.propagate(sourceVal, target, targetVal, f, relatedCallSite, isUnbalancedReturn); 57 | 58 | }; 59 | 60 | 61 | private class CacheEntry { 62 | private N n; 63 | private JoinKey sourceKey; 64 | private JoinKey targetKey; 65 | 66 | public CacheEntry(N n, JoinKey sourceKey, JoinKey targetKey) { 67 | super(); 68 | this.n = n; 69 | this.sourceKey = sourceKey; 70 | this.targetKey = targetKey; 71 | } 72 | 73 | @Override 74 | public int hashCode() { 75 | final int prime = 31; 76 | int result = 1; 77 | result = prime * result + ((sourceKey == null) ? 0 : sourceKey.hashCode()); 78 | result = prime * result + ((targetKey == null) ? 0 : targetKey.hashCode()); 79 | result = prime * result + ((n == null) ? 0 : n.hashCode()); 80 | return result; 81 | } 82 | 83 | @Override 84 | public boolean equals(Object obj) { 85 | if (this == obj) 86 | return true; 87 | if (obj == null) 88 | return false; 89 | if (getClass() != obj.getClass()) 90 | return false; 91 | @SuppressWarnings({ "unchecked" }) 92 | CacheEntry other = (CacheEntry) obj; 93 | if (sourceKey == null) { 94 | if (other.sourceKey != null) 95 | return false; 96 | } else if (!sourceKey.equals(other.sourceKey)) 97 | return false; 98 | if (targetKey == null) { 99 | if (other.targetKey != null) 100 | return false; 101 | } else if (!targetKey.equals(other.targetKey)) 102 | return false; 103 | if (n == null) { 104 | if (other.n != null) 105 | return false; 106 | } else if (!n.equals(other.n)) 107 | return false; 108 | return true; 109 | } 110 | } 111 | 112 | 113 | 114 | } 115 | -------------------------------------------------------------------------------- /src/heros/solver/LinkedNode.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2013 Eric Bodden. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Eric Bodden - initial API and implementation 10 | ******************************************************************************/ 11 | package heros.solver; 12 | 13 | /** 14 | * A data-flow fact that can be linked with other equal facts. 15 | * Equality and hash-code operations must not take the linking data structures into account! 16 | * 17 | * @deprecated Use {@link JoinHandlingNode} instead. 18 | */ 19 | @Deprecated 20 | public interface LinkedNode { 21 | /** 22 | * Links this node to a neighbor node, i.e., to an abstraction that would have been merged 23 | * with this one of paths were not being tracked. 24 | */ 25 | public void addNeighbor(D originalAbstraction); 26 | 27 | public void setCallingContext(D callingContext); 28 | } -------------------------------------------------------------------------------- /src/heros/solver/NotesOnSummaryGeneration.txt: -------------------------------------------------------------------------------- 1 | 1.) determine fixed methods and fixed call sites 2 | 2.) summarize fixed methods; special care needs to be taken if they are in an SCC 3 | 3.) summarize information at fixed call sites within non-fixed methods 4 | 4.) find a good way to store summaries 5 | 5.) find a way to take summaries into account on next run -------------------------------------------------------------------------------- /src/heros/solver/Pair.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2012 Eric Bodden. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Eric Bodden - initial API and implementation 10 | ******************************************************************************/ 11 | package heros.solver; 12 | 13 | //copied from soot.toolkits.scalar 14 | public class Pair { 15 | protected T o1; 16 | protected U o2; 17 | 18 | protected int hashCode = 0; 19 | 20 | public Pair() { 21 | o1 = null; 22 | o2 = null; 23 | } 24 | 25 | public Pair(T o1, U o2) { 26 | this.o1 = o1; 27 | this.o2 = o2; 28 | } 29 | 30 | @Override 31 | public int hashCode() { 32 | if (hashCode != 0) 33 | return hashCode; 34 | 35 | final int prime = 31; 36 | int result = 1; 37 | result = prime * result + ((o1 == null) ? 0 : o1.hashCode()); 38 | result = prime * result + ((o2 == null) ? 0 : o2.hashCode()); 39 | hashCode = result; 40 | 41 | return hashCode; 42 | } 43 | 44 | @Override 45 | public boolean equals(Object obj) { 46 | if (this == obj) 47 | return true; 48 | if (obj == null) 49 | return false; 50 | if (getClass() != obj.getClass()) 51 | return false; 52 | @SuppressWarnings("rawtypes") 53 | Pair other = (Pair) obj; 54 | if (o1 == null) { 55 | if (other.o1 != null) 56 | return false; 57 | } else if (!o1.equals(other.o1)) 58 | return false; 59 | if (o2 == null) { 60 | if (other.o2 != null) 61 | return false; 62 | } else if (!o2.equals(other.o2)) 63 | return false; 64 | return true; 65 | } 66 | 67 | public String toString() { 68 | return "Pair " + o1 + "," + o2; 69 | } 70 | 71 | public T getO1() { 72 | return o1; 73 | } 74 | 75 | public U getO2() { 76 | return o2; 77 | } 78 | 79 | public void setO1(T no1) { 80 | o1 = no1; 81 | hashCode = 0; 82 | } 83 | 84 | public void setO2(U no2) { 85 | o2 = no2; 86 | hashCode = 0; 87 | } 88 | 89 | public void setPair(T no1, U no2) { 90 | o1 = no1; 91 | o2 = no2; 92 | hashCode = 0; 93 | } 94 | 95 | } 96 | -------------------------------------------------------------------------------- /src/heros/solver/PathEdge.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2012 Eric Bodden. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Eric Bodden - initial API and implementation 10 | ******************************************************************************/ 11 | package heros.solver; 12 | 13 | import heros.InterproceduralCFG; 14 | 15 | /** 16 | * A path edge as described in the IFDS/IDE algorithms. 17 | * The source node is implicit: it can be computed from the target by using the {@link InterproceduralCFG}. 18 | * Hence, we don't store it. 19 | * 20 | * @param The type of nodes in the interprocedural control-flow graph. Typically {@link Unit}. 21 | * @param The type of data-flow facts to be computed by the tabulation problem. 22 | */ 23 | public class PathEdge { 24 | 25 | protected final N target; 26 | protected final D dSource, dTarget; 27 | protected final int hashCode; 28 | 29 | /** 30 | * @param dSource The fact at the source. 31 | * @param target The target statement. 32 | * @param dTarget The fact at the target. 33 | */ 34 | public PathEdge(D dSource, N target, D dTarget) { 35 | super(); 36 | this.target = target; 37 | this.dSource = dSource; 38 | this.dTarget = dTarget; 39 | 40 | final int prime = 31; 41 | int result = 1; 42 | result = prime * result + ((dSource == null) ? 0 : dSource.hashCode()); 43 | result = prime * result + ((dTarget == null) ? 0 : dTarget.hashCode()); 44 | result = prime * result + ((target == null) ? 0 : target.hashCode()); 45 | this.hashCode = result; 46 | } 47 | 48 | public N getTarget() { 49 | return target; 50 | } 51 | 52 | public D factAtSource() { 53 | return dSource; 54 | } 55 | 56 | public D factAtTarget() { 57 | return dTarget; 58 | } 59 | 60 | @Override 61 | public int hashCode() { 62 | return hashCode; 63 | } 64 | 65 | @Override 66 | public boolean equals(Object obj) { 67 | if (this == obj) 68 | return true; 69 | if (obj == null) 70 | return false; 71 | if (getClass() != obj.getClass()) 72 | return false; 73 | @SuppressWarnings("rawtypes") 74 | PathEdge other = (PathEdge) obj; 75 | if (dSource == null) { 76 | if (other.dSource != null) 77 | return false; 78 | } else if (!dSource.equals(other.dSource)) 79 | return false; 80 | if (dTarget == null) { 81 | if (other.dTarget != null) 82 | return false; 83 | } else if (!dTarget.equals(other.dTarget)) 84 | return false; 85 | if (target == null) { 86 | if (other.target != null) 87 | return false; 88 | } else if (!target.equals(other.target)) 89 | return false; 90 | return true; 91 | } 92 | 93 | @Override 94 | public String toString() { 95 | StringBuffer result = new StringBuffer(); 96 | result.append("<"); 97 | result.append(dSource); 98 | result.append("> -> <"); 99 | result.append(target.toString()); 100 | result.append(","); 101 | result.append(dTarget); 102 | result.append(">"); 103 | return result.toString(); 104 | } 105 | 106 | } 107 | -------------------------------------------------------------------------------- /src/heros/solver/PathTrackingIFDSSolver.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2013 Eric Bodden. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Eric Bodden - initial API and implementation 10 | ******************************************************************************/ 11 | package heros.solver; 12 | 13 | import heros.EdgeFunction; 14 | import heros.IFDSTabulationProblem; 15 | import heros.InterproceduralCFG; 16 | 17 | import java.util.Map; 18 | 19 | import com.google.common.collect.Maps; 20 | 21 | /** 22 | * An {@link IFDSSolver} that tracks paths for reporting. To do so, it requires that data-flow abstractions implement the LinkedNode interface. 23 | * The solver implements a cache of data-flow facts for each statement and source value. If for the same statement and source value the same 24 | * target value is seen again (as determined through a cache hit), then the solver propagates the cached value but at the same time links 25 | * both target values with one another. 26 | * 27 | * @author Eric Bodden 28 | * @deprecated Use {@link JoinHandlingNodesIFDSSolver} instead. 29 | */ 30 | @Deprecated 31 | public class PathTrackingIFDSSolver, M, I extends InterproceduralCFG> extends IFDSSolver { 32 | 33 | public PathTrackingIFDSSolver(IFDSTabulationProblem ifdsProblem) { 34 | super(ifdsProblem); 35 | } 36 | 37 | protected final Map> cache = Maps.newHashMap(); 38 | 39 | @Override 40 | protected void propagate(D sourceVal, N target, D targetVal, EdgeFunction f, N relatedCallSite, boolean isUnbalancedReturn) { 41 | CacheEntry currentCacheEntry = new CacheEntry(target, sourceVal, targetVal); 42 | 43 | boolean propagate = false; 44 | synchronized (this) { 45 | if (cache.containsKey(currentCacheEntry)) { 46 | LinkedNode existingTargetVal = cache.get(currentCacheEntry); 47 | if (existingTargetVal != targetVal) 48 | existingTargetVal.addNeighbor(targetVal); 49 | } else { 50 | cache.put(currentCacheEntry, targetVal); 51 | propagate = true; 52 | } 53 | } 54 | 55 | if (propagate) 56 | super.propagate(sourceVal, target, targetVal, f, relatedCallSite, isUnbalancedReturn); 57 | 58 | }; 59 | 60 | 61 | private class CacheEntry { 62 | private N n; 63 | private D sourceVal; 64 | private D targetVal; 65 | 66 | public CacheEntry(N n, D sourceVal, D targetVal) { 67 | super(); 68 | this.n = n; 69 | this.sourceVal = sourceVal; 70 | this.targetVal = targetVal; 71 | } 72 | 73 | @Override 74 | public int hashCode() { 75 | final int prime = 31; 76 | int result = 1; 77 | result = prime * result + ((sourceVal == null) ? 0 : sourceVal.hashCode()); 78 | result = prime * result + ((targetVal == null) ? 0 : targetVal.hashCode()); 79 | result = prime * result + ((n == null) ? 0 : n.hashCode()); 80 | return result; 81 | } 82 | 83 | @Override 84 | public boolean equals(Object obj) { 85 | if (this == obj) 86 | return true; 87 | if (obj == null) 88 | return false; 89 | if (getClass() != obj.getClass()) 90 | return false; 91 | @SuppressWarnings({ "unchecked" }) 92 | CacheEntry other = (CacheEntry) obj; 93 | if (sourceVal == null) { 94 | if (other.sourceVal != null) 95 | return false; 96 | } else if (!sourceVal.equals(other.sourceVal)) 97 | return false; 98 | if (targetVal == null) { 99 | if (other.targetVal != null) 100 | return false; 101 | } else if (!targetVal.equals(other.targetVal)) 102 | return false; 103 | if (n == null) { 104 | if (other.n != null) 105 | return false; 106 | } else if (!n.equals(other.n)) 107 | return false; 108 | return true; 109 | } 110 | } 111 | 112 | 113 | 114 | } 115 | -------------------------------------------------------------------------------- /src/heros/template/DefaultIDETabulationProblem.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2012 Eric Bodden. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Eric Bodden - initial API and implementation 10 | ******************************************************************************/ 11 | package heros.template; 12 | 13 | import heros.EdgeFunction; 14 | import heros.EdgeFunctions; 15 | import heros.IDETabulationProblem; 16 | import heros.InterproceduralCFG; 17 | import heros.MeetLattice; 18 | 19 | /** 20 | * This is a template for {@link IDETabulationProblem}s that automatically caches values 21 | * that ought to be cached. This class uses the Factory Method design pattern. 22 | * The {@link InterproceduralCFG} is passed into the constructor so that it can be conveniently 23 | * reused for solving multiple different {@link IDETabulationProblem}s. 24 | * This class is specific to Soot. 25 | * 26 | * @param The type of data-flow facts to be computed by the tabulation problem. 27 | * @param The type of values to be computed along flow edges. 28 | * @param The type of inter-procedural control-flow graph being used. 29 | */ 30 | public abstract class DefaultIDETabulationProblem> 31 | extends DefaultIFDSTabulationProblem implements IDETabulationProblem{ 32 | 33 | private final EdgeFunction allTopFunction; 34 | private final MeetLattice joinLattice; 35 | private final EdgeFunctions edgeFunctions; 36 | 37 | public DefaultIDETabulationProblem(I icfg) { 38 | super(icfg); 39 | this.allTopFunction = createAllTopFunction(); 40 | this.joinLattice = createMeetLattice(); 41 | this.edgeFunctions = createEdgeFunctionsFactory(); 42 | } 43 | 44 | protected abstract EdgeFunction createAllTopFunction(); 45 | 46 | protected abstract MeetLattice createMeetLattice(); 47 | 48 | protected abstract EdgeFunctions createEdgeFunctionsFactory(); 49 | 50 | @Override 51 | public final EdgeFunction allTopFunction() { 52 | return allTopFunction; 53 | } 54 | 55 | @Override 56 | public final MeetLattice meetLattice() { 57 | return joinLattice; 58 | } 59 | 60 | @Override 61 | public final EdgeFunctions edgeFunctions() { 62 | return edgeFunctions; 63 | } 64 | 65 | } 66 | -------------------------------------------------------------------------------- /src/heros/template/DefaultIFDSTabulationProblem.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2012 Eric Bodden. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Eric Bodden - initial API and implementation 10 | ******************************************************************************/ 11 | package heros.template; 12 | 13 | import heros.FlowFunctions; 14 | import heros.IFDSTabulationProblem; 15 | import heros.InterproceduralCFG; 16 | 17 | /** 18 | * This is a template for {@link IFDSTabulationProblem}s that automatically caches values 19 | * that ought to be cached. This class uses the Factory Method design pattern. 20 | * The {@link InterproceduralCFG} is passed into the constructor so that it can be conveniently 21 | * reused for solving multiple different {@link IFDSTabulationProblem}s. 22 | * This class is specific to Soot. 23 | * 24 | * @param The type of data-flow facts to be computed by the tabulation problem. 25 | */ 26 | public abstract class DefaultIFDSTabulationProblem> implements IFDSTabulationProblem { 27 | 28 | private final I icfg; 29 | private FlowFunctions flowFunctions; 30 | private D zeroValue; 31 | 32 | public DefaultIFDSTabulationProblem(I icfg) { 33 | this.icfg = icfg; 34 | } 35 | 36 | protected abstract FlowFunctions createFlowFunctionsFactory(); 37 | 38 | /** A factory method to create and return the ZERO value. Meant to be overwritten by subclasses. 39 | Clients should call zeroValue() instead to access the singleton zero value. */ 40 | protected abstract D createZeroValue(); 41 | 42 | @Override 43 | public final FlowFunctions flowFunctions() { 44 | if(flowFunctions==null) { 45 | flowFunctions = createFlowFunctionsFactory(); 46 | } 47 | return flowFunctions; 48 | } 49 | 50 | @Override 51 | public I interproceduralCFG() { 52 | return icfg; 53 | } 54 | 55 | @Override 56 | public final D zeroValue() { 57 | if(zeroValue==null) { 58 | zeroValue = createZeroValue(); 59 | } 60 | return zeroValue; 61 | } 62 | 63 | @Override 64 | public boolean followReturnsPastSeeds() { 65 | return false; 66 | } 67 | 68 | @Override 69 | public boolean autoAddZero() { 70 | return true; 71 | } 72 | 73 | @Override 74 | public int numThreads() { 75 | return Runtime.getRuntime().availableProcessors(); 76 | } 77 | 78 | @Override 79 | public boolean computeValues() { 80 | return true; 81 | } 82 | 83 | @Override 84 | public boolean recordEdges() { 85 | return false; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /src/heros/util/SootThreadGroup.java: -------------------------------------------------------------------------------- 1 | package heros.util; 2 | 3 | public class SootThreadGroup extends ThreadGroup { 4 | 5 | private final Thread startThread; 6 | 7 | public SootThreadGroup() { 8 | super("Soot Threadgroup"); 9 | if (Thread.currentThread().getThreadGroup() instanceof SootThreadGroup) { 10 | SootThreadGroup group = (SootThreadGroup) Thread.currentThread().getThreadGroup(); 11 | startThread = group.getStarterThread(); 12 | } else { 13 | startThread = Thread.currentThread(); 14 | } 15 | } 16 | 17 | public Thread getStarterThread() { 18 | return startThread; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/heros/utilities/DefaultValueMap.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2015 Johannes Lerch. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Johannes Lerch - initial API and implementation 10 | ******************************************************************************/ 11 | package heros.utilities; 12 | 13 | import java.util.Collection; 14 | import java.util.HashMap; 15 | import java.util.Map; 16 | import java.util.Set; 17 | 18 | public abstract class DefaultValueMap implements Map { 19 | 20 | private HashMap map; 21 | 22 | public DefaultValueMap() { 23 | map = new HashMap(); 24 | } 25 | 26 | @Override 27 | public int size() { 28 | return map.size(); 29 | } 30 | 31 | @Override 32 | public boolean isEmpty() { 33 | return map.isEmpty(); 34 | } 35 | 36 | @Override 37 | public boolean containsKey(Object key) { 38 | return map.containsKey(key); 39 | } 40 | 41 | @Override 42 | public boolean containsValue(Object value) { 43 | return map.containsValue(value); 44 | } 45 | 46 | protected abstract V createItem(K key); 47 | 48 | public V getOrCreate(K key) { 49 | if (!map.containsKey(key)) { 50 | V value = createItem((K) key); 51 | map.put((K) key, value); 52 | return value; 53 | } 54 | 55 | return map.get(key); 56 | } 57 | 58 | @Override 59 | public V get(Object key) { 60 | return map.get(key); 61 | } 62 | 63 | @Override 64 | public V put(K key, V value) { 65 | return map.put(key, value); 66 | } 67 | 68 | @Override 69 | public V remove(Object key) { 70 | return map.remove(key); 71 | } 72 | 73 | @Override 74 | public void putAll(Map m) { 75 | map.putAll(m); 76 | } 77 | 78 | @Override 79 | public void clear() { 80 | map.clear(); 81 | } 82 | 83 | @Override 84 | public Set keySet() { 85 | return map.keySet(); 86 | } 87 | 88 | @Override 89 | public Collection values() { 90 | return map.values(); 91 | } 92 | 93 | @Override 94 | public Set> entrySet() { 95 | return map.entrySet(); 96 | } 97 | 98 | } 99 | -------------------------------------------------------------------------------- /src/heros/utilities/JsonArray.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2015 Johannes Lerch. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Johannes Lerch - initial API and implementation 10 | ******************************************************************************/ 11 | package heros.utilities; 12 | 13 | import java.util.List; 14 | 15 | import com.google.common.collect.Lists; 16 | 17 | public class JsonArray { 18 | 19 | private List items = Lists.newLinkedList(); 20 | 21 | public void add(String item) { 22 | items.add(item); 23 | } 24 | 25 | public void write(StringBuilder builder, int tabs) { 26 | builder.append("[\n"); 27 | for(String item: items) { 28 | JsonDocument.tabs(tabs+1, builder); builder.append("\""+item+"\",\n"); 29 | } 30 | 31 | if(!items.isEmpty()) 32 | builder.delete(builder.length()-2, builder.length()-1); 33 | 34 | JsonDocument.tabs(tabs, builder); builder.append("]"); 35 | } 36 | } -------------------------------------------------------------------------------- /src/heros/utilities/JsonDocument.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2015 Johannes Lerch. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Johannes Lerch - initial API and implementation 10 | ******************************************************************************/ 11 | package heros.utilities; 12 | 13 | import java.util.Map; 14 | import java.util.Map.Entry; 15 | 16 | import com.google.common.collect.Maps; 17 | 18 | public class JsonDocument { 19 | 20 | private DefaultValueMap documents = new DefaultValueMap() { 21 | @Override 22 | protected JsonDocument createItem(String key) { 23 | return new JsonDocument(); 24 | } 25 | }; 26 | private DefaultValueMap arrays = new DefaultValueMap() { 27 | @Override 28 | protected JsonArray createItem(String key) { 29 | return new JsonArray(); 30 | } 31 | }; 32 | private Map keyValuePairs = Maps.newHashMap(); 33 | 34 | public JsonDocument doc(String key) { 35 | return documents.getOrCreate(key); 36 | } 37 | 38 | public JsonDocument doc(String key, JsonDocument doc) { 39 | if(documents.containsKey(key)) 40 | throw new IllegalArgumentException("There is already a document registered for key: "+key); 41 | documents.put(key, doc); 42 | return doc; 43 | } 44 | 45 | public JsonArray array(String key) { 46 | return arrays.getOrCreate(key); 47 | } 48 | 49 | public void keyValue(String key, String value) { 50 | keyValuePairs.put(key, value); 51 | } 52 | 53 | @Override 54 | public String toString() { 55 | StringBuilder builder = new StringBuilder(); 56 | write(builder, 0); 57 | return builder.toString(); 58 | } 59 | 60 | public void write(StringBuilder builder, int tabs) { 61 | builder.append("{\n"); 62 | 63 | for(Entry entry : keyValuePairs.entrySet()) { 64 | tabs(tabs+1, builder); builder.append("\""+entry.getKey()+"\": \""+entry.getValue()+"\",\n"); 65 | } 66 | 67 | for(Entry entry : arrays.entrySet()) { 68 | tabs(tabs+1, builder); builder.append("\""+entry.getKey()+"\": "); 69 | entry.getValue().write(builder, tabs+1); 70 | builder.append(",\n"); 71 | } 72 | 73 | for(Entry entry : documents.entrySet()) { 74 | tabs(tabs+1, builder); builder.append("\""+entry.getKey()+"\": "); 75 | entry.getValue().write(builder, tabs+1); 76 | builder.append(",\n"); 77 | } 78 | 79 | if(!keyValuePairs.isEmpty() || !arrays.isEmpty() || !documents.isEmpty()) 80 | builder.delete(builder.length()-2, builder.length()-1); 81 | 82 | tabs(tabs, builder); builder.append("}"); 83 | } 84 | 85 | static void tabs(int tabs, StringBuilder builder) { 86 | for(int i=0; i getDeltaConstraint(String... fieldRefs) { 40 | return new DeltaConstraint(getDelta(fieldRefs)); 41 | } 42 | 43 | private static Delta getDelta(String... fieldRefs) { 44 | AccessPath accPath = createAccessPath(fieldRefs); 45 | return new AccessPath().getDeltaTo(accPath); 46 | } 47 | 48 | protected static AccessPath createAccessPath(String... fieldRefs) { 49 | AccessPath accPath = new AccessPath(); 50 | for (String fieldRef : fieldRefs) { 51 | accPath = accPath.append(fieldRef); 52 | } 53 | return accPath; 54 | } 55 | 56 | private PerAccessPathMethodAnalyzer analyzer; 57 | private Statement joinStmt; 58 | private ControlFlowJoinResolver sut; 59 | private TestFact fact; 60 | private InterestCallback callback; 61 | private Resolver callEdgeResolver; 62 | 63 | @Before 64 | public void before() { 65 | analyzer = mock(PerAccessPathMethodAnalyzer.class); 66 | joinStmt = new Statement("joinStmt"); 67 | sut = new ControlFlowJoinResolver(mock(FactMergeHandler.class), analyzer, joinStmt, 68 | new Debugger.NullDebugger()); 69 | fact = new TestFact("value"); 70 | callback = mock(InterestCallback.class); 71 | callEdgeResolver = mock(CallEdgeResolver.class); 72 | } 73 | 74 | @Test 75 | public void emptyIncomingFact() { 76 | sut.addIncoming(new WrappedFact(fact, createAccessPath(), callEdgeResolver)); 77 | verify(analyzer).processFlowFromJoinStmt(eq(new WrappedFactAtStatement(joinStmt, new WrappedFact(fact, createAccessPath(), sut)))); 78 | assertTrue(sut.isInterestGiven()); 79 | } 80 | 81 | @Test 82 | public void resolveViaIncomingFact() { 83 | sut.resolve(getDeltaConstraint("a"), callback); 84 | sut.addIncoming(new WrappedFact(fact, createAccessPath("a"), callEdgeResolver)); 85 | verify(callback).interest(eq(analyzer), argThat(new ResolverArgumentMatcher(createAccessPath("a")))); 86 | } 87 | 88 | @Test 89 | public void registerCallbackAtIncomingResolver() { 90 | Resolver resolver = mock(Resolver.class); 91 | sut.addIncoming(new WrappedFact(fact, createAccessPath(), resolver)); 92 | sut.resolve(getDeltaConstraint("a"), callback); 93 | verify(resolver).resolve(eq(getDeltaConstraint("a")), any(InterestCallback.class)); 94 | } 95 | 96 | @Test 97 | public void resolveViaIncomingResolver() { 98 | Resolver resolver = mock(Resolver.class); 99 | final Resolver nestedResolver = mock(Resolver.class); 100 | Mockito.doAnswer(new Answer(){ 101 | @Override 102 | public Object answer(InvocationOnMock invocation) throws Throwable { 103 | InterestCallback argCallback = 104 | (InterestCallback) invocation.getArguments()[1]; 105 | argCallback.interest(analyzer, nestedResolver); 106 | return null; 107 | } 108 | }).when(resolver).resolve(eq(getDeltaConstraint("a")), any(InterestCallback.class)); 109 | 110 | sut.addIncoming(new WrappedFact(fact, createAccessPath(), resolver)); 111 | sut.resolve(getDeltaConstraint("a"), callback); 112 | 113 | verify(callback).interest(eq(analyzer), eq(nestedResolver)); 114 | } 115 | 116 | 117 | private class ResolverArgumentMatcher implements ArgumentMatcher> { 118 | 119 | private AccessPath accPath; 120 | 121 | public ResolverArgumentMatcher(AccessPath accPath) { 122 | this.accPath = accPath; 123 | } 124 | 125 | @Override 126 | public boolean matches(ControlFlowJoinResolver resolver) { 127 | return resolver.isInterestGiven() && resolver.resolvedAccessPath.equals(accPath) && resolver.getJoinStmt().equals(joinStmt); 128 | } 129 | } 130 | } 131 | -------------------------------------------------------------------------------- /test/heros/utilities/Edge.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2015 Johannes Lerch. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Johannes Lerch - initial API and implementation 10 | ******************************************************************************/ 11 | package heros.utilities; 12 | 13 | 14 | public abstract class Edge { 15 | public final ExpectedFlowFunction[] flowFunctions; 16 | public boolean includeInCfg = true; 17 | 18 | public Edge(ExpectedFlowFunction...flowFunctions) { 19 | this.flowFunctions = flowFunctions; 20 | for(ExpectedFlowFunction ff : flowFunctions) { 21 | ff.edge = this; 22 | } 23 | } 24 | 25 | public abstract void accept(EdgeVisitor visitor); 26 | 27 | 28 | public static class NormalEdge extends Edge { 29 | 30 | public final Statement unit; 31 | public final Statement succUnit; 32 | 33 | public NormalEdge(Statement unit, Statement succUnit, ExpectedFlowFunction...flowFunctions) { 34 | super(flowFunctions); 35 | this.unit = unit; 36 | this.succUnit = succUnit; 37 | } 38 | 39 | @Override 40 | public String toString() { 41 | return String.format("%s -normal-> %s", unit, succUnit); 42 | } 43 | 44 | @Override 45 | public void accept(EdgeVisitor visitor) { 46 | visitor.visit(this); 47 | } 48 | } 49 | 50 | public static class CallEdge extends Edge { 51 | 52 | public final Statement callSite; 53 | public final TestMethod destinationMethod; 54 | 55 | public CallEdge(Statement callSite, TestMethod destinationMethod, ExpectedFlowFunction...flowFunctions) { 56 | super(flowFunctions); 57 | this.callSite = callSite; 58 | this.destinationMethod = destinationMethod; 59 | } 60 | 61 | @Override 62 | public String toString() { 63 | return String.format("%s -call-> %s", callSite, destinationMethod); 64 | } 65 | 66 | @Override 67 | public void accept(EdgeVisitor visitor) { 68 | visitor.visit(this); 69 | } 70 | } 71 | 72 | public static class Call2ReturnEdge extends Edge { 73 | public final Statement callSite; 74 | public final Statement returnSite; 75 | 76 | public Call2ReturnEdge(Statement callSite, Statement returnSite, ExpectedFlowFunction...flowFunctions) { 77 | super(flowFunctions); 78 | this.callSite = callSite; 79 | this.returnSite = returnSite; 80 | } 81 | 82 | @Override 83 | public String toString() { 84 | return String.format("%s -call2ret-> %s", callSite, returnSite); 85 | } 86 | 87 | @Override 88 | public void accept(EdgeVisitor visitor) { 89 | visitor.visit(this); 90 | } 91 | } 92 | 93 | public static class ReturnEdge extends Edge { 94 | 95 | public final Statement exitStmt; 96 | public final Statement returnSite; 97 | public final Statement callSite; 98 | public TestMethod calleeMethod; 99 | 100 | public ReturnEdge(Statement callSite, Statement exitStmt, Statement returnSite, ExpectedFlowFunction...flowFunctions) { 101 | super(flowFunctions); 102 | this.callSite = callSite; 103 | this.exitStmt = exitStmt; 104 | this.returnSite = returnSite; 105 | if(callSite == null || returnSite == null) 106 | includeInCfg = false; 107 | } 108 | 109 | @Override 110 | public String toString() { 111 | return String.format("%s -return-> %s", exitStmt, returnSite); 112 | } 113 | 114 | @Override 115 | public void accept(EdgeVisitor visitor) { 116 | visitor.visit(this); 117 | } 118 | } 119 | 120 | 121 | public static interface EdgeVisitor { 122 | void visit(NormalEdge edge); 123 | void visit(CallEdge edge); 124 | void visit(Call2ReturnEdge edge); 125 | void visit(ReturnEdge edge); 126 | } 127 | } -------------------------------------------------------------------------------- /test/heros/utilities/EdgeBuilder.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2014 Johannes Lerch. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Johannes Lerch - initial API and implementation 10 | ******************************************************************************/ 11 | package heros.utilities; 12 | 13 | 14 | import java.util.Collection; 15 | import java.util.List; 16 | 17 | import com.google.common.collect.Lists; 18 | 19 | 20 | public abstract class EdgeBuilder { 21 | 22 | protected List edges = Lists.newLinkedList(); 23 | public Collection edges() { 24 | if(edges.isEmpty()) { 25 | throw new IllegalStateException("Not a single edge created on EdgeBuilder: "+toString()); 26 | } 27 | 28 | return edges; 29 | } 30 | 31 | public static class CallSiteBuilder extends EdgeBuilder { 32 | 33 | private Statement callSite; 34 | 35 | public CallSiteBuilder(Statement callSite) { 36 | this.callSite = callSite; 37 | } 38 | 39 | public CallSiteBuilder calls(String method, ExpectedFlowFunction...flows) { 40 | edges.add(new Edge.CallEdge(callSite, new TestMethod(method), flows)); 41 | return this; 42 | } 43 | 44 | public CallSiteBuilder retSite(String returnSite, ExpectedFlowFunction...flows) { 45 | edges.add(new Edge.Call2ReturnEdge(callSite, new Statement(returnSite), flows)); 46 | return this; 47 | } 48 | } 49 | 50 | public static class NormalStmtBuilder extends EdgeBuilder { 51 | 52 | private Statement stmt; 53 | private ExpectedFlowFunction[] flowFunctions; 54 | 55 | public NormalStmtBuilder(Statement stmt, ExpectedFlowFunction[] flowFunctions) { 56 | this.stmt = stmt; 57 | this.flowFunctions = flowFunctions; 58 | } 59 | 60 | public NormalStmtBuilder succ(String succ) { 61 | edges.add(new Edge.NormalEdge(stmt, new Statement(succ), flowFunctions)); 62 | return this; 63 | } 64 | } 65 | 66 | public static class ExitStmtBuilder extends EdgeBuilder { 67 | 68 | private Statement exitStmt; 69 | 70 | public ExitStmtBuilder(Statement exitStmt) { 71 | this.exitStmt = exitStmt; 72 | } 73 | 74 | public ExitStmtBuilder expectArtificalFlow(ExpectedFlowFunction...flows) { 75 | edges.add(new Edge.ReturnEdge(null, exitStmt, null, flows)); 76 | return this; 77 | } 78 | 79 | public ExitStmtBuilder returns(Statement callSite, Statement returnSite, ExpectedFlowFunction... flows) { 80 | edges.add(new Edge.ReturnEdge(callSite, exitStmt, returnSite, flows)); 81 | return this; 82 | } 83 | 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /test/heros/utilities/ExpectedFlowFunction.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2015 Johannes Lerch. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Johannes Lerch - initial API and implementation 10 | ******************************************************************************/ 11 | package heros.utilities; 12 | 13 | import heros.fieldsens.AccessPathHandler; 14 | import heros.fieldsens.FlowFunction; 15 | 16 | import com.google.common.base.Joiner; 17 | 18 | public abstract class ExpectedFlowFunction { 19 | 20 | public final Fact source; 21 | public final Fact[] targets; 22 | public Edge edge; 23 | int times; 24 | 25 | public ExpectedFlowFunction(int times, Fact source, Fact... targets) { 26 | this.times = times; 27 | this.source = source; 28 | this.targets = targets; 29 | } 30 | 31 | @Override 32 | public String toString() { 33 | return String.format("%s: %s -> {%s}", edge, source, Joiner.on(",").join(targets)); 34 | } 35 | 36 | public abstract String transformerString(); 37 | 38 | public abstract FlowFunction.ConstrainedFact apply(TestFact target, AccessPathHandler accPathHandler); 39 | } -------------------------------------------------------------------------------- /test/heros/utilities/JoinableFact.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2014 Johannes Lerch. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Johannes Lerch - initial API and implementation 10 | ******************************************************************************/ 11 | package heros.utilities; 12 | 13 | import heros.solver.JoinHandlingNode; 14 | import heros.solver.LinkedNode; 15 | import heros.solver.JoinHandlingNode.JoinKey; 16 | 17 | public class JoinableFact implements JoinHandlingNode { 18 | 19 | public final String name; 20 | 21 | public JoinableFact(String name) { 22 | this.name = name; 23 | } 24 | 25 | @Override 26 | public int hashCode() { 27 | final int prime = 31; 28 | int result = 1; 29 | result = prime * result + ((name == null) ? 0 : name.hashCode()); 30 | return result; 31 | } 32 | 33 | @Override 34 | public boolean equals(Object obj) { 35 | if (this == obj) 36 | return true; 37 | if (obj == null) 38 | return false; 39 | if (!(obj instanceof JoinableFact)) 40 | return false; 41 | JoinableFact other = (JoinableFact) obj; 42 | if (name == null) { 43 | if (other.name != null) 44 | return false; 45 | } else if (!name.equals(other.name)) 46 | return false; 47 | return true; 48 | } 49 | 50 | @Override 51 | public String toString() { 52 | return "[Fact "+name+"]"; 53 | } 54 | 55 | @Override 56 | public void setCallingContext(JoinableFact callingContext) { 57 | 58 | } 59 | 60 | @Override 61 | public heros.solver.JoinHandlingNode.JoinKey createJoinKey() { 62 | return new TestJoinKey(); 63 | } 64 | 65 | @Override 66 | public boolean handleJoin(JoinableFact joiningNode) { 67 | return true; 68 | } 69 | 70 | private class TestJoinKey extends JoinKey { 71 | 72 | private JoinableFact getFact() { 73 | return JoinableFact.this; 74 | } 75 | 76 | @Override 77 | public boolean equals(Object obj) { 78 | if (obj instanceof TestJoinKey) { 79 | return getFact().equals(((TestJoinKey) obj).getFact()); 80 | } 81 | throw new IllegalArgumentException(); 82 | } 83 | 84 | @Override 85 | public int hashCode() { 86 | return JoinableFact.this.hashCode(); 87 | } 88 | } 89 | } 90 | -------------------------------------------------------------------------------- /test/heros/utilities/Statement.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2014 Johannes Lerch. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Johannes Lerch - initial API and implementation 10 | ******************************************************************************/ 11 | package heros.utilities; 12 | 13 | public class Statement { 14 | 15 | public final String identifier; 16 | 17 | public Statement(String identifier) { 18 | this.identifier = identifier; 19 | } 20 | 21 | @Override 22 | public int hashCode() { 23 | final int prime = 31; 24 | int result = 1; 25 | result = prime * result + ((identifier == null) ? 0 : identifier.hashCode()); 26 | return result; 27 | } 28 | 29 | @Override 30 | public boolean equals(Object obj) { 31 | if (this == obj) 32 | return true; 33 | if (obj == null) 34 | return false; 35 | if (!(obj instanceof Statement)) 36 | return false; 37 | Statement other = (Statement) obj; 38 | if (identifier == null) { 39 | if (other.identifier != null) 40 | return false; 41 | } else if (!identifier.equals(other.identifier)) 42 | return false; 43 | return true; 44 | } 45 | 46 | @Override 47 | public String toString() { 48 | return "[Statement "+identifier+"]"; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /test/heros/utilities/TestDebugger.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2015 Johannes Lerch. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Johannes Lerch - initial API and implementation 10 | ******************************************************************************/ 11 | package heros.utilities; 12 | 13 | import java.io.FileWriter; 14 | import java.io.IOException; 15 | import java.util.Set; 16 | 17 | import com.google.common.collect.Sets; 18 | 19 | import heros.InterproceduralCFG; 20 | import heros.fieldsens.Debugger; 21 | import heros.fieldsens.FlowFunction.Constraint; 22 | import heros.fieldsens.PerAccessPathMethodAnalyzer; 23 | import heros.fieldsens.Resolver; 24 | import heros.fieldsens.structs.WrappedFactAtStatement; 25 | 26 | public class TestDebugger implements Debugger { 27 | 28 | private JsonDocument root = new JsonDocument(); 29 | private InterproceduralCFG icfg; 30 | 31 | public void writeJsonDebugFile(String filename) { 32 | try { 33 | FileWriter writer = new FileWriter(filename); 34 | StringBuilder builder = new StringBuilder(); 35 | builder.append("var root="); 36 | root.write(builder, 0); 37 | writer.write(builder.toString()); 38 | writer.close(); 39 | } catch (IOException e) { 40 | e.printStackTrace(); 41 | } 42 | } 43 | 44 | /* (non-Javadoc) 45 | * @see heros.alias.Debugger#setICFG(I) 46 | */ 47 | @Override 48 | public void setICFG(InterproceduralCFG icfg) { 49 | this.icfg = icfg; 50 | } 51 | 52 | /* (non-Javadoc) 53 | * @see heros.alias.Debugger#initialSeed(Stmt) 54 | */ 55 | @Override 56 | public void initialSeed(Stmt stmt) { 57 | stmt(stmt).keyValue("seed", "true"); 58 | 59 | includeSuccessors(stmt, Sets. newHashSet()); 60 | } 61 | 62 | private void includeSuccessors(Stmt stmt, Set visited) { 63 | if(!visited.add(stmt)) 64 | return; 65 | 66 | JsonDocument doc = stmt(stmt); 67 | for(Stmt succ : icfg.getSuccsOf(stmt)) { 68 | doc.array("successors").add(succ.toString()); 69 | stmt(succ); 70 | includeSuccessors(succ, visited); 71 | } 72 | 73 | if(icfg.isCallStmt(stmt)) { 74 | for(Method m : icfg.getCalleesOfCallAt(stmt)) { 75 | doc.doc("calls").doc(m.toString()); 76 | for(Stmt sp : icfg.getStartPointsOf(m)) { 77 | stmt(sp).keyValue("startPoint", "true"); 78 | includeSuccessors(sp, visited); 79 | } 80 | } 81 | for(Stmt retSite :icfg.getReturnSitesOfCallAt(stmt)) { 82 | doc.array("successors").add(retSite.toString()); 83 | stmt(retSite); 84 | includeSuccessors(retSite, visited); 85 | } 86 | } 87 | if(icfg.isExitStmt(stmt)) { 88 | for(Stmt callSite : icfg.getCallersOf(icfg.getMethodOf(stmt))) { 89 | for(Stmt retSite : icfg.getReturnSitesOfCallAt(callSite)) { 90 | doc.doc("returns").doc(retSite.toString()); 91 | includeSuccessors(retSite, visited); 92 | } 93 | } 94 | } 95 | } 96 | 97 | protected JsonDocument stmt(Stmt stmt) { 98 | Method methodOf = icfg.getMethodOf(stmt); 99 | return root.doc("methods").doc(methodOf.toString()).doc(stmt.toString()); 100 | } 101 | 102 | public void expectNormalFlow(Stmt unit, String expectedFlowFunctionsToString) { 103 | stmt(unit).keyValue("flow", expectedFlowFunctionsToString); 104 | } 105 | 106 | public void expectCallFlow(Stmt callSite, Method destinationMethod, String expectedFlowFunctionsToString) { 107 | stmt(callSite).doc("calls").doc(destinationMethod.toString()).keyValue("flow", expectedFlowFunctionsToString); 108 | } 109 | 110 | public void expectReturnFlow(Stmt exitStmt, Stmt returnSite, String expectedFlowFunctionsToString) { 111 | if(returnSite != null) 112 | stmt(exitStmt).doc("returns").doc(returnSite.toString()).keyValue("flow", expectedFlowFunctionsToString); 113 | } 114 | 115 | @Override 116 | public void edgeTo(PerAccessPathMethodAnalyzer analyzer, WrappedFactAtStatement factAtStmt) { 117 | 118 | } 119 | 120 | @Override 121 | public void newResolver(PerAccessPathMethodAnalyzer analyzer, Resolver resolver) { 122 | 123 | } 124 | 125 | @Override 126 | public void newJob(PerAccessPathMethodAnalyzer analyzer, WrappedFactAtStatement factAtStmt) { 127 | 128 | } 129 | 130 | @Override 131 | public void jobStarted(PerAccessPathMethodAnalyzer analyzer, 132 | WrappedFactAtStatement factAtStmt) { 133 | 134 | } 135 | 136 | @Override 137 | public void jobFinished(PerAccessPathMethodAnalyzer analyzer, 138 | WrappedFactAtStatement factAtStmt) { 139 | 140 | } 141 | 142 | @Override 143 | public void askedToResolve(Resolver resolver, Constraint constraint) { 144 | 145 | } 146 | 147 | } 148 | -------------------------------------------------------------------------------- /test/heros/utilities/TestFact.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2014 Johannes Lerch. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Johannes Lerch - initial API and implementation 10 | ******************************************************************************/ 11 | package heros.utilities; 12 | 13 | public class TestFact { 14 | 15 | public final String baseValue; 16 | 17 | public TestFact(String baseValue) { 18 | this.baseValue = baseValue; 19 | } 20 | 21 | @Override 22 | public String toString() { 23 | return "[Fact "+baseValue+"]"; 24 | } 25 | 26 | @Override 27 | public int hashCode() { 28 | final int prime = 31; 29 | int result = 1; 30 | result = prime * result + ((baseValue == null) ? 0 : baseValue.hashCode()); 31 | return result; 32 | } 33 | 34 | @Override 35 | public boolean equals(Object obj) { 36 | if (this == obj) 37 | return true; 38 | if (obj == null) 39 | return false; 40 | if (!(obj instanceof TestFact)) 41 | return false; 42 | TestFact other = (TestFact) obj; 43 | if (baseValue == null) { 44 | if (other.baseValue != null) 45 | return false; 46 | } else if (!baseValue.equals(other.baseValue)) 47 | return false; 48 | return true; 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /test/heros/utilities/TestMethod.java: -------------------------------------------------------------------------------- 1 | /******************************************************************************* 2 | * Copyright (c) 2014 Johannes Lerch. 3 | * All rights reserved. This program and the accompanying materials 4 | * are made available under the terms of the GNU Lesser Public License v2.1 5 | * which accompanies this distribution, and is available at 6 | * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html 7 | * 8 | * Contributors: 9 | * Johannes Lerch - initial API and implementation 10 | ******************************************************************************/ 11 | package heros.utilities; 12 | 13 | public class TestMethod { 14 | 15 | public final String name; 16 | 17 | public TestMethod(String name) { 18 | this.name = name; 19 | } 20 | 21 | @Override 22 | public int hashCode() { 23 | final int prime = 31; 24 | int result = 1; 25 | result = prime * result + ((name == null) ? 0 : name.hashCode()); 26 | return result; 27 | } 28 | 29 | @Override 30 | public boolean equals(Object obj) { 31 | if (this == obj) 32 | return true; 33 | if (obj == null) 34 | return false; 35 | if (!(obj instanceof TestMethod)) 36 | return false; 37 | TestMethod other = (TestMethod) obj; 38 | if (name == null) { 39 | if (other.name != null) 40 | return false; 41 | } else if (!name.equals(other.name)) 42 | return false; 43 | return true; 44 | } 45 | 46 | @Override 47 | public String toString() { 48 | return "[Method "+name+"]"; 49 | } 50 | } 51 | --------------------------------------------------------------------------------