From f02abb3e939d6b5fe316998477bd976d851064a8 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Tue, 3 Mar 2026 13:34:27 +0100 Subject: [PATCH 1/3] Cfg: Handle ExprStmt and BlockStmt in defaultStep. --- .../codeql/controlflow/ControlFlowGraph.qll | 29 ++++--------------- 1 file changed, 5 insertions(+), 24 deletions(-) diff --git a/shared/controlflow/codeql/controlflow/ControlFlowGraph.qll b/shared/controlflow/codeql/controlflow/ControlFlowGraph.qll index 0965217c595b..e4d157ca3895 100644 --- a/shared/controlflow/codeql/controlflow/ControlFlowGraph.qll +++ b/shared/controlflow/codeql/controlflow/ControlFlowGraph.qll @@ -1200,28 +1200,6 @@ module Make0 Ast> { n2.isAfterValue(boollit, any(BooleanSuccessor t | t.getValue() = boollit.getValue())) ) or - exists(ExprStmt exprstmt | - n1.isBefore(exprstmt) and - n2.isBefore(exprstmt.getExpr()) - // the `isAfter(exprstmt.getExpr())` to `isAfter(exprstmt)` case is handled by `propagatesValue` above. - ) - or - exists(BlockStmt blockstmt | - n1.isBefore(blockstmt) and - n2.isBefore(blockstmt.getStmt(0)) - or - not exists(blockstmt.getStmt(_)) and - n1.isBefore(blockstmt) and - n2.isAfter(blockstmt) and - not simpleLeafNode(blockstmt) - or - exists(int i | - n1.isAfter(blockstmt.getStmt(i)) and - n2.isBefore(blockstmt.getStmt(i + 1)) - ) - // the `isAfter(blockstmt.getLastStmt())` to `isAfter(blockstmt)` case is handled by `propagatesValue` above. - ) - or exists(IfStmt ifstmt | n1.isBefore(ifstmt) and n2.isBefore(ifstmt.getCondition()) @@ -1525,8 +1503,11 @@ module Make0 Ast> { ( n1.isBefore(ast) and not exists(getRankedChild(ast, _)) and not simpleLeafNode(ast) or - exists(int i | - n1.isAfter(getRankedChild(ast, i)) and not exists(getRankedChild(ast, i + 1)) + exists(int i, AstNode last | + last = getRankedChild(ast, i) and + not exists(getRankedChild(ast, i + 1)) and + n1.isAfter(last) and + not propagatesValue(last, ast) ) ) and (if postOrInOrder(ast) then n2.isIn(ast) else n2.isAfter(ast)) From d9ea78bfb88077c5011d28319bd9860d59fe2aa9 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Tue, 3 Mar 2026 13:42:13 +0100 Subject: [PATCH 2/3] Cfg: Step directly from a failed case guard to the next case. --- shared/controlflow/codeql/controlflow/ControlFlowGraph.qll | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/shared/controlflow/codeql/controlflow/ControlFlowGraph.qll b/shared/controlflow/codeql/controlflow/ControlFlowGraph.qll index e4d157ca3895..56a909a006c0 100644 --- a/shared/controlflow/codeql/controlflow/ControlFlowGraph.qll +++ b/shared/controlflow/codeql/controlflow/ControlFlowGraph.qll @@ -1412,6 +1412,8 @@ module Make0 Ast> { exists(int i | n1.isAfterValue(getRankedCaseCfgOrder(switch, i), any(MatchingSuccessor t | t.getValue() = false)) + or + n1.isAfterFalse(getRankedCaseCfgOrder(switch, i).getGuard()) | n2.isBefore(getRankedCaseCfgOrder(switch, i + 1)) or @@ -1456,9 +1458,6 @@ module Make0 Ast> { or n1.isAfterTrue(case.getGuard()) and n2 = beforeBody - or - n1.isAfterFalse(case.getGuard()) and - n2.isAfterValue(case, any(MatchingSuccessor t | t.getValue() = false)) ) ) or From daefd5988e758450ded60d8893070d06bd1ed8c7 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Tue, 3 Mar 2026 14:18:10 +0100 Subject: [PATCH 3/3] Java: Accept CFG diff. --- java/ql/test/library-tests/guards12/guard.expected | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/java/ql/test/library-tests/guards12/guard.expected b/java/ql/test/library-tests/guards12/guard.expected index 9e0962c1cad7..e12bf8c6edb6 100644 --- a/java/ql/test/library-tests/guards12/guard.expected +++ b/java/ql/test/library-tests/guards12/guard.expected @@ -11,8 +11,8 @@ hasBranchEdge | Test.java:11:7:11:17 | case ... | Test.java:11:7:11:17 | case ... | Test.java:12:7:12:17 | case ... | false | | Test.java:12:7:12:17 | case ... | Test.java:12:7:12:17 | case ... | Test.java:12:12:12:14 | "d" | true | | Test.java:12:7:12:17 | case ... | Test.java:12:7:12:17 | case ... | Test.java:13:7:13:16 | default | false | +| Test.java:17:7:17:36 | case | Test.java:15:5:15:25 | var ...; | Test.java:17:7:17:36 | After case [no-match] | false | | Test.java:17:7:17:36 | case | Test.java:15:5:15:25 | var ...; | Test.java:17:19:17:19 | | true | -| Test.java:17:7:17:36 | case | Test.java:15:5:15:25 | var ...; | Test.java:18:7:18:17 | case ... | false | | Test.java:17:26:17:33 | ... == ... | Test.java:17:19:17:19 | | Test.java:17:26:17:33 | After ... == ... [false] | false | | Test.java:17:26:17:33 | ... == ... | Test.java:17:19:17:19 | | Test.java:17:38:17:40 | { ... } | true | | Test.java:18:7:18:17 | case ... | Test.java:18:7:18:17 | case ... | Test.java:18:12:18:14 | "e" | true | @@ -21,16 +21,16 @@ hasBranchEdge | Test.java:21:13:21:19 | unknown | Test.java:21:5:21:42 | switch (...) | Test.java:21:27:21:27 | s | false | | Test.java:22:7:22:17 | case ... | Test.java:22:7:22:17 | case ... | Test.java:22:12:22:14 | "f" | true | | Test.java:22:7:22:17 | case ... | Test.java:22:7:22:17 | case ... | Test.java:23:7:23:37 | case | false | +| Test.java:23:7:23:37 | case | Test.java:23:7:23:37 | case | Test.java:23:7:23:37 | After case [no-match] | false | | Test.java:23:7:23:37 | case | Test.java:23:7:23:37 | case | Test.java:23:19:23:20 | s2 | true | -| Test.java:23:7:23:37 | case | Test.java:23:7:23:37 | case | Test.java:24:7:24:17 | case ... | false | | Test.java:23:27:23:34 | ... == ... | Test.java:23:19:23:20 | s2 | Test.java:23:27:23:34 | After ... == ... [false] | false | | Test.java:23:27:23:34 | ... == ... | Test.java:23:19:23:20 | s2 | Test.java:23:39:23:41 | { ... } | true | | Test.java:24:7:24:17 | case ... | Test.java:24:7:24:17 | case ... | Test.java:24:12:24:14 | "g" | true | | Test.java:24:7:24:17 | case ... | Test.java:24:7:24:17 | case ... | Test.java:25:7:25:16 | default | false | | Test.java:28:7:28:15 | case ... | Test.java:27:5:27:14 | switch (...) | Test.java:28:12:28:14 | "h" | true | | Test.java:28:7:28:15 | case ... | Test.java:27:5:27:14 | switch (...) | Test.java:29:7:29:34 | case | false | +| Test.java:29:7:29:34 | case | Test.java:29:7:29:34 | case | Test.java:29:7:29:34 | After case [no-match] | false | | Test.java:29:7:29:34 | case | Test.java:29:7:29:34 | case | Test.java:29:19:29:19 | | true | -| Test.java:29:7:29:34 | case | Test.java:29:7:29:34 | case | Test.java:30:7:30:15 | case ... | false | | Test.java:29:26:29:33 | ... == ... | Test.java:29:19:29:19 | | Test.java:29:26:29:33 | After ... == ... [false] | false | | Test.java:29:26:29:33 | ... == ... | Test.java:29:19:29:19 | | Test.java:29:26:29:33 | After ... == ... [true] | true | | Test.java:30:7:30:15 | case ... | Test.java:30:7:30:15 | case ... | Test.java:30:12:30:14 | "i" | true | @@ -52,6 +52,7 @@ hasBranchEdge | Test.java:17:26:17:33 | ... == ... | Test.java:17:26:17:28 | len | Test.java:17:33:17:33 | 4 | true | true | Test.java:17:38:17:40 | { ... } | | Test.java:18:7:18:17 | case ... | Test.java:16:13:16:13 | s | Test.java:18:12:18:14 | "e" | true | false | Test.java:19:7:19:16 | default | | Test.java:18:7:18:17 | case ... | Test.java:16:13:16:13 | s | Test.java:18:12:18:14 | "e" | true | true | Test.java:18:12:18:14 | "e" | +| Test.java:22:7:22:17 | case ... | Test.java:21:13:21:41 | ...?...:... | Test.java:22:12:22:14 | "f" | true | false | Test.java:23:7:23:37 | After case [no-match] | | Test.java:22:7:22:17 | case ... | Test.java:21:13:21:41 | ...?...:... | Test.java:22:12:22:14 | "f" | true | false | Test.java:23:7:23:37 | case | | Test.java:22:7:22:17 | case ... | Test.java:21:13:21:41 | ...?...:... | Test.java:22:12:22:14 | "f" | true | false | Test.java:23:19:23:20 | s2 | | Test.java:22:7:22:17 | case ... | Test.java:21:13:21:41 | ...?...:... | Test.java:22:12:22:14 | "f" | true | false | Test.java:23:27:23:34 | After ... == ... [false] | @@ -64,6 +65,7 @@ hasBranchEdge | Test.java:23:27:23:34 | ... == ... | Test.java:23:27:23:29 | len | Test.java:23:34:23:34 | 4 | true | true | Test.java:23:39:23:41 | { ... } | | Test.java:24:7:24:17 | case ... | Test.java:21:13:21:41 | ...?...:... | Test.java:24:12:24:14 | "g" | true | false | Test.java:25:7:25:16 | default | | Test.java:24:7:24:17 | case ... | Test.java:21:13:21:41 | ...?...:... | Test.java:24:12:24:14 | "g" | true | true | Test.java:24:12:24:14 | "g" | +| Test.java:28:7:28:15 | case ... | Test.java:27:13:27:13 | s | Test.java:28:12:28:14 | "h" | true | false | Test.java:29:7:29:34 | After case [no-match] | | Test.java:28:7:28:15 | case ... | Test.java:27:13:27:13 | s | Test.java:28:12:28:14 | "h" | true | false | Test.java:29:7:29:34 | case | | Test.java:28:7:28:15 | case ... | Test.java:27:13:27:13 | s | Test.java:28:12:28:14 | "h" | true | false | Test.java:29:19:29:19 | | | Test.java:28:7:28:15 | case ... | Test.java:27:13:27:13 | s | Test.java:28:12:28:14 | "h" | true | false | Test.java:29:26:29:33 | After ... == ... [false] |