Skip to content

Commit c4adcd8

Browse files
authored
Merge pull request #624 from guiyj/develop
Address issue #622: merge FPC into FlowDroid
2 parents 782ff5b + 2be91e4 commit c4adcd8

27 files changed

+1832
-137
lines changed

soot-infoflow-cmd/src/soot/jimple/infoflow/cmd/MainClass.java

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,7 @@ public class MainClass {
108108
private static final String OPTION_MAX_CALLBACKS_COMPONENT = "mc";
109109
private static final String OPTION_MAX_CALLBACKS_DEPTH = "md";
110110
private static final String OPTION_PATH_SPECIFIC_RESULTS = "ps";
111+
private static final String OPTION_MAX_THREAD_NUMBER = "mt";
111112

112113
// Inter-component communication
113114
private static final String OPTION_ICC_MODEL = "im";
@@ -126,6 +127,7 @@ public class MainClass {
126127
private static final String OPTION_IMPLICIT_FLOW_MODE = "i";
127128
private static final String OPTION_STATIC_FLOW_TRACKING_MODE = "sf";
128129
private static final String OPTION_DATA_FLOW_DIRECTION = "dir";
130+
private static final String OPTION_GC_SLEEP_TIME = "st";
129131

130132
// Evaluation-specific options
131133
private static final String OPTION_ANALYZE_FRAMEWORKS = "ff";
@@ -193,7 +195,8 @@ private void initializeCommandLineOptions() {
193195
"Compute the taint propagation paths and not just source-to-sink connections. This is a shorthand notation for -pr fast.");
194196
options.addOption(OPTION_LOG_SOURCES_SINKS, "logsourcesandsinks", false,
195197
"Write the discovered sources and sinks to the log output");
196-
options.addOption("mt", "maxthreadnum", true, "Limit the maximum number of threads to the given value");
198+
options.addOption(OPTION_MAX_THREAD_NUMBER, "maxthreadnum", true,
199+
"Limit the maximum number of threads to the given value");
197200
options.addOption(OPTION_ONE_COMPONENT, "onecomponentatatime", false,
198201
"Analyze one Android component at a time");
199202
options.addOption(OPTION_ONE_SOURCE, "onesourceatatime", false, "Analyze one source at a time");
@@ -241,6 +244,8 @@ private void initializeCommandLineOptions() {
241244
"Use the specified mode when tracking static data flows (CONTEXTFLOWSENSITIVE, CONTEXTFLOWINSENSITIVE, NONE)");
242245
options.addOption(OPTION_DATA_FLOW_DIRECTION, "direction", true,
243246
"Specifies the direction of the infoflow analysis (FORWARDS, BACKWARDS)");
247+
options.addOption(OPTION_GC_SLEEP_TIME, "gcsleeptime", true,
248+
"Specifies the sleep time for path edge collectors in seconds");
244249

245250
// Evaluation-specific options
246251
options.addOption(OPTION_ANALYZE_FRAMEWORKS, "analyzeframeworks", false,
@@ -588,6 +593,8 @@ else if (solver.equalsIgnoreCase("FLOWINSENSITIVE"))
588593
return DataFlowSolver.FlowInsensitive;
589594
else if (solver.equalsIgnoreCase("GC"))
590595
return DataFlowSolver.GarbageCollecting;
596+
else if (solver.equalsIgnoreCase("FPC"))
597+
return DataFlowSolver.FineGrainedGC;
591598
else {
592599
System.err.println(String.format("Invalid data flow solver: %s", solver));
593600
throw new AbortAnalysisException();
@@ -790,6 +797,12 @@ private void parseCommandLineOptions(CommandLine cmd, InfoflowAndroidConfigurati
790797
if (maxDepth != null)
791798
config.getCallbackConfig().setMaxAnalysisCallbackDepth(maxDepth);
792799
}
800+
{
801+
Integer maxthreadnum = getIntOption(cmd, OPTION_MAX_THREAD_NUMBER);
802+
if (maxthreadnum != null) {
803+
config.setMaxThreadNum(maxthreadnum);
804+
}
805+
}
793806

794807
// Inter-component communication
795808
if (cmd.hasOption(OPTION_ICC_NO_PURIFY))
@@ -887,6 +900,13 @@ private void parseCommandLineOptions(CommandLine cmd, InfoflowAndroidConfigurati
887900
config.getCallbackConfig().setCallbacksFile(callgraphFile);
888901
}
889902
}
903+
904+
{
905+
Integer sleepTime = getIntOption(cmd, OPTION_GC_SLEEP_TIME);
906+
if (sleepTime != null) {
907+
config.getSolverConfiguration().setSleepTime(sleepTime);
908+
}
909+
}
890910
}
891911

892912
private Integer getIntOption(CommandLine cmd, String option) {

soot-infoflow/src/soot/jimple/infoflow/AbstractInfoflow.java

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818
import org.slf4j.Logger;
1919
import org.slf4j.LoggerFactory;
2020

21+
import heros.solver.Pair;
2122
import soot.FastHierarchy;
2223
import soot.G;
2324
import soot.MethodOrMethodContext;
@@ -704,7 +705,13 @@ public Thread newThread(Runnable r) {
704705
manager = initializeInfoflowManager(sourcesSinks, iCfg, globalTaintManager);
705706

706707
// Create the solver peer group
707-
solverPeerGroup = new GCSolverPeerGroup();
708+
switch (manager.getConfig().getSolverConfiguration().getDataFlowSolver()) {
709+
case FineGrainedGC:
710+
solverPeerGroup = new GCSolverPeerGroup<Pair<SootMethod, Abstraction>>();
711+
break;
712+
default:
713+
solverPeerGroup = new GCSolverPeerGroup<SootMethod>();
714+
}
708715

709716
// Initialize the alias analysis
710717
Abstraction zeroValue = Abstraction.getZeroAbstraction(manager.getConfig().getFlowSensitiveAliasing());
@@ -1238,10 +1245,18 @@ protected IInfoflowSolver createDataFlowSolver(InterruptableExecutor executor, A
12381245
return new soot.jimple.infoflow.solver.fastSolver.flowInsensitive.InfoflowSolver(problem, executor);
12391246
case GarbageCollecting:
12401247
logger.info("Using garbage-collecting solver");
1241-
IInfoflowSolver solver = new soot.jimple.infoflow.solver.gcSolver.InfoflowSolver(problem, executor);
1248+
IInfoflowSolver solver = new soot.jimple.infoflow.solver.gcSolver.InfoflowSolver(problem, executor,
1249+
solverConfig.getSleepTime());
12421250
solverPeerGroup.addSolver(solver);
12431251
solver.setPeerGroup(solverPeerGroup);
12441252
return solver;
1253+
case FineGrainedGC:
1254+
logger.info("Using fine-grained garbage-collecting solver");
1255+
IInfoflowSolver fgSolver = new soot.jimple.infoflow.solver.gcSolver.fpc.InfoflowSolver(problem, executor,
1256+
solverConfig.getSleepTime());
1257+
solverPeerGroup.addSolver(fgSolver);
1258+
fgSolver.setPeerGroup(solverPeerGroup);
1259+
return fgSolver;
12451260
default:
12461261
throw new RuntimeException("Unsupported data flow solver");
12471262
}

soot-infoflow/src/soot/jimple/infoflow/InfoflowConfiguration.java

Lines changed: 25 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -133,7 +133,12 @@ public static enum DataFlowSolver {
133133
/**
134134
* Use the garbage-collecting solver
135135
*/
136-
GarbageCollecting
136+
GarbageCollecting,
137+
138+
/**
139+
* Use the fine-grained GC solver
140+
* */
141+
FineGrainedGC,
137142
}
138143

139144
public static enum DataFlowDirection {
@@ -971,6 +976,7 @@ public static class SolverConfiguration {
971976
private int maxJoinPointAbstractions = 10;
972977
private int maxCalleesPerCallSite = 75;
973978
private int maxAbstractionPathLength = 100;
979+
private int sleepTime = 1;
974980

975981
/**
976982
* Copies the settings of the given configuration into this configuration object
@@ -1084,6 +1090,24 @@ public void setMaxAbstractionPathLength(int maxAbstractionPathLength) {
10841090
this.maxAbstractionPathLength = maxAbstractionPathLength;
10851091
}
10861092

1093+
/**
1094+
* Sets the sleep time of garbage colletors
1095+
*
1096+
* @param sleeptime The interval in second for the path edge collection
1097+
*/
1098+
public void setSleepTime(int sleeptime) {
1099+
this.sleepTime = sleeptime;
1100+
}
1101+
1102+
/**
1103+
* Gets the sleep time of garbage colletors
1104+
*
1105+
* @return The interval in second for the path edge collection
1106+
*/
1107+
public int getSleepTime() {
1108+
return this.sleepTime;
1109+
}
1110+
10871111
@Override
10881112
public int hashCode() {
10891113
final int prime = 31;

soot-infoflow/src/soot/jimple/infoflow/solver/gcSolver/AbstractGarbageCollector.java

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,23 +11,23 @@
1111
* @author Steven Arzt
1212
*
1313
*/
14-
public abstract class AbstractGarbageCollector<N, D> implements IGarbageCollector<N, D> {
14+
public abstract class AbstractGarbageCollector<N, D, A> implements IGarbageCollector<N, D> {
1515

1616
protected final BiDiInterproceduralCFG<N, SootMethod> icfg;
17-
protected final IGCReferenceProvider<D, N> referenceProvider;
18-
protected final ConcurrentHashMultiMap<SootMethod, PathEdge<N, D>> jumpFunctions;
17+
protected final IGCReferenceProvider<A> referenceProvider;
18+
protected final ConcurrentHashMultiMap<A, PathEdge<N, D>> jumpFunctions;
1919

2020
public AbstractGarbageCollector(BiDiInterproceduralCFG<N, SootMethod> icfg,
21-
ConcurrentHashMultiMap<SootMethod, PathEdge<N, D>> jumpFunctions,
22-
IGCReferenceProvider<D, N> referenceProvider) {
21+
ConcurrentHashMultiMap<A, PathEdge<N, D>> jumpFunctions,
22+
IGCReferenceProvider<A> referenceProvider) {
2323
this.icfg = icfg;
2424
this.referenceProvider = referenceProvider;
2525
this.jumpFunctions = jumpFunctions;
2626
initialize();
2727
}
2828

2929
public AbstractGarbageCollector(BiDiInterproceduralCFG<N, SootMethod> icfg,
30-
ConcurrentHashMultiMap<SootMethod, PathEdge<N, D>> jumpFunctions) {
30+
ConcurrentHashMultiMap<A, PathEdge<N, D>> jumpFunctions) {
3131
this.icfg = icfg;
3232
this.referenceProvider = createReferenceProvider();
3333
this.jumpFunctions = jumpFunctions;
@@ -46,8 +46,10 @@ protected void initialize() {
4646
*
4747
* @return The new reference provider
4848
*/
49-
protected IGCReferenceProvider<D, N> createReferenceProvider() {
50-
return new OnDemandReferenceProvider<>(icfg);
49+
protected abstract IGCReferenceProvider<A> createReferenceProvider();
50+
51+
protected long getRemainingPathEdgeCount() {
52+
return jumpFunctions.values().size();
5153
}
5254

5355
}

soot-infoflow/src/soot/jimple/infoflow/solver/gcSolver/AbstractReferenceCountingGarbageCollector.java

Lines changed: 33 additions & 67 deletions
Original file line numberDiff line numberDiff line change
@@ -18,17 +18,17 @@
1818
* @author Steven Arzt
1919
*
2020
*/
21-
public abstract class AbstractReferenceCountingGarbageCollector<N, D> extends AbstractGarbageCollector<N, D>
22-
implements IGarbageCollectorPeer {
23-
24-
private ConcurrentCountingMap<SootMethod> jumpFnCounter = new ConcurrentCountingMap<>();
25-
private final Set<SootMethod> gcScheduleSet = new ConcurrentHashSet<>();
26-
private final AtomicInteger gcedMethods = new AtomicInteger();
27-
private final AtomicInteger gcedEdges = new AtomicInteger();
28-
private final ExtendedAtomicInteger edgeCounterForThreshold = new ExtendedAtomicInteger();
29-
private GarbageCollectionTrigger trigger = GarbageCollectionTrigger.Immediate;
30-
private GarbageCollectorPeerGroup peerGroup = null;
31-
private boolean checkChangeCounter = false;
21+
public abstract class AbstractReferenceCountingGarbageCollector<N, D, A> extends AbstractGarbageCollector<N, D, A>
22+
implements IGarbageCollectorPeer<A> {
23+
24+
protected ConcurrentCountingMap<A> jumpFnCounter = new ConcurrentCountingMap<>();
25+
protected final Set<A> gcScheduleSet = new ConcurrentHashSet<>();
26+
protected final AtomicInteger gcedAbstractions = new AtomicInteger();
27+
protected final AtomicInteger gcedEdges = new AtomicInteger();
28+
protected final ExtendedAtomicInteger edgeCounterForThreshold = new ExtendedAtomicInteger();
29+
protected GarbageCollectionTrigger trigger = GarbageCollectionTrigger.Immediate;
30+
protected GarbageCollectorPeerGroup<A> peerGroup = null;
31+
protected boolean checkChangeCounter = false;
3232

3333
protected boolean validateEdges = false;
3434
protected Set<PathEdge<N, D>> oldEdges = new HashSet<>();
@@ -44,21 +44,23 @@ public abstract class AbstractReferenceCountingGarbageCollector<N, D> extends Ab
4444
protected int edgeThreshold = 0;
4545

4646
public AbstractReferenceCountingGarbageCollector(BiDiInterproceduralCFG<N, SootMethod> icfg,
47-
ConcurrentHashMultiMap<SootMethod, PathEdge<N, D>> jumpFunctions,
48-
IGCReferenceProvider<D, N> referenceProvider) {
47+
ConcurrentHashMultiMap<A, PathEdge<N, D>> jumpFunctions,
48+
IGCReferenceProvider<A> referenceProvider) {
4949
super(icfg, jumpFunctions, referenceProvider);
5050
}
5151

5252
public AbstractReferenceCountingGarbageCollector(BiDiInterproceduralCFG<N, SootMethod> icfg,
53-
ConcurrentHashMultiMap<SootMethod, PathEdge<N, D>> jumpFunctions) {
53+
ConcurrentHashMultiMap<A, PathEdge<N, D>> jumpFunctions) {
5454
super(icfg, jumpFunctions);
5555
}
5656

57+
protected abstract A genAbstraction(PathEdge<N, D> edge);
58+
5759
@Override
5860
public void notifyEdgeSchedule(PathEdge<N, D> edge) {
59-
SootMethod sm = icfg.getMethodOf(edge.getTarget());
60-
jumpFnCounter.increment(sm);
61-
gcScheduleSet.add(sm);
61+
A abstraction = genAbstraction(edge);
62+
jumpFnCounter.increment(abstraction);
63+
gcScheduleSet.add(abstraction);
6264
if (trigger == GarbageCollectionTrigger.EdgeThreshold)
6365
edgeCounterForThreshold.incrementAndGet();
6466

@@ -70,42 +72,8 @@ public void notifyEdgeSchedule(PathEdge<N, D> edge) {
7072

7173
@Override
7274
public void notifyTaskProcessed(PathEdge<N, D> edge) {
73-
jumpFnCounter.decrement(icfg.getMethodOf(edge.getTarget()));
74-
}
75-
76-
/**
77-
* Checks whether the given method has any open dependencies that prevent its
78-
* jump functions from being garbage collected
79-
*
80-
* @param method The method to check
81-
* @param referenceCounter The counter that keeps track of active references to
82-
* taint abstractions
83-
* @return True it the method has active dependencies and thus cannot be
84-
* garbage-collected, false otherwise
85-
*/
86-
private boolean hasActiveDependencies(SootMethod method, ConcurrentCountingMap<SootMethod> referenceCounter) {
87-
int changeCounter = -1;
88-
do {
89-
// Update the change counter for the next round
90-
changeCounter = referenceCounter.getChangeCounter();
91-
92-
// Check the method itself
93-
if (referenceCounter.get(method) > 0)
94-
return true;
95-
96-
// Check the transitive callees
97-
Set<SootMethod> references = referenceProvider.getMethodReferences(method, null);
98-
for (SootMethod ref : references) {
99-
if (referenceCounter.get(ref) > 0)
100-
return true;
101-
}
102-
} while (checkChangeCounter && changeCounter != referenceCounter.getChangeCounter());
103-
return false;
104-
}
105-
106-
@Override
107-
public boolean hasActiveDependencies(SootMethod method) {
108-
return hasActiveDependencies(method, jumpFnCounter);
75+
A abstraction = genAbstraction(edge);
76+
jumpFnCounter.decrement(abstraction);
10977
}
11078

11179
/**
@@ -120,18 +88,17 @@ protected void gcImmediate() {
12088

12189
// Perform the garbage collection if required
12290
if (gc) {
123-
int tempMethods = 0;
12491
onBeforeRemoveEdges();
125-
for (SootMethod sm : gcScheduleSet) {
92+
for (A abst : gcScheduleSet) {
12693
// Is it safe to remove this method?
12794
if (peerGroup != null) {
128-
if (peerGroup.hasActiveDependencies(sm))
95+
if (peerGroup.hasActiveDependencies(abst))
12996
continue;
130-
} else if (hasActiveDependencies(sm))
97+
} else if (hasActiveDependencies(abst))
13198
continue;
13299

133100
// Get stats for the stuff we are about to remove
134-
Set<PathEdge<N, D>> oldFunctions = jumpFunctions.get(sm);
101+
Set<PathEdge<N, D>> oldFunctions = jumpFunctions.get(abst);
135102
if (oldFunctions != null) {
136103
int gcedSize = oldFunctions.size();
137104
gcedEdges.addAndGet(gcedSize);
@@ -142,15 +109,14 @@ protected void gcImmediate() {
142109
// First unregister the method, then delete the edges. In case some other thread
143110
// concurrently schedules a new edge, the method gets back into the GC work list
144111
// this way.
145-
gcScheduleSet.remove(sm);
146-
if (jumpFunctions.remove(sm)) {
147-
gcedMethods.incrementAndGet();
148-
tempMethods++;
112+
gcScheduleSet.remove(abst);
113+
if (jumpFunctions.remove(abst)) {
114+
gcedAbstractions.incrementAndGet();
149115
if (validateEdges)
150116
oldEdges.addAll(oldFunctions);
151117
}
152118
}
153-
onAfterRemoveEdges(tempMethods);
119+
onAfterRemoveEdges();
154120
}
155121
}
156122
}
@@ -168,12 +134,12 @@ protected void onBeforeRemoveEdges() {
168134
*
169135
* @param gcedMethods The number of methods for which edges have been removed
170136
*/
171-
protected void onAfterRemoveEdges(int gcedMethods) {
137+
protected void onAfterRemoveEdges() {
172138
}
173139

174140
@Override
175-
public int getGcedMethods() {
176-
return gcedMethods.get();
141+
public int getGcedAbstractions() {
142+
return gcedAbstractions.get();
177143
}
178144

179145
@Override
@@ -219,7 +185,7 @@ public void setTrigger(GarbageCollectionTrigger trigger) {
219185
*
220186
* @param peerGroup The peer group
221187
*/
222-
public void setPeerGroup(GarbageCollectorPeerGroup peerGroup) {
188+
public void setPeerGroup(GarbageCollectorPeerGroup<A> peerGroup) {
223189
this.peerGroup = peerGroup;
224190
peerGroup.addGarbageCollector(this);
225191
}

soot-infoflow/src/soot/jimple/infoflow/solver/gcSolver/AbstractReferenceProvider.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
* @author Steven Arzt
1515
*
1616
*/
17-
public abstract class AbstractReferenceProvider<D, N> implements IGCReferenceProvider<D, N> {
17+
public abstract class AbstractReferenceProvider<A, N> implements IGCReferenceProvider<A> {
1818

1919
protected final BiDiInterproceduralCFG<N, SootMethod> icfg;
2020

0 commit comments

Comments
 (0)