From b505f25b0fb8fb454dbe4931ba78c10f0d789c49 Mon Sep 17 00:00:00 2001
From: Alexis <alexis.challande@trailofbits.com>
Date: Mon, 18 Nov 2024 15:15:14 +0100
Subject: [PATCH] Update test

---
 .../security/Recursion/Recursion.expected     | 78 +++++++++++++++++++
 .../security/Recursion/Recursion.java         | 33 ++++++++
 2 files changed, 111 insertions(+)

diff --git a/java/test/query-tests/security/Recursion/Recursion.expected b/java/test/query-tests/security/Recursion/Recursion.expected
index a758686..b34aa1c 100644
--- a/java/test/query-tests/security/Recursion/Recursion.expected
+++ b/java/test/query-tests/security/Recursion/Recursion.expected
@@ -28,6 +28,44 @@ edges
 | Recursion.java:101:16:101:23 | level2 calls level0 : Boolean | Recursion.java:95:16:95:23 | level1 calls level2 : Boolean | provenance |  |
 | Recursion.java:115:16:115:54 | directRecursiveNoDepth calls directRecursiveNoDepth : Boolean | Recursion.java:115:16:115:54 | directRecursiveNoDepth calls directRecursiveNoDepth | provenance |  |
 | Recursion.java:115:16:115:54 | directRecursiveNoDepth calls directRecursiveNoDepth : Boolean | Recursion.java:115:16:115:54 | directRecursiveNoDepth calls directRecursiveNoDepth : Boolean | provenance |  |
