From bd114db862898bd1f8300adfa2bbdebd0939f838 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Mon, 18 May 2020 09:48:14 +0200 Subject: [PATCH 1/3] Java: Add cfg edges for instanceof-pattern. --- .../src/semmle/code/java/ControlFlowGraph.qll | 22 ++++++++++++++++--- 1 file changed, 19 insertions(+), 3 deletions(-) diff --git a/java/ql/src/semmle/code/java/ControlFlowGraph.qll b/java/ql/src/semmle/code/java/ControlFlowGraph.qll index c14c3d7749d..b5905b240f6 100644 --- a/java/ql/src/semmle/code/java/ControlFlowGraph.qll +++ b/java/ql/src/semmle/code/java/ControlFlowGraph.qll @@ -405,7 +405,7 @@ private module ControlFlowGraphImpl { * Expressions and statements with CFG edges in post-order AST traversal. * * This includes most expressions, except those that initiate or propagate branching control - * flow (`LogicExpr`, `ConditionalExpr`), and parentheses, which aren't in the CFG. + * flow (`LogicExpr`, `ConditionalExpr`). * Only a few statements are included; those with specific side-effects * occurring after the evaluation of their children, that is, `Call`, `ReturnStmt`, * and `ThrowStmt`. CFG nodes without child nodes in the CFG that may complete @@ -429,9 +429,10 @@ private module ControlFlowGraphImpl { or this instanceof CastExpr or - this instanceof InstanceOfExpr + this instanceof InstanceOfExpr and not this.(InstanceOfExpr).isPattern() or - this instanceof LocalVariableDeclExpr + this instanceof LocalVariableDeclExpr and + not this = any(InstanceOfExpr ioe).getLocalVariableDeclExpr() or this instanceof RValue or @@ -573,6 +574,8 @@ private module ControlFlowGraphImpl { or result = first(n.(PostOrderNode).firstChild()) or + result = first(n.(InstanceOfExpr).getExpr()) + or result = first(n.(SynchronizedStmt).getExpr()) or result = n and @@ -707,6 +710,11 @@ private module ControlFlowGraphImpl { last(condexpr.getTrueExpr(), last, completion) ) or + exists(InstanceOfExpr ioe | ioe.isPattern() and ioe = n | + last = n and completion = basicBooleanCompletion(false) or + last = ioe.getLocalVariableDeclExpr() and completion = basicBooleanCompletion(true) + ) + or // The last node of a node executed in post-order is the node itself. n.(PostOrderNode).mayCompleteNormally() and last = n and completion = NormalCompletion() or @@ -916,6 +924,14 @@ private module ControlFlowGraphImpl { result = first(e.getFalseExpr()) ) or + exists(InstanceOfExpr ioe | ioe.isPattern() | + last(ioe.getExpr(), n, completion) and completion = NormalCompletion() and result = ioe + or + n = ioe and + result = ioe.getLocalVariableDeclExpr() and + completion = basicBooleanCompletion(true) + ) + or // In other expressions control flows from left to right and ends in the node itself. exists(PostOrderNode p, int i | last(p.getChildNode(i), n, completion) and completion = NormalCompletion() From 37c8917813a078bc3f4d8e9b5b81adf0ed6e3ce1 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Mon, 18 May 2020 13:19:19 +0200 Subject: [PATCH 2/3] Java: Add test. --- .../ssa/TestInstanceOfPattern.java | 31 +++++++++++++++++++ .../library-tests/ssa/adjacentUses.expected | 3 ++ .../test/library-tests/ssa/firstUse.expected | 12 +++++++ java/ql/test/library-tests/ssa/options | 1 + .../ql/test/library-tests/ssa/ssaDef.expected | 12 +++++++ .../ql/test/library-tests/ssa/ssaUse.expected | 14 +++++++++ 6 files changed, 73 insertions(+) create mode 100644 java/ql/test/library-tests/ssa/TestInstanceOfPattern.java create mode 100644 java/ql/test/library-tests/ssa/options diff --git a/java/ql/test/library-tests/ssa/TestInstanceOfPattern.java b/java/ql/test/library-tests/ssa/TestInstanceOfPattern.java new file mode 100644 index 00000000000..202aaa98480 --- /dev/null +++ b/java/ql/test/library-tests/ssa/TestInstanceOfPattern.java @@ -0,0 +1,31 @@ +class TestInstanceOfPattern { + private String s = "field"; + void test(Object obj) { + if (obj instanceof String s) { + if (s.contains("abc")) {} + } else { + if (s.contains("def")) {} + } + } + void test2(Object obj) { + if (!(obj instanceof String s)) { + if (s.contains("abc")) {} + } else { + if (s.contains("def")) {} + } + } + void test3(Object obj) { + if (obj instanceof String s && s.length() > 5) { + if (s.contains("abc")) {} + } else { + if (s.contains("def")) {} + } + } + void test4(Object obj) { + if (obj instanceof String s || s.length() > 5) { + if (s.contains("abc")) {} + } else { + if (s.contains("def")) {} + } + } +} diff --git a/java/ql/test/library-tests/ssa/adjacentUses.expected b/java/ql/test/library-tests/ssa/adjacentUses.expected index 9c40a18dd6d..d8eb355fa3c 100644 --- a/java/ql/test/library-tests/ssa/adjacentUses.expected +++ b/java/ql/test/library-tests/ssa/adjacentUses.expected @@ -30,3 +30,6 @@ | Test.java:20:14:20:14 | y | Test.java:31:14:31:14 | y | | Test.java:27:19:27:19 | i | Test.java:28:9:28:9 | i | | Test.java:28:9:28:9 | i | Test.java:27:25:27:25 | i | +| TestInstanceOfPattern.java:18:34:18:34 | s | TestInstanceOfPattern.java:19:8:19:8 | s | +| TestInstanceOfPattern.java:25:34:25:34 | s | TestInstanceOfPattern.java:26:8:26:8 | s | +| TestInstanceOfPattern.java:25:34:25:34 | s | TestInstanceOfPattern.java:28:8:28:8 | s | diff --git a/java/ql/test/library-tests/ssa/firstUse.expected b/java/ql/test/library-tests/ssa/firstUse.expected index 0295248ea6b..2d86e6ed117 100644 --- a/java/ql/test/library-tests/ssa/firstUse.expected +++ b/java/ql/test/library-tests/ssa/firstUse.expected @@ -58,3 +58,15 @@ | Test.java:27:25:27:27 | SSA def(i) | Test.java:27:19:27:19 | i | | Test.java:28:4:28:9 | SSA def(x) | Test.java:28:4:28:4 | x | | Test.java:28:4:28:9 | SSA def(x) | Test.java:31:10:31:10 | x | +| TestInstanceOfPattern.java:3:24:9:2 | SSA init(obj) | TestInstanceOfPattern.java:4:7:4:9 | obj | +| TestInstanceOfPattern.java:4:29:4:29 | SSA def(s) | TestInstanceOfPattern.java:5:8:5:8 | s | +| TestInstanceOfPattern.java:7:8:7:8 | SSA impl upd[untracked](this.s) | TestInstanceOfPattern.java:7:8:7:8 | s | +| TestInstanceOfPattern.java:10:25:16:2 | SSA init(obj) | TestInstanceOfPattern.java:11:9:11:11 | obj | +| TestInstanceOfPattern.java:11:31:11:31 | SSA def(s) | TestInstanceOfPattern.java:14:8:14:8 | s | +| TestInstanceOfPattern.java:12:8:12:8 | SSA impl upd[untracked](this.s) | TestInstanceOfPattern.java:12:8:12:8 | s | +| TestInstanceOfPattern.java:17:25:23:2 | SSA init(obj) | TestInstanceOfPattern.java:18:7:18:9 | obj | +| TestInstanceOfPattern.java:18:29:18:29 | SSA def(s) | TestInstanceOfPattern.java:18:34:18:34 | s | +| TestInstanceOfPattern.java:21:8:21:8 | SSA impl upd[untracked](this.s) | TestInstanceOfPattern.java:21:8:21:8 | s | +| TestInstanceOfPattern.java:24:25:30:2 | SSA init(obj) | TestInstanceOfPattern.java:25:7:25:9 | obj | +| TestInstanceOfPattern.java:24:25:30:2 | SSA init(this.s) | TestInstanceOfPattern.java:25:34:25:34 | s | +| TestInstanceOfPattern.java:24:25:30:2 | SSA init(this.s) | TestInstanceOfPattern.java:26:8:26:8 | s | diff --git a/java/ql/test/library-tests/ssa/options b/java/ql/test/library-tests/ssa/options new file mode 100644 index 00000000000..266b0eadc5e --- /dev/null +++ b/java/ql/test/library-tests/ssa/options @@ -0,0 +1 @@ +//semmle-extractor-options: --javac-args --enable-preview -source 14 -target 14 diff --git a/java/ql/test/library-tests/ssa/ssaDef.expected b/java/ql/test/library-tests/ssa/ssaDef.expected index 7ba272c2918..f3acbc1c2f9 100644 --- a/java/ql/test/library-tests/ssa/ssaDef.expected +++ b/java/ql/test/library-tests/ssa/ssaDef.expected @@ -91,3 +91,15 @@ | Test.java:27:8:27:16 | i | Test.java:27:12:27:16 | i | SSA def(i) | | Test.java:27:8:27:16 | i | Test.java:27:19:27:19 | i | SSA phi(i) | | Test.java:27:8:27:16 | i | Test.java:27:25:27:27 | ...++ | SSA def(i) | +| TestInstanceOfPattern.java:3:12:3:21 | obj | TestInstanceOfPattern.java:3:24:9:2 | stmt | SSA init(obj) | +| TestInstanceOfPattern.java:4:22:4:29 | s | TestInstanceOfPattern.java:4:29:4:29 | s | SSA def(s) | +| TestInstanceOfPattern.java:7:8:7:8 | this.s | TestInstanceOfPattern.java:7:8:7:8 | s | SSA impl upd[untracked](this.s) | +| TestInstanceOfPattern.java:10:13:10:22 | obj | TestInstanceOfPattern.java:10:25:16:2 | stmt | SSA init(obj) | +| TestInstanceOfPattern.java:11:24:11:31 | s | TestInstanceOfPattern.java:11:31:11:31 | s | SSA def(s) | +| TestInstanceOfPattern.java:12:8:12:8 | this.s | TestInstanceOfPattern.java:12:8:12:8 | s | SSA impl upd[untracked](this.s) | +| TestInstanceOfPattern.java:17:13:17:22 | obj | TestInstanceOfPattern.java:17:25:23:2 | stmt | SSA init(obj) | +| TestInstanceOfPattern.java:18:22:18:29 | s | TestInstanceOfPattern.java:18:29:18:29 | s | SSA def(s) | +| TestInstanceOfPattern.java:21:8:21:8 | this.s | TestInstanceOfPattern.java:21:8:21:8 | s | SSA impl upd[untracked](this.s) | +| TestInstanceOfPattern.java:24:13:24:22 | obj | TestInstanceOfPattern.java:24:25:30:2 | stmt | SSA init(obj) | +| TestInstanceOfPattern.java:25:22:25:29 | s | TestInstanceOfPattern.java:25:29:25:29 | s | SSA def(s) | +| TestInstanceOfPattern.java:25:34:25:34 | this.s | TestInstanceOfPattern.java:24:25:30:2 | stmt | SSA init(this.s) | diff --git a/java/ql/test/library-tests/ssa/ssaUse.expected b/java/ql/test/library-tests/ssa/ssaUse.expected index dd3d4c1e953..b06f5eaf649 100644 --- a/java/ql/test/library-tests/ssa/ssaUse.expected +++ b/java/ql/test/library-tests/ssa/ssaUse.expected @@ -58,3 +58,17 @@ | Test.java:27:8:27:16 | i | Test.java:27:19:27:19 | i | SSA phi(i) | Test.java:27:19:27:19 | i | | Test.java:27:8:27:16 | i | Test.java:27:19:27:19 | i | SSA phi(i) | Test.java:27:25:27:25 | i | | Test.java:27:8:27:16 | i | Test.java:27:19:27:19 | i | SSA phi(i) | Test.java:28:9:28:9 | i | +| TestInstanceOfPattern.java:3:12:3:21 | obj | TestInstanceOfPattern.java:3:24:9:2 | stmt | SSA init(obj) | TestInstanceOfPattern.java:4:7:4:9 | obj | +| TestInstanceOfPattern.java:4:22:4:29 | s | TestInstanceOfPattern.java:4:29:4:29 | s | SSA def(s) | TestInstanceOfPattern.java:5:8:5:8 | s | +| TestInstanceOfPattern.java:7:8:7:8 | this.s | TestInstanceOfPattern.java:7:8:7:8 | s | SSA impl upd[untracked](this.s) | TestInstanceOfPattern.java:7:8:7:8 | s | +| TestInstanceOfPattern.java:10:13:10:22 | obj | TestInstanceOfPattern.java:10:25:16:2 | stmt | SSA init(obj) | TestInstanceOfPattern.java:11:9:11:11 | obj | +| TestInstanceOfPattern.java:11:24:11:31 | s | TestInstanceOfPattern.java:11:31:11:31 | s | SSA def(s) | TestInstanceOfPattern.java:14:8:14:8 | s | +| TestInstanceOfPattern.java:12:8:12:8 | this.s | TestInstanceOfPattern.java:12:8:12:8 | s | SSA impl upd[untracked](this.s) | TestInstanceOfPattern.java:12:8:12:8 | s | +| TestInstanceOfPattern.java:17:13:17:22 | obj | TestInstanceOfPattern.java:17:25:23:2 | stmt | SSA init(obj) | TestInstanceOfPattern.java:18:7:18:9 | obj | +| TestInstanceOfPattern.java:18:22:18:29 | s | TestInstanceOfPattern.java:18:29:18:29 | s | SSA def(s) | TestInstanceOfPattern.java:18:34:18:34 | s | +| TestInstanceOfPattern.java:18:22:18:29 | s | TestInstanceOfPattern.java:18:29:18:29 | s | SSA def(s) | TestInstanceOfPattern.java:19:8:19:8 | s | +| TestInstanceOfPattern.java:21:8:21:8 | this.s | TestInstanceOfPattern.java:21:8:21:8 | s | SSA impl upd[untracked](this.s) | TestInstanceOfPattern.java:21:8:21:8 | s | +| TestInstanceOfPattern.java:24:13:24:22 | obj | TestInstanceOfPattern.java:24:25:30:2 | stmt | SSA init(obj) | TestInstanceOfPattern.java:25:7:25:9 | obj | +| TestInstanceOfPattern.java:25:34:25:34 | this.s | TestInstanceOfPattern.java:24:25:30:2 | stmt | SSA init(this.s) | TestInstanceOfPattern.java:25:34:25:34 | s | +| TestInstanceOfPattern.java:25:34:25:34 | this.s | TestInstanceOfPattern.java:24:25:30:2 | stmt | SSA init(this.s) | TestInstanceOfPattern.java:26:8:26:8 | s | +| TestInstanceOfPattern.java:25:34:25:34 | this.s | TestInstanceOfPattern.java:24:25:30:2 | stmt | SSA init(this.s) | TestInstanceOfPattern.java:28:8:28:8 | s | From 796eac108f0d8be296a1fccc3d1759a9c0190d95 Mon Sep 17 00:00:00 2001 From: Anders Schack-Mulligen Date: Wed, 27 May 2020 09:19:59 +0200 Subject: [PATCH 3/3] Java: Autoformat --- java/ql/src/semmle/code/java/ControlFlowGraph.qll | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/java/ql/src/semmle/code/java/ControlFlowGraph.qll b/java/ql/src/semmle/code/java/ControlFlowGraph.qll index b5905b240f6..f482398a74f 100644 --- a/java/ql/src/semmle/code/java/ControlFlowGraph.qll +++ b/java/ql/src/semmle/code/java/ControlFlowGraph.qll @@ -711,7 +711,8 @@ private module ControlFlowGraphImpl { ) or exists(InstanceOfExpr ioe | ioe.isPattern() and ioe = n | - last = n and completion = basicBooleanCompletion(false) or + last = n and completion = basicBooleanCompletion(false) + or last = ioe.getLocalVariableDeclExpr() and completion = basicBooleanCompletion(true) ) or