@@ -33,7 +33,9 @@ public class ContextSensitivePathBuilder extends ConcurrentAbstractionPathBuilde
3333 protected ConcurrentIdentityHashMultiMap <Abstraction , SourceContextAndPath > pathCache = new ConcurrentIdentityHashMultiMap <>();
3434
3535 // Set holds all paths that reach an already cached subpath
36- protected ConcurrentHashSet <Pair <SourceContextAndPath , SourceContextAndPath >> deferredPaths = new ConcurrentHashSet <>();
36+ protected ConcurrentHashSet <SourceContextAndPath > deferredPaths = new ConcurrentHashSet <>();
37+ // Set holds all paths that reach a source
38+ protected ConcurrentHashSet <SourceContextAndPath > sourceReachingScaps = new ConcurrentHashSet <>();
3739
3840 /**
3941 * Creates a new instance of the {@link ContextSensitivePathBuilder} class
@@ -76,7 +78,7 @@ public SourceFindingTask(Abstraction abstraction) {
7678 @ Override
7779 public void run () {
7880 final Set <SourceContextAndPath > paths = pathCache .get (abstraction );
79- final Abstraction pred = abstraction .getPredecessor ();
81+ Abstraction pred = abstraction .getPredecessor ();
8082
8183 if (pred != null && paths != null ) {
8284 for (SourceContextAndPath scap : paths ) {
@@ -94,14 +96,6 @@ public void run() {
9496 }
9597
9698 private void processAndQueue (Abstraction pred , SourceContextAndPath scap ) {
97- // Skip abstractions that don't contain any new information. This might
98- // be the case when a turn unit was added to the abstraction.
99- if (pred .getCorrespondingCallSite () == null && pred .getCurrentStmt () == null
100- && pred .getTurnUnit () != null ) {
101- processAndQueue (pred .getPredecessor (), scap );
102- return ;
103- }
104-
10599 ProcessingResult p = processPredecessor (scap , pred );
106100 switch (p .getResult ()) {
107101 case NEW :
@@ -112,7 +106,7 @@ private void processAndQueue(Abstraction pred, SourceContextAndPath scap) {
112106 case CACHED :
113107 // In case we already know the subpath, we do append the path after the path
114108 // builder terminated
115- deferredPaths .add (new Pair <>( scap , p . getScap ()) );
109+ deferredPaths .add (scap );
116110 break ;
117111 case INFEASIBLE_OR_MAX_PATHS_REACHED :
118112 // Nothing to do
@@ -130,7 +124,8 @@ private ProcessingResult processPredecessor(SourceContextAndPath scap, Abstracti
130124 if (extendedScap == null )
131125 return ProcessingResult .INFEASIBLE_OR_MAX_PATHS_REACHED ();
132126
133- checkForSource (pred , extendedScap );
127+ if (checkForSource (pred , extendedScap ))
128+ sourceReachingScaps .add (extendedScap );
134129 return pathCache .put (pred , extendedScap ) ? ProcessingResult .NEW ()
135130 : ProcessingResult .CACHED (extendedScap );
136131 }
@@ -141,44 +136,24 @@ private ProcessingResult processPredecessor(SourceContextAndPath scap, Abstracti
141136 return ProcessingResult .INFEASIBLE_OR_MAX_PATHS_REACHED ();
142137
143138 // Check if we are in the right context
144- switch (manager .getConfig ().getDataFlowDirection ()) {
145- case Forwards :
146- if (pred .getCurrentStmt () != null && pred .getCurrentStmt ().containsInvokeExpr ()) {
147- // Pop the top item off the call stack. This gives us the item
148- // and the new SCAP without the item we popped off.
149- Pair <SourceContextAndPath , Stmt > pathAndItem = extendedScap .popTopCallStackItem ();
150- if (pathAndItem != null ) {
151- Stmt topCallStackItem = pathAndItem .getO2 ();
152- // Make sure that we don't follow an unrealizable path
153- if (topCallStackItem != pred .getCurrentStmt ())
154- return ProcessingResult .INFEASIBLE_OR_MAX_PATHS_REACHED ();
155-
156- // We have returned from a function
157- extendedScap = pathAndItem .getO1 ();
158- }
159- }
160- break ;
161- case Backwards :
162- if (pred .getCorrespondingCallSite () != null
163- && pred .getCorrespondingCallSite () != pred .getCurrentStmt ()) {
164- // Pop the top item off the call stack. This gives us the item
165- // and the new SCAP without the item we popped off.
166- Pair <SourceContextAndPath , Stmt > pathAndItem = extendedScap .popTopCallStackItem ();
167- if (pathAndItem != null ) {
168- Stmt topCallStackItem = pathAndItem .getO2 ();
169- // Make sure that we don't follow an unrealizable path
170- if (topCallStackItem != pred .getCorrespondingCallSite ())
171- return ProcessingResult .INFEASIBLE_OR_MAX_PATHS_REACHED ();
172-
173- // We have returned from a function
174- extendedScap = pathAndItem .getO1 ();
175- }
139+ if (pred .getCurrentStmt () != null && pred .getCurrentStmt ().containsInvokeExpr ()) {
140+ // Pop the top item off the call stack. This gives us the item
141+ // and the new SCAP without the item we popped off.
142+ Pair <SourceContextAndPath , Stmt > pathAndItem = extendedScap .popTopCallStackItem ();
143+ if (pathAndItem != null ) {
144+ Stmt topCallStackItem = pathAndItem .getO2 ();
145+ // Make sure that we don't follow an unrealizable path
146+ if (topCallStackItem != pred .getCurrentStmt ())
147+ return ProcessingResult .INFEASIBLE_OR_MAX_PATHS_REACHED ();
148+
149+ // We have returned from a function
150+ extendedScap = pathAndItem .getO1 ();
176151 }
177- break ;
178152 }
179153
180154 // Add the new path
181- checkForSource (pred , extendedScap );
155+ if (checkForSource (pred , extendedScap ))
156+ sourceReachingScaps .add (extendedScap );
182157
183158 final int maxPaths = config .getPathConfiguration ().getMaxPathsPerAbstraction ();
184159 if (maxPaths > 0 ) {
@@ -291,27 +266,14 @@ public void computeTaintPaths(Set<AbstractionAtSink> res) {
291266 }
292267
293268 /**
294- * Uses the cached path to extend the current path
295- *
296- * @param scap SourceContextAndPath of the current abstraction
297- * @param cachedScap cached SourceContextAndPath to extend scap
269+ * Tries to fill up deferred paths toward a source.
298270 */
299- protected void buildFullPathFromCache (SourceContextAndPath scap , SourceContextAndPath cachedScap ) {
300- // Try to extend scap with cachedScap
301- Stack <Pair <SourceContextAndPath , SourceContextAndPath >> workStack = new Stack <>();
302- workStack .push (new Pair <>(scap , cachedScap ));
303- while (!workStack .isEmpty ()) {
304- Pair <SourceContextAndPath , SourceContextAndPath > p = workStack .pop ();
305- scap = p .getO1 ();
306- cachedScap = p .getO2 ();
307-
308- SourceContextAndPath extendedScap = scap .extendPath (cachedScap );
309- if (extendedScap != null ) {
310- Abstraction last = extendedScap .getLastAbstraction ();
311- // Try to build the path further using the cache if we didn't reach a source
312- if (!checkForSource (last , extendedScap ))
313- for (SourceContextAndPath preds : pathCache .get (last .getPredecessor ()))
314- workStack .push (new Pair <>(extendedScap , preds ));
271+ protected void buildPathsFromCache () {
272+ for (SourceContextAndPath deferredScap : deferredPaths ) {
273+ for (SourceContextAndPath sourceScap : sourceReachingScaps ) {
274+ SourceContextAndPath fullScap = deferredScap .extendPath (sourceScap );
275+ if (fullScap != null )
276+ checkForSource (fullScap .getLastAbstraction (), fullScap );
315277 }
316278 }
317279 }
@@ -320,9 +282,7 @@ protected void buildFullPathFromCache(SourceContextAndPath scap, SourceContextAn
320282 * Method that is called when the taint paths have been computed
321283 */
322284 protected void onTaintPathsComputed () {
323- for (Pair <SourceContextAndPath , SourceContextAndPath > deferredPair : deferredPaths ) {
324- buildFullPathFromCache (deferredPair .getO1 (), deferredPair .getO2 ());
325- }
285+ buildPathsFromCache ();
326286 }
327287
328288 /**
0 commit comments