+| Recursion.java:184:20:184:27 | level0 calls level1 : Boolean | Recursion.java:198:16:198:23 | level2 calls level0 | provenance |  |
+| Recursion.java:184:20:184:27 | level0 calls level1 : Boolean | Recursion.java:198:16:198:23 | level2 calls level0 | provenance |  |
+| Recursion.java:184:20:184:27 | level0 calls level1 : Boolean | Recursion.java:198:16:198:23 | level2 calls level0 : Boolean | provenance |  |
+| Recursion.java:184:20:184:27 | level0 calls level1 : Boolean | Recursion.java:198:16:198:23 | level2 calls level0 : Boolean | provenance |  |
+| Recursion.java:184:20:184:27 | level0 calls level1 : Boolean | Recursion.java:198:16:198:23 | level2 calls level0 : Boolean | provenance |  |
+| Recursion.java:186:16:186:23 | level0 calls level2 : Boolean | Recursion.java:198:16:198:23 | level2 calls level0 | provenance |  |
+| Recursion.java:186:16:186:23 | level0 calls level2 : Boolean | Recursion.java:198:16:198:23 | level2 calls level0 | provenance |  |
+| Recursion.java:186:16:186:23 | level0 calls level2 : Boolean | Recursion.java:198:16:198:23 | level2 calls level0 : Boolean | provenance |  |
+| Recursion.java:186:16:186:23 | level0 calls level2 : Boolean | Recursion.java:198:16:198:23 | level2 calls level0 : Boolean | provenance |  |
+| Recursion.java:186:16:186:23 | level0 calls level2 : Boolean | Recursion.java:198:16:198:23 | level2 calls level0 : Boolean | provenance |  |
+| Recursion.java:192:16:192:23 | level1 calls level2 : Boolean | Recursion.java:184:20:184:27 | level0 calls level1 | provenance |  |
+| Recursion.java:192:16:192:23 | level1 calls level2 : Boolean | Recursion.java:184:20:184:27 | level0 calls level1 : Boolean | provenance |  |
+| Recursion.java:192:16:192:23 | level1 calls level2 : Boolean | Recursion.java:184:20:184:27 | level0 calls level1 : Boolean | provenance |  |
+| Recursion.java:192:16:192:23 | level1 calls level2 : Boolean | Recursion.java:184:20:184:27 | level0 calls level1 : Boolean | provenance |  |
+| Recursion.java:192:16:192:23 | level1 calls level2 : Boolean | Recursion.java:196:20:196:27 | level2 calls level1 | provenance |  |
+| Recursion.java:192:16:192:23 | level1 calls level2 : Boolean | Recursion.java:196:20:196:27 | level2 calls level1 : Boolean | provenance |  |
+| Recursion.java:192:16:192:23 | level1 calls level2 : Boolean | Recursion.java:196:20:196:27 | level2 calls level1 : Boolean | provenance |  |
+| Recursion.java:192:16:192:23 | level1 calls level2 : Boolean | Recursion.java:196:20:196:27 | level2 calls level1 : Boolean | provenance |  |
+| Recursion.java:196:20:196:27 | level2 calls level1 : Boolean | Recursion.java:186:16:186:23 | level0 calls level2 | provenance |  |
+| Recursion.java:196:20:196:27 | level2 calls level1 : Boolean | Recursion.java:186:16:186:23 | level0 calls level2 | provenance |  |
+| Recursion.java:196:20:196:27 | level2 calls level1 : Boolean | Recursion.java:186:16:186:23 | level0 calls level2 : Boolean | provenance |  |
+| Recursion.java:196:20:196:27 | level2 calls level1 : Boolean | Recursion.java:186:16:186:23 | level0 calls level2 : Boolean | provenance |  |
+| Recursion.java:196:20:196:27 | level2 calls level1 : Boolean | Recursion.java:186:16:186:23 | level0 calls level2 : Boolean | provenance |  |
+| Recursion.java:196:20:196:27 | level2 calls level1 : Boolean | Recursion.java:192:16:192:23 | level1 calls level2 | provenance |  |
+| Recursion.java:196:20:196:27 | level2 calls level1 : Boolean | Recursion.java:192:16:192:23 | level1 calls level2 | provenance |  |
+| Recursion.java:196:20:196:27 | level2 calls level1 : Boolean | Recursion.java:192:16:192:23 | level1 calls level2 : Boolean | provenance |  |
+| Recursion.java:196:20:196:27 | level2 calls level1 : Boolean | Recursion.java:192:16:192:23 | level1 calls level2 : Boolean | provenance |  |
+| Recursion.java:196:20:196:27 | level2 calls level1 : Boolean | Recursion.java:192:16:192:23 | level1 calls level2 : Boolean | provenance |  |
+| Recursion.java:198:16:198:23 | level2 calls level0 : Boolean | Recursion.java:186:16:186:23 | level0 calls level2 | provenance |  |
+| Recursion.java:198:16:198:23 | level2 calls level0 : Boolean | Recursion.java:186:16:186:23 | level0 calls level2 | provenance |  |
+| Recursion.java:198:16:198:23 | level2 calls level0 : Boolean | Recursion.java:186:16:186:23 | level0 calls level2 : Boolean | provenance |  |
+| Recursion.java:198:16:198:23 | level2 calls level0 : Boolean | Recursion.java:186:16:186:23 | level0 calls level2 : Boolean | provenance |  |
+| Recursion.java:198:16:198:23 | level2 calls level0 : Boolean | Recursion.java:186:16:186:23 | level0 calls level2 : Boolean | provenance |  |
+| Recursion.java:198:16:198:23 | level2 calls level0 : Boolean | Recursion.java:192:16:192:23 | level1 calls level2 | provenance |  |
+| Recursion.java:198:16:198:23 | level2 calls level0 : Boolean | Recursion.java:192:16:192:23 | level1 calls level2 | provenance |  |
+| Recursion.java:198:16:198:23 | level2 calls level0 : Boolean | Recursion.java:192:16:192:23 | level1 calls level2 : Boolean | provenance |  |
+| Recursion.java:198:16:198:23 | level2 calls level0 : Boolean | Recursion.java:192:16:192:23 | level1 calls level2 : Boolean | provenance |  |
+| Recursion.java:198:16:198:23 | level2 calls level0 : Boolean | Recursion.java:192:16:192:23 | level1 calls level2 : Boolean | provenance |  |
 nodes
 | Recursion.java:53:33:53:55 | readToken calls read : Token | semmle.label | readToken calls read : Token |
 | Recursion.java:57:24:57:34 | readToken calls readToken | semmle.label | readToken calls readToken |
@@ -57,6 +95,29 @@ nodes
 | Recursion.java:101:16:101:23 | level2 calls level0 : Boolean | semmle.label | level2 calls level0 : Boolean |
 | Recursion.java:115:16:115:54 | directRecursiveNoDepth calls directRecursiveNoDepth | semmle.label | directRecursiveNoDepth calls directRecursiveNoDepth |
 | Recursion.java:115:16:115:54 | directRecursiveNoDepth calls directRecursiveNoDepth : Boolean | semmle.label | directRecursiveNoDepth calls directRecursiveNoDepth : Boolean |
