@@ -34,6 +34,7 @@ import de.fraunhofer.aisec.cpg.graph.statements.*
34
34
import de.fraunhofer.aisec.cpg.graph.statements.expressions.*
35
35
import de.fraunhofer.aisec.cpg.graph.statements.expressions.Block
36
36
import de.fraunhofer.aisec.cpg.helpers.SubgraphWalker
37
+ import kotlin.collections.firstOrNull
37
38
import kotlin.math.absoluteValue
38
39
39
40
/* *
@@ -227,7 +228,7 @@ fun Node.followPrevFullDFGEdgesUntilHit(
227
228
predicate : (Node ) -> Boolean ,
228
229
): FulfilledAndFailedPaths {
229
230
return followXUntilHit(
230
- x = { currentNode, _ -> currentNode.prevFullDFG },
231
+ x = { currentNode, _, _ -> currentNode.prevFullDFG },
231
232
collectFailedPaths = collectFailedPaths,
232
233
findAllPossiblePaths = findAllPossiblePaths,
233
234
predicate = predicate,
@@ -267,7 +268,7 @@ fun Node.followPrevDFGEdgesUntilHit(
267
268
predicate : (Node ) -> Boolean ,
268
269
): FulfilledAndFailedPaths {
269
270
return followXUntilHit(
270
- x = { currentNode, ctx ->
271
+ x = { currentNode, ctx, path ->
271
272
if (
272
273
useIndexStack &&
273
274
currentNode is InitializerListExpression &&
@@ -324,10 +325,10 @@ fun Node.followPrevDFGEdgesUntilHit(
324
325
*/
325
326
class Context (
326
327
val indexStack : SimpleStack <IndexedDataflowGranularity > = SimpleStack (),
327
- val callStack : SimpleStack <CallExpression > = SimpleStack (),
328
+ val callStack : ArrayDeque <CallExpression > = ArrayDeque < CallExpression > (),
328
329
) {
329
330
fun clone (): Context {
330
- return Context (indexStack.clone(), callStack.clone( ))
331
+ return Context (indexStack.clone(), ArrayDeque (callStack ))
331
332
}
332
333
}
333
334
@@ -340,6 +341,9 @@ class SimpleStack<T>() {
340
341
deque.addFirst(newElem)
341
342
}
342
343
344
+ val current: T ?
345
+ get() = deque.firstOrNull()
346
+
343
347
fun checkAndPop (elemToPop : T ): Boolean {
344
348
if (deque.firstOrNull() == elemToPop) {
345
349
deque.removeFirst()
@@ -475,7 +479,7 @@ fun Node.followNextPDGUntilHit(
475
479
predicate : (Node ) -> Boolean ,
476
480
): FulfilledAndFailedPaths {
477
481
return followXUntilHit(
478
- x = { currentNode, _ ->
482
+ x = { currentNode, _, _ ->
479
483
val nextNodes = currentNode.nextPDG.toMutableList()
480
484
if (interproceduralAnalysis) {
481
485
nextNodes.addAll((currentNode as ? CallExpression )?.calls ? : listOf ())
@@ -504,7 +508,7 @@ fun Node.followNextCDGUntilHit(
504
508
predicate : (Node ) -> Boolean ,
505
509
): FulfilledAndFailedPaths {
506
510
return followXUntilHit(
507
- x = { currentNode, _ ->
511
+ x = { currentNode, _, _ ->
508
512
val nextNodes = currentNode.nextCDG.toMutableList()
509
513
if (interproceduralAnalysis) {
510
514
nextNodes.addAll((currentNode as ? CallExpression )?.calls ? : listOf ())
@@ -534,7 +538,7 @@ fun Node.followPrevPDGUntilHit(
534
538
predicate : (Node ) -> Boolean ,
535
539
): FulfilledAndFailedPaths {
536
540
return followXUntilHit(
537
- x = { currentNode, _ ->
541
+ x = { currentNode, _, _ ->
538
542
val nextNodes = currentNode.prevPDG.toMutableList()
539
543
if (interproceduralAnalysis) {
540
544
nextNodes.addAll(
@@ -568,7 +572,7 @@ fun Node.followPrevCDGUntilHit(
568
572
predicate : (Node ) -> Boolean ,
569
573
): FulfilledAndFailedPaths {
570
574
return followXUntilHit(
571
- x = { currentNode, _ ->
575
+ x = { currentNode, _, _ ->
572
576
val nextNodes = currentNode.prevCDG.toMutableList()
573
577
if (interproceduralAnalysis) {
574
578
nextNodes.addAll(
@@ -596,7 +600,7 @@ fun Node.followPrevCDGUntilHit(
596
600
* not mandatory**. If the list "failed" is empty, the path is mandatory.
597
601
*/
598
602
inline fun Node.followXUntilHit (
599
- noinline x : (Node , Context ) -> Collection <Node >,
603
+ noinline x : (Node , Context , List < Node > ) -> Collection <Node >,
600
604
collectFailedPaths : Boolean = true,
601
605
findAllPossiblePaths : Boolean = true,
602
606
context : Context = Context (),
@@ -621,7 +625,7 @@ inline fun Node.followXUntilHit(
621
625
alreadySeenNodes.add(currentNode)
622
626
// The last node of the path is where we continue. We get all of its outgoing CDG edges and
623
627
// follow them
624
- var nextNodes = x(currentNode, currentContext)
628
+ var nextNodes = x(currentNode, currentContext, currentPath.first )
625
629
626
630
// No further nodes in the path and the path criteria are not satisfied.
627
631
if (nextNodes.isEmpty() && collectFailedPaths) failedPaths.add(currentPath.first)
@@ -672,7 +676,7 @@ fun Node.followNextFullDFGEdgesUntilHit(
672
676
predicate : (Node ) -> Boolean ,
673
677
): FulfilledAndFailedPaths {
674
678
return followXUntilHit(
675
- x = { currentNode, _ -> currentNode.nextFullDFG },
679
+ x = { currentNode, _, _ -> currentNode.nextFullDFG },
676
680
collectFailedPaths = collectFailedPaths,
677
681
findAllPossiblePaths = findAllPossiblePaths,
678
682
predicate = predicate,
@@ -695,7 +699,7 @@ fun Node.followNextDFGEdgesUntilHit(
695
699
predicate : (Node ) -> Boolean ,
696
700
): FulfilledAndFailedPaths {
697
701
return followXUntilHit(
698
- x = { currentNode, ctx ->
702
+ x = { currentNode, ctx, path ->
699
703
if (
700
704
useIndexStack &&
701
705
currentNode is InitializerListExpression &&
@@ -726,7 +730,7 @@ fun Node.followNextDFGEdgesUntilHit(
726
730
currentNode.nextDFGEdges.forEach {
727
731
if (it is ContextSensitiveDataflow && it.callingContext is CallingContextIn ) {
728
732
// Push the call of our calling context to the stack
729
- ctx.callStack.push (it.callingContext.call)
733
+ ctx.callStack.addFirst (it.callingContext.call)
730
734
}
731
735
if (
732
736
it.end is InitializerListExpression &&
@@ -739,21 +743,33 @@ fun Node.followNextDFGEdgesUntilHit(
739
743
}
740
744
741
745
// We need to filter out the edges which based on the stack
742
- currentNode.nextDFGEdges
743
- .filter {
744
- if (ctx.callStack.isEmpty()) {
745
- true
746
- } else if (
747
- it is ContextSensitiveDataflow && it.callingContext is CallingContextOut
748
- ) {
749
- // We are only interested in outgoing edges from our current "call-in".
750
- // If we found it, we can pop it.
751
- ctx.callStack.checkAndPop(it.callingContext.call)
752
- } else {
753
- true
746
+ val selected =
747
+ currentNode.nextDFGEdges
748
+ .filter {
749
+ if (ctx.callStack.isEmpty()) {
750
+ true
751
+ } else if (
752
+ it is ContextSensitiveDataflow &&
753
+ it.callingContext is CallingContextOut
754
+ ) {
755
+ // We are only interested in outgoing edges from our current
756
+ // "call-in", i.e., the call expression that is on the stack.
757
+ ctx.callStack.firstOrNull() == it.callingContext.call
758
+ } else {
759
+ true
760
+ }
754
761
}
762
+ .map { it.end }
763
+
764
+ // Let's do any remaining pop'ing
765
+ currentNode.nextDFGEdges.forEach {
766
+ if (it is ContextSensitiveDataflow && it.callingContext is CallingContextOut ) {
767
+ // Pop the current call, if it's on top
768
+ ctx.callStack.removeIfFirst<CallExpression >(it.callingContext.call)
755
769
}
756
- .map { it.end }
770
+ }
771
+
772
+ selected
757
773
}
758
774
},
759
775
collectFailedPaths = collectFailedPaths,
@@ -778,7 +794,7 @@ fun Node.followNextEOGEdgesUntilHit(
778
794
predicate : (Node ) -> Boolean ,
779
795
): FulfilledAndFailedPaths {
780
796
return followXUntilHit(
781
- x = { currentNode, _ ->
797
+ x = { currentNode, _, _ ->
782
798
currentNode.nextEOGEdges.filter { it.unreachable != true }.map { it.end }
783
799
},
784
800
collectFailedPaths = collectFailedPaths,
@@ -803,7 +819,7 @@ fun Node.followPrevEOGEdgesUntilHit(
803
819
predicate : (Node ) -> Boolean ,
804
820
): FulfilledAndFailedPaths {
805
821
return followXUntilHit(
806
- x = { currentNode, _ ->
822
+ x = { currentNode, _, _ ->
807
823
currentNode.prevEOGEdges.filter { it.unreachable != true }.map { it.start }
808
824
},
809
825
collectFailedPaths = collectFailedPaths,
@@ -1291,3 +1307,12 @@ val Expression.isImported: Boolean
1291
1307
get() {
1292
1308
return this .importedFrom.isNotEmpty()
1293
1309
}
1310
+
1311
+ private fun <T > ArrayDeque<T>.removeIfFirst (element : T ): Boolean {
1312
+ return if (firstOrNull() == element) {
1313
+ removeFirst()
1314
+ true
1315
+ } else {
1316
+ false
1317
+ }
1318
+ }
0 commit comments