{
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