+| Recursion.java:184:20:184:27 | level0 calls level1 | semmle.label | level0 calls level1 |
+| Recursion.java:184:20:184:27 | level0 calls level1 : Boolean | semmle.label | level0 calls level1 : Boolean |
+| Recursion.java:184:20:184:27 | level0 calls level1 : Boolean | semmle.label | level0 calls level1 : Boolean |
+| Recursion.java:184:20:184:27 | level0 calls level1 : Boolean | semmle.label | level0 calls level1 : Boolean |
+| Recursion.java:186:16:186:23 | level0 calls level2 | semmle.label | level0 calls level2 |
+| Recursion.java:186:16:186:23 | level0 calls level2 | semmle.label | level0 calls level2 |
+| Recursion.java:186:16:186:23 | level0 calls level2 : Boolean | semmle.label | level0 calls level2 : Boolean |
+| Recursion.java:186:16:186:23 | level0 calls level2 : Boolean | semmle.label | level0 calls level2 : Boolean |
+| Recursion.java:186:16:186:23 | level0 calls level2 : Boolean | semmle.label | level0 calls level2 : Boolean |
+| Recursion.java:192:16:192:23 | level1 calls level2 | semmle.label | level1 calls level2 |
+| Recursion.java:192:16:192:23 | level1 calls level2 | semmle.label | level1 calls level2 |
+| Recursion.java:192:16:192:23 | level1 calls level2 : Boolean | semmle.label | level1 calls level2 : Boolean |
+| Recursion.java:192:16:192:23 | level1 calls level2 : Boolean | semmle.label | level1 calls level2 : Boolean |
+| Recursion.java:192:16:192:23 | level1 calls level2 : Boolean | semmle.label | level1 calls level2 : Boolean |
+| Recursion.java:196:20:196:27 | level2 calls level1 | semmle.label | level2 calls level1 |
+| Recursion.java:196:20:196:27 | level2 calls level1 : Boolean | semmle.label | level2 calls level1 : Boolean |
+| Recursion.java:196:20:196:27 | level2 calls level1 : Boolean | semmle.label | level2 calls level1 : Boolean |
+| Recursion.java:196:20:196:27 | level2 calls level1 : Boolean | semmle.label | level2 calls level1 : Boolean |
+| Recursion.java:198:16:198:23 | level2 calls level0 | semmle.label | level2 calls level0 |
+| Recursion.java:198:16:198:23 | level2 calls level0 | semmle.label | level2 calls level0 |
+| Recursion.java:198:16:198:23 | level2 calls level0 : Boolean | semmle.label | level2 calls level0 : Boolean |
+| Recursion.java:198:16:198:23 | level2 calls level0 : Boolean | semmle.label | level2 calls level0 : Boolean |
+| Recursion.java:198:16:198:23 | level2 calls level0 : Boolean | semmle.label | level2 calls level0 : Boolean |
 subpaths
 #select
 | Recursion.java:57:24:57:34 | readToken calls readToken | Recursion.java:53:33:53:55 | readToken calls read : Token | Recursion.java:57:24:57:34 | readToken calls readToken | Found a recursion:  |
@@ -73,3 +134,20 @@ subpaths
 | Recursion.java:101:16:101:23 | level2 calls level0 | Recursion.java:95:16:95:23 | level1 calls level2 : Boolean | Recursion.java:101:16:101:23 | level2 calls level0 | Found a recursion:  |
 | Recursion.java:115:16:115:54 | directRecursiveNoDepth calls directRecursiveNoDepth | Recursion.java:115:16:115:54 | directRecursiveNoDepth calls directRecursiveNoDepth | Recursion.java:115:16:115:54 | directRecursiveNoDepth calls directRecursiveNoDepth | Found a recursion:  |
 | Recursion.java:115:16:115:54 | directRecursiveNoDepth calls directRecursiveNoDepth | Recursion.java:115:16:115:54 | directRecursiveNoDepth calls directRecursiveNoDepth : Boolean | Recursion.java:115:16:115:54 | directRecursiveNoDepth calls directRecursiveNoDepth | Found a recursion:  |
+| Recursion.java:184:20:184:27 | level0 calls level1 | Recursion.java:196:20:196:27 | level2 calls level1 : Boolean | Recursion.java:184:20:184:27 | level0 calls level1 | Found a recursion:  |
+| Recursion.java:184:20:184:27 | level0 calls level1 | Recursion.java:198:16:198:23 | level2 calls level0 : Boolean | Recursion.java:184:20:184:27 | level0 calls level1 | Found a recursion:  |
+| Recursion.java:186:16:186:23 | level0 calls level2 | Recursion.java:184:20:184:27 | level0 calls level1 : Boolean | Recursion.java:186:16:186:23 | level0 calls level2 | Found a recursion:  |
+| Recursion.java:186:16:186:23 | level0 calls level2 | Recursion.java:186:16:186:23 | level0 calls level2 | Recursion.java:186:16:186:23 | level0 calls level2 | Found a recursion:  |
+| Recursion.java:186:16:186:23 | level0 calls level2 | Recursion.java:186:16:186:23 | level0 calls level2 : Boolean | Recursion.java:186:16:186:23 | level0 calls level2 | Found a recursion:  |
+| Recursion.java:186:16:186:23 | level0 calls level2 | Recursion.java:192:16:192:23 | level1 calls level2 : Boolean | Recursion.java:186:16:186:23 | level0 calls level2 | Found a recursion:  |
+| Recursion.java:192:16:192:23 | level1 calls level2 | Recursion.java:184:20:184:27 | level0 calls level1 : Boolean | Recursion.java:192:16:192:23 | level1 calls level2 | Found a recursion:  |
+| Recursion.java:192:16:192:23 | level1 calls level2 | Recursion.java:186:16:186:23 | level0 calls level2 : Boolean | Recursion.java:192:16:192:23 | level1 calls level2 | Found a recursion:  |
+| Recursion.java:192:16:192:23 | level1 calls level2 | Recursion.java:192:16:192:23 | level1 calls level2 | Recursion.java:192:16:192:23 | level1 calls level2 | Found a recursion:  |
+| Recursion.java:192:16:192:23 | level1 calls level2 | Recursion.java:192:16:192:23 | level1 calls level2 : Boolean | Recursion.java:192:16:192:23 | level1 calls level2 | Found a recursion:  |
+| Recursion.java:196:20:196:27 | level2 calls level1 | Recursion.java:196:20:196:27 | level2 calls level1 | Recursion.java:196:20:196:27 | level2 calls level1 | Found a recursion:  |
+| Recursion.java:196:20:196:27 | level2 calls level1 | Recursion.java:196:20:196:27 | level2 calls level1 : Boolean | Recursion.java:196:20:196:27 | level2 calls level1 | Found a recursion:  |
+| Recursion.java:196:20:196:27 | level2 calls level1 | Recursion.java:198:16:198:23 | level2 calls level0 : Boolean | Recursion.java:196:20:196:27 | level2 calls level1 | Found a recursion:  |
+| Recursion.java:198:16:198:23 | level2 calls level0 | Recursion.java:192:16:192:23 | level1 calls level2 : Boolean | Recursion.java:198:16:198:23 | level2 calls level0 | Found a recursion:  |
+| Recursion.java:198:16:198:23 | level2 calls level0 | Recursion.java:196:20:196:27 | level2 calls level1 : Boolean | Recursion.java:198:16:198:23 | level2 calls level0 | Found a recursion:  |
+| Recursion.java:198:16:198:23 | level2 calls level0 | Recursion.java:198:16:198:23 | level2 calls level0 | Recursion.java:198:16:198:23 | level2 calls level0 | Found a recursion:  |
+| Recursion.java:198:16:198:23 | level2 calls level0 | Recursion.java:198:16:198:23 | level2 calls level0 : Boolean | Recursion.java:198:16:198:23 | level2 calls level0 | Found a recursion:  |
diff --git a/java/test/query-tests/security/Recursion/Recursion.java b/java/test/query-tests/security/Recursion/Recursion.java
index f5414c9..e361b9c 100644
--- a/java/test/query-tests/security/Recursion/Recursion.java
+++ b/java/test/query-tests/security/Recursion/Recursion.java
@@ -172,4 +172,37 @@ public static boolean foo() {
     public static boolean bar() {
         return true;
     }
+}
+
+class RecursiveCallNonLinear {
+    // finding: level0->...->level0
+    public boolean level0() {
+        if (someOtherCondition()) {
+            return true;
+        }
+        if (someCondition()) {
+            return level1();
+        }        
+        return level2();
+    }
+    public boolean level1() {
+        if (someCondition()) {
+            return true;
+        }        
+        return level2();
+    }
+    public boolean level2() {
+        if (someCondition()) {
+            return level1();
+        }
+        return level0();
+    }
+
+    private boolean someCondition() {
+        return false;
+    }
+
+    private boolean someOtherCondition() {
+        return true;
+    }
 }
\ No newline at end of file