From 32f60fd11281fcbf943e920e40991aad43447127 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Mon, 14 Nov 2022 14:07:02 +0100 Subject: [PATCH 1/5] Ruby: Add more local flow tests for use-use flow --- .../dataflow/local/DataflowStep.expected | 109 ++++++++++++++++- .../dataflow/local/Nodes.expected | 60 +++++++++ .../dataflow/local/TaintStep.expected | 115 +++++++++++++++++- .../dataflow/local/local_dataflow.rb | 26 ++++ 4 files changed, 308 insertions(+), 2 deletions(-) diff --git a/ruby/ql/test/library-tests/dataflow/local/DataflowStep.expected b/ruby/ql/test/library-tests/dataflow/local/DataflowStep.expected index c6023a039d38..db3bc7b7296e 100644 --- a/ruby/ql/test/library-tests/dataflow/local/DataflowStep.expected +++ b/ruby/ql/test/library-tests/dataflow/local/DataflowStep.expected @@ -1,6 +1,6 @@ | local_dataflow.rb:1:1:7:3 | self (foo) | local_dataflow.rb:3:8:3:10 | self | | local_dataflow.rb:1:1:7:3 | self in foo | local_dataflow.rb:1:1:7:3 | self (foo) | -| local_dataflow.rb:1:1:124:4 | self (local_dataflow.rb) | local_dataflow.rb:49:1:53:3 | self | +| local_dataflow.rb:1:1:150:3 | self (local_dataflow.rb) | local_dataflow.rb:49:1:53:3 | self | | local_dataflow.rb:1:9:1:9 | a | local_dataflow.rb:1:9:1:9 | a | | local_dataflow.rb:1:9:1:9 | a | local_dataflow.rb:2:7:2:7 | a | | local_dataflow.rb:2:3:2:7 | ... = ... | local_dataflow.rb:3:13:3:13 | b | @@ -279,3 +279,110 @@ | local_dataflow.rb:123:8:123:20 | call to dup | local_dataflow.rb:123:8:123:45 | call to tap | | local_dataflow.rb:123:8:123:45 | call to tap | local_dataflow.rb:123:8:123:49 | call to dup | | local_dataflow.rb:123:26:123:45 | self | local_dataflow.rb:123:32:123:43 | self | +| local_dataflow.rb:126:1:128:3 | self (use) | local_dataflow.rb:127:3:127:8 | self | +| local_dataflow.rb:126:1:128:3 | self in use | local_dataflow.rb:126:1:128:3 | self (use) | +| local_dataflow.rb:130:1:150:3 | self (use_use_madness) | local_dataflow.rb:132:6:132:11 | self | +| local_dataflow.rb:130:1:150:3 | self in use_use_madness | local_dataflow.rb:130:1:150:3 | self (use_use_madness) | +| local_dataflow.rb:131:3:131:8 | ... = ... | local_dataflow.rb:132:10:132:10 | x | +| local_dataflow.rb:131:7:131:8 | "" | local_dataflow.rb:131:3:131:8 | ... = ... | +| local_dataflow.rb:131:7:131:8 | "" | local_dataflow.rb:131:3:131:8 | ... = ... | +| local_dataflow.rb:132:6:132:11 | [post] self | local_dataflow.rb:133:8:133:13 | self | +| local_dataflow.rb:132:6:132:11 | self | local_dataflow.rb:133:8:133:13 | self | +| local_dataflow.rb:132:10:132:10 | x | local_dataflow.rb:133:12:133:12 | x | +| local_dataflow.rb:132:12:148:10 | then ... | local_dataflow.rb:132:3:149:5 | if ... | +| local_dataflow.rb:133:8:133:13 | [post] self | local_dataflow.rb:133:18:133:23 | self | +| local_dataflow.rb:133:8:133:13 | [post] self | local_dataflow.rb:134:7:134:12 | self | +| local_dataflow.rb:133:8:133:13 | call to use | local_dataflow.rb:133:8:133:23 | [false] ... \|\| ... | +| local_dataflow.rb:133:8:133:13 | call to use | local_dataflow.rb:133:8:133:23 | [true] ... \|\| ... | +| local_dataflow.rb:133:8:133:13 | self | local_dataflow.rb:133:18:133:23 | self | +| local_dataflow.rb:133:8:133:13 | self | local_dataflow.rb:134:7:134:12 | self | +| local_dataflow.rb:133:12:133:12 | x | local_dataflow.rb:133:22:133:22 | x | +| local_dataflow.rb:133:12:133:12 | x | local_dataflow.rb:134:11:134:11 | x | +| local_dataflow.rb:133:18:133:23 | [post] self | local_dataflow.rb:134:7:134:12 | self | +| local_dataflow.rb:133:18:133:23 | [post] self | local_dataflow.rb:136:7:136:12 | self | +| local_dataflow.rb:133:18:133:23 | call to use | local_dataflow.rb:133:8:133:23 | [false] ... \|\| ... | +| local_dataflow.rb:133:18:133:23 | call to use | local_dataflow.rb:133:8:133:23 | [true] ... \|\| ... | +| local_dataflow.rb:133:18:133:23 | self | local_dataflow.rb:134:7:134:12 | self | +| local_dataflow.rb:133:18:133:23 | self | local_dataflow.rb:136:7:136:12 | self | +| local_dataflow.rb:133:22:133:22 | x | local_dataflow.rb:134:11:134:11 | x | +| local_dataflow.rb:133:22:133:22 | x | local_dataflow.rb:136:11:136:11 | x | +| local_dataflow.rb:133:24:134:12 | then ... | local_dataflow.rb:133:5:139:7 | if ... | +| local_dataflow.rb:134:7:134:12 | [post] self | local_dataflow.rb:141:9:141:14 | self | +| local_dataflow.rb:134:7:134:12 | call to use | local_dataflow.rb:133:24:134:12 | then ... | +| local_dataflow.rb:134:7:134:12 | self | local_dataflow.rb:141:9:141:14 | self | +| local_dataflow.rb:134:11:134:11 | x | local_dataflow.rb:141:13:141:13 | x | +| local_dataflow.rb:135:5:138:9 | else ... | local_dataflow.rb:133:5:139:7 | if ... | +| local_dataflow.rb:136:7:136:12 | [post] self | local_dataflow.rb:137:10:137:15 | self | +| local_dataflow.rb:136:7:136:12 | self | local_dataflow.rb:137:10:137:15 | self | +| local_dataflow.rb:136:11:136:11 | x | local_dataflow.rb:137:14:137:14 | x | +| local_dataflow.rb:137:7:138:9 | if ... | local_dataflow.rb:135:5:138:9 | else ... | +| local_dataflow.rb:137:10:137:15 | [post] self | local_dataflow.rb:137:21:137:26 | self | +| local_dataflow.rb:137:10:137:15 | [post] self | local_dataflow.rb:141:9:141:14 | self | +| local_dataflow.rb:137:10:137:15 | call to use | local_dataflow.rb:137:10:137:26 | [false] ... && ... | +| local_dataflow.rb:137:10:137:15 | call to use | local_dataflow.rb:137:10:137:26 | [true] ... && ... | +| local_dataflow.rb:137:10:137:15 | self | local_dataflow.rb:137:21:137:26 | self | +| local_dataflow.rb:137:10:137:15 | self | local_dataflow.rb:141:9:141:14 | self | +| local_dataflow.rb:137:14:137:14 | x | local_dataflow.rb:137:25:137:25 | x | +| local_dataflow.rb:137:14:137:14 | x | local_dataflow.rb:141:13:141:13 | x | +| local_dataflow.rb:137:20:137:26 | [false] ! ... | local_dataflow.rb:137:10:137:26 | [false] ... && ... | +| local_dataflow.rb:137:20:137:26 | [true] ! ... | local_dataflow.rb:137:10:137:26 | [true] ... && ... | +| local_dataflow.rb:137:21:137:26 | [post] self | local_dataflow.rb:141:9:141:14 | self | +| local_dataflow.rb:137:21:137:26 | self | local_dataflow.rb:141:9:141:14 | self | +| local_dataflow.rb:137:25:137:25 | x | local_dataflow.rb:141:13:141:13 | x | +| local_dataflow.rb:141:8:141:14 | [false] ! ... | local_dataflow.rb:141:8:141:37 | [false] ... \|\| ... | +| local_dataflow.rb:141:8:141:14 | [false] ! ... | local_dataflow.rb:141:8:141:37 | [true] ... \|\| ... | +| local_dataflow.rb:141:8:141:14 | [true] ! ... | local_dataflow.rb:141:8:141:37 | [true] ... \|\| ... | +| local_dataflow.rb:141:9:141:14 | [post] self | local_dataflow.rb:141:20:141:25 | self | +| local_dataflow.rb:141:9:141:14 | [post] self | local_dataflow.rb:147:5:147:10 | self | +| local_dataflow.rb:141:9:141:14 | self | local_dataflow.rb:141:20:141:25 | self | +| local_dataflow.rb:141:9:141:14 | self | local_dataflow.rb:147:5:147:10 | self | +| local_dataflow.rb:141:13:141:13 | x | local_dataflow.rb:141:24:141:24 | x | +| local_dataflow.rb:141:13:141:13 | x | local_dataflow.rb:147:9:147:9 | x | +| local_dataflow.rb:141:19:141:37 | [false] ( ... ) | local_dataflow.rb:141:8:141:37 | [false] ... \|\| ... | +| local_dataflow.rb:141:19:141:37 | [true] ( ... ) | local_dataflow.rb:141:8:141:37 | [true] ... \|\| ... | +| local_dataflow.rb:141:20:141:25 | [post] self | local_dataflow.rb:141:31:141:36 | self | +| local_dataflow.rb:141:20:141:25 | [post] self | local_dataflow.rb:143:11:143:16 | self | +| local_dataflow.rb:141:20:141:25 | call to use | local_dataflow.rb:141:20:141:36 | [false] ... && ... | +| local_dataflow.rb:141:20:141:25 | call to use | local_dataflow.rb:141:20:141:36 | [true] ... && ... | +| local_dataflow.rb:141:20:141:25 | self | local_dataflow.rb:141:31:141:36 | self | +| local_dataflow.rb:141:20:141:25 | self | local_dataflow.rb:143:11:143:16 | self | +| local_dataflow.rb:141:20:141:36 | [false] ... && ... | local_dataflow.rb:141:19:141:37 | [false] ( ... ) | +| local_dataflow.rb:141:20:141:36 | [true] ... && ... | local_dataflow.rb:141:19:141:37 | [true] ( ... ) | +| local_dataflow.rb:141:24:141:24 | x | local_dataflow.rb:141:35:141:35 | x | +| local_dataflow.rb:141:24:141:24 | x | local_dataflow.rb:143:15:143:15 | x | +| local_dataflow.rb:141:30:141:36 | [false] ! ... | local_dataflow.rb:141:20:141:36 | [false] ... && ... | +| local_dataflow.rb:141:30:141:36 | [true] ! ... | local_dataflow.rb:141:20:141:36 | [true] ... && ... | +| local_dataflow.rb:141:31:141:36 | [post] self | local_dataflow.rb:143:11:143:16 | self | +| local_dataflow.rb:141:31:141:36 | [post] self | local_dataflow.rb:147:5:147:10 | self | +| local_dataflow.rb:141:31:141:36 | self | local_dataflow.rb:143:11:143:16 | self | +| local_dataflow.rb:141:31:141:36 | self | local_dataflow.rb:147:5:147:10 | self | +| local_dataflow.rb:141:35:141:35 | x | local_dataflow.rb:143:15:143:15 | x | +| local_dataflow.rb:141:35:141:35 | x | local_dataflow.rb:147:9:147:9 | x | +| local_dataflow.rb:141:38:142:9 | then ... | local_dataflow.rb:141:5:145:7 | if ... | +| local_dataflow.rb:142:7:142:9 | nil | local_dataflow.rb:141:38:142:9 | then ... | +| local_dataflow.rb:143:5:144:16 | elsif ... | local_dataflow.rb:141:5:145:7 | if ... | +| local_dataflow.rb:143:11:143:16 | [post] self | local_dataflow.rb:143:21:143:26 | self | +| local_dataflow.rb:143:11:143:16 | [post] self | local_dataflow.rb:144:11:144:16 | self | +| local_dataflow.rb:143:11:143:16 | call to use | local_dataflow.rb:143:11:143:26 | [false] ... \|\| ... | +| local_dataflow.rb:143:11:143:16 | call to use | local_dataflow.rb:143:11:143:26 | [true] ... \|\| ... | +| local_dataflow.rb:143:11:143:16 | self | local_dataflow.rb:143:21:143:26 | self | +| local_dataflow.rb:143:11:143:16 | self | local_dataflow.rb:144:11:144:16 | self | +| local_dataflow.rb:143:15:143:15 | x | local_dataflow.rb:143:25:143:25 | x | +| local_dataflow.rb:143:15:143:15 | x | local_dataflow.rb:144:15:144:15 | x | +| local_dataflow.rb:143:21:143:26 | [post] self | local_dataflow.rb:144:11:144:16 | self | +| local_dataflow.rb:143:21:143:26 | [post] self | local_dataflow.rb:147:5:147:10 | self | +| local_dataflow.rb:143:21:143:26 | call to use | local_dataflow.rb:143:11:143:26 | [false] ... \|\| ... | +| local_dataflow.rb:143:21:143:26 | call to use | local_dataflow.rb:143:11:143:26 | [true] ... \|\| ... | +| local_dataflow.rb:143:21:143:26 | self | local_dataflow.rb:144:11:144:16 | self | +| local_dataflow.rb:143:21:143:26 | self | local_dataflow.rb:147:5:147:10 | self | +| local_dataflow.rb:143:25:143:25 | x | local_dataflow.rb:144:15:144:15 | x | +| local_dataflow.rb:143:25:143:25 | x | local_dataflow.rb:147:9:147:9 | x | +| local_dataflow.rb:143:27:144:16 | then ... | local_dataflow.rb:143:5:144:16 | elsif ... | +| local_dataflow.rb:144:11:144:16 | [post] self | local_dataflow.rb:147:5:147:10 | self | +| local_dataflow.rb:144:11:144:16 | call to use | local_dataflow.rb:143:27:144:16 | then ... | +| local_dataflow.rb:144:11:144:16 | self | local_dataflow.rb:147:5:147:10 | self | +| local_dataflow.rb:144:15:144:15 | x | local_dataflow.rb:147:9:147:9 | x | +| local_dataflow.rb:147:5:147:10 | [post] self | local_dataflow.rb:148:5:148:10 | self | +| local_dataflow.rb:147:5:147:10 | self | local_dataflow.rb:148:5:148:10 | self | +| local_dataflow.rb:147:9:147:9 | x | local_dataflow.rb:148:9:148:9 | x | +| local_dataflow.rb:148:5:148:10 | call to use | local_dataflow.rb:132:12:148:10 | then ... | diff --git a/ruby/ql/test/library-tests/dataflow/local/Nodes.expected b/ruby/ql/test/library-tests/dataflow/local/Nodes.expected index 353d1f0d2d65..fcb55f6ada7c 100644 --- a/ruby/ql/test/library-tests/dataflow/local/Nodes.expected +++ b/ruby/ql/test/library-tests/dataflow/local/Nodes.expected @@ -19,6 +19,8 @@ ret | local_dataflow.rb:119:3:119:31 | call to sink | | local_dataflow.rb:123:3:123:50 | call to sink | | local_dataflow.rb:123:32:123:43 | call to puts | +| local_dataflow.rb:127:3:127:8 | call to rand | +| local_dataflow.rb:132:3:149:5 | if ... | arg | local_dataflow.rb:3:8:3:10 | self | local_dataflow.rb:3:8:3:10 | call to p | self | | local_dataflow.rb:3:10:3:10 | a | local_dataflow.rb:3:8:3:10 | call to p | position 0 | @@ -170,3 +172,61 @@ arg | local_dataflow.rb:123:26:123:45 | { ... } | local_dataflow.rb:123:8:123:45 | call to tap | block | | local_dataflow.rb:123:32:123:43 | self | local_dataflow.rb:123:32:123:43 | call to puts | self | | local_dataflow.rb:123:37:123:43 | "hello" | local_dataflow.rb:123:32:123:43 | call to puts | position 0 | +| local_dataflow.rb:127:3:127:8 | self | local_dataflow.rb:127:3:127:8 | call to rand | self | +| local_dataflow.rb:132:6:132:11 | self | local_dataflow.rb:132:6:132:11 | call to use | self | +| local_dataflow.rb:132:10:132:10 | x | local_dataflow.rb:132:6:132:11 | call to use | position 0 | +| local_dataflow.rb:133:8:133:13 | call to use | local_dataflow.rb:133:8:133:23 | [false] ... \|\| ... | self | +| local_dataflow.rb:133:8:133:13 | call to use | local_dataflow.rb:133:8:133:23 | [true] ... \|\| ... | self | +| local_dataflow.rb:133:8:133:13 | self | local_dataflow.rb:133:8:133:13 | call to use | self | +| local_dataflow.rb:133:12:133:12 | x | local_dataflow.rb:133:8:133:13 | call to use | position 0 | +| local_dataflow.rb:133:18:133:23 | call to use | local_dataflow.rb:133:8:133:23 | [false] ... \|\| ... | position 0 | +| local_dataflow.rb:133:18:133:23 | call to use | local_dataflow.rb:133:8:133:23 | [true] ... \|\| ... | position 0 | +| local_dataflow.rb:133:18:133:23 | self | local_dataflow.rb:133:18:133:23 | call to use | self | +| local_dataflow.rb:133:22:133:22 | x | local_dataflow.rb:133:18:133:23 | call to use | position 0 | +| local_dataflow.rb:134:7:134:12 | self | local_dataflow.rb:134:7:134:12 | call to use | self | +| local_dataflow.rb:134:11:134:11 | x | local_dataflow.rb:134:7:134:12 | call to use | position 0 | +| local_dataflow.rb:136:7:136:12 | self | local_dataflow.rb:136:7:136:12 | call to use | self | +| local_dataflow.rb:136:11:136:11 | x | local_dataflow.rb:136:7:136:12 | call to use | position 0 | +| local_dataflow.rb:137:10:137:15 | call to use | local_dataflow.rb:137:10:137:26 | [false] ... && ... | self | +| local_dataflow.rb:137:10:137:15 | call to use | local_dataflow.rb:137:10:137:26 | [true] ... && ... | self | +| local_dataflow.rb:137:10:137:15 | self | local_dataflow.rb:137:10:137:15 | call to use | self | +| local_dataflow.rb:137:14:137:14 | x | local_dataflow.rb:137:10:137:15 | call to use | position 0 | +| local_dataflow.rb:137:20:137:26 | [false] ! ... | local_dataflow.rb:137:10:137:26 | [false] ... && ... | position 0 | +| local_dataflow.rb:137:20:137:26 | [true] ! ... | local_dataflow.rb:137:10:137:26 | [true] ... && ... | position 0 | +| local_dataflow.rb:137:21:137:26 | call to use | local_dataflow.rb:137:20:137:26 | [false] ! ... | self | +| local_dataflow.rb:137:21:137:26 | call to use | local_dataflow.rb:137:20:137:26 | [true] ! ... | self | +| local_dataflow.rb:137:21:137:26 | self | local_dataflow.rb:137:21:137:26 | call to use | self | +| local_dataflow.rb:137:25:137:25 | x | local_dataflow.rb:137:21:137:26 | call to use | position 0 | +| local_dataflow.rb:141:8:141:14 | [false] ! ... | local_dataflow.rb:141:8:141:37 | [false] ... \|\| ... | self | +| local_dataflow.rb:141:8:141:14 | [false] ! ... | local_dataflow.rb:141:8:141:37 | [true] ... \|\| ... | self | +| local_dataflow.rb:141:8:141:14 | [true] ! ... | local_dataflow.rb:141:8:141:37 | [true] ... \|\| ... | self | +| local_dataflow.rb:141:9:141:14 | call to use | local_dataflow.rb:141:8:141:14 | [false] ! ... | self | +| local_dataflow.rb:141:9:141:14 | call to use | local_dataflow.rb:141:8:141:14 | [true] ! ... | self | +| local_dataflow.rb:141:9:141:14 | self | local_dataflow.rb:141:9:141:14 | call to use | self | +| local_dataflow.rb:141:13:141:13 | x | local_dataflow.rb:141:9:141:14 | call to use | position 0 | +| local_dataflow.rb:141:19:141:37 | [false] ( ... ) | local_dataflow.rb:141:8:141:37 | [false] ... \|\| ... | position 0 | +| local_dataflow.rb:141:19:141:37 | [true] ( ... ) | local_dataflow.rb:141:8:141:37 | [true] ... \|\| ... | position 0 | +| local_dataflow.rb:141:20:141:25 | call to use | local_dataflow.rb:141:20:141:36 | [false] ... && ... | self | +| local_dataflow.rb:141:20:141:25 | call to use | local_dataflow.rb:141:20:141:36 | [true] ... && ... | self | +| local_dataflow.rb:141:20:141:25 | self | local_dataflow.rb:141:20:141:25 | call to use | self | +| local_dataflow.rb:141:24:141:24 | x | local_dataflow.rb:141:20:141:25 | call to use | position 0 | +| local_dataflow.rb:141:30:141:36 | [false] ! ... | local_dataflow.rb:141:20:141:36 | [false] ... && ... | position 0 | +| local_dataflow.rb:141:30:141:36 | [true] ! ... | local_dataflow.rb:141:20:141:36 | [true] ... && ... | position 0 | +| local_dataflow.rb:141:31:141:36 | call to use | local_dataflow.rb:141:30:141:36 | [false] ! ... | self | +| local_dataflow.rb:141:31:141:36 | call to use | local_dataflow.rb:141:30:141:36 | [true] ! ... | self | +| local_dataflow.rb:141:31:141:36 | self | local_dataflow.rb:141:31:141:36 | call to use | self | +| local_dataflow.rb:141:35:141:35 | x | local_dataflow.rb:141:31:141:36 | call to use | position 0 | +| local_dataflow.rb:143:11:143:16 | call to use | local_dataflow.rb:143:11:143:26 | [false] ... \|\| ... | self | +| local_dataflow.rb:143:11:143:16 | call to use | local_dataflow.rb:143:11:143:26 | [true] ... \|\| ... | self | +| local_dataflow.rb:143:11:143:16 | self | local_dataflow.rb:143:11:143:16 | call to use | self | +| local_dataflow.rb:143:15:143:15 | x | local_dataflow.rb:143:11:143:16 | call to use | position 0 | +| local_dataflow.rb:143:21:143:26 | call to use | local_dataflow.rb:143:11:143:26 | [false] ... \|\| ... | position 0 | +| local_dataflow.rb:143:21:143:26 | call to use | local_dataflow.rb:143:11:143:26 | [true] ... \|\| ... | position 0 | +| local_dataflow.rb:143:21:143:26 | self | local_dataflow.rb:143:21:143:26 | call to use | self | +| local_dataflow.rb:143:25:143:25 | x | local_dataflow.rb:143:21:143:26 | call to use | position 0 | +| local_dataflow.rb:144:11:144:16 | self | local_dataflow.rb:144:11:144:16 | call to use | self | +| local_dataflow.rb:144:15:144:15 | x | local_dataflow.rb:144:11:144:16 | call to use | position 0 | +| local_dataflow.rb:147:5:147:10 | self | local_dataflow.rb:147:5:147:10 | call to use | self | +| local_dataflow.rb:147:9:147:9 | x | local_dataflow.rb:147:5:147:10 | call to use | position 0 | +| local_dataflow.rb:148:5:148:10 | self | local_dataflow.rb:148:5:148:10 | call to use | self | +| local_dataflow.rb:148:9:148:9 | x | local_dataflow.rb:148:5:148:10 | call to use | position 0 | diff --git a/ruby/ql/test/library-tests/dataflow/local/TaintStep.expected b/ruby/ql/test/library-tests/dataflow/local/TaintStep.expected index 85473aea3ddc..f1b8eb2da264 100644 --- a/ruby/ql/test/library-tests/dataflow/local/TaintStep.expected +++ b/ruby/ql/test/library-tests/dataflow/local/TaintStep.expected @@ -50,7 +50,7 @@ | file://:0:0:0:0 | parameter self of each(0) | file://:0:0:0:0 | [summary] read: argument self.any element in each(0) | | local_dataflow.rb:1:1:7:3 | self (foo) | local_dataflow.rb:3:8:3:10 | self | | local_dataflow.rb:1:1:7:3 | self in foo | local_dataflow.rb:1:1:7:3 | self (foo) | -| local_dataflow.rb:1:1:124:4 | self (local_dataflow.rb) | local_dataflow.rb:49:1:53:3 | self | +| local_dataflow.rb:1:1:150:3 | self (local_dataflow.rb) | local_dataflow.rb:49:1:53:3 | self | | local_dataflow.rb:1:9:1:9 | a | local_dataflow.rb:1:9:1:9 | a | | local_dataflow.rb:1:9:1:9 | a | local_dataflow.rb:2:7:2:7 | a | | local_dataflow.rb:2:3:2:7 | ... = ... | local_dataflow.rb:3:13:3:13 | b | @@ -354,3 +354,116 @@ | local_dataflow.rb:123:8:123:20 | call to dup | local_dataflow.rb:123:8:123:45 | call to tap | | local_dataflow.rb:123:8:123:45 | call to tap | local_dataflow.rb:123:8:123:49 | call to dup | | local_dataflow.rb:123:26:123:45 | self | local_dataflow.rb:123:32:123:43 | self | +| local_dataflow.rb:126:1:128:3 | self (use) | local_dataflow.rb:127:3:127:8 | self | +| local_dataflow.rb:126:1:128:3 | self in use | local_dataflow.rb:126:1:128:3 | self (use) | +| local_dataflow.rb:130:1:150:3 | self (use_use_madness) | local_dataflow.rb:132:6:132:11 | self | +| local_dataflow.rb:130:1:150:3 | self in use_use_madness | local_dataflow.rb:130:1:150:3 | self (use_use_madness) | +| local_dataflow.rb:131:3:131:8 | ... = ... | local_dataflow.rb:132:10:132:10 | x | +| local_dataflow.rb:131:7:131:8 | "" | local_dataflow.rb:131:3:131:8 | ... = ... | +| local_dataflow.rb:131:7:131:8 | "" | local_dataflow.rb:131:3:131:8 | ... = ... | +| local_dataflow.rb:132:6:132:11 | [post] self | local_dataflow.rb:133:8:133:13 | self | +| local_dataflow.rb:132:6:132:11 | self | local_dataflow.rb:133:8:133:13 | self | +| local_dataflow.rb:132:10:132:10 | x | local_dataflow.rb:133:12:133:12 | x | +| local_dataflow.rb:132:12:148:10 | then ... | local_dataflow.rb:132:3:149:5 | if ... | +| local_dataflow.rb:133:8:133:13 | [post] self | local_dataflow.rb:133:18:133:23 | self | +| local_dataflow.rb:133:8:133:13 | [post] self | local_dataflow.rb:134:7:134:12 | self | +| local_dataflow.rb:133:8:133:13 | call to use | local_dataflow.rb:133:8:133:23 | [false] ... \|\| ... | +| local_dataflow.rb:133:8:133:13 | call to use | local_dataflow.rb:133:8:133:23 | [true] ... \|\| ... | +| local_dataflow.rb:133:8:133:13 | self | local_dataflow.rb:133:18:133:23 | self | +| local_dataflow.rb:133:8:133:13 | self | local_dataflow.rb:134:7:134:12 | self | +| local_dataflow.rb:133:12:133:12 | x | local_dataflow.rb:133:22:133:22 | x | +| local_dataflow.rb:133:12:133:12 | x | local_dataflow.rb:134:11:134:11 | x | +| local_dataflow.rb:133:18:133:23 | [post] self | local_dataflow.rb:134:7:134:12 | self | +| local_dataflow.rb:133:18:133:23 | [post] self | local_dataflow.rb:136:7:136:12 | self | +| local_dataflow.rb:133:18:133:23 | call to use | local_dataflow.rb:133:8:133:23 | [false] ... \|\| ... | +| local_dataflow.rb:133:18:133:23 | call to use | local_dataflow.rb:133:8:133:23 | [true] ... \|\| ... | +| local_dataflow.rb:133:18:133:23 | self | local_dataflow.rb:134:7:134:12 | self | +| local_dataflow.rb:133:18:133:23 | self | local_dataflow.rb:136:7:136:12 | self | +| local_dataflow.rb:133:22:133:22 | x | local_dataflow.rb:134:11:134:11 | x | +| local_dataflow.rb:133:22:133:22 | x | local_dataflow.rb:136:11:136:11 | x | +| local_dataflow.rb:133:24:134:12 | then ... | local_dataflow.rb:133:5:139:7 | if ... | +| local_dataflow.rb:134:7:134:12 | [post] self | local_dataflow.rb:141:9:141:14 | self | +| local_dataflow.rb:134:7:134:12 | call to use | local_dataflow.rb:133:24:134:12 | then ... | +| local_dataflow.rb:134:7:134:12 | self | local_dataflow.rb:141:9:141:14 | self | +| local_dataflow.rb:134:11:134:11 | x | local_dataflow.rb:141:13:141:13 | x | +| local_dataflow.rb:135:5:138:9 | else ... | local_dataflow.rb:133:5:139:7 | if ... | +| local_dataflow.rb:136:7:136:12 | [post] self | local_dataflow.rb:137:10:137:15 | self | +| local_dataflow.rb:136:7:136:12 | self | local_dataflow.rb:137:10:137:15 | self | +| local_dataflow.rb:136:11:136:11 | x | local_dataflow.rb:137:14:137:14 | x | +| local_dataflow.rb:137:7:138:9 | if ... | local_dataflow.rb:135:5:138:9 | else ... | +| local_dataflow.rb:137:10:137:15 | [post] self | local_dataflow.rb:137:21:137:26 | self | +| local_dataflow.rb:137:10:137:15 | [post] self | local_dataflow.rb:141:9:141:14 | self | +| local_dataflow.rb:137:10:137:15 | call to use | local_dataflow.rb:137:10:137:26 | [false] ... && ... | +| local_dataflow.rb:137:10:137:15 | call to use | local_dataflow.rb:137:10:137:26 | [true] ... && ... | +| local_dataflow.rb:137:10:137:15 | self | local_dataflow.rb:137:21:137:26 | self | +| local_dataflow.rb:137:10:137:15 | self | local_dataflow.rb:141:9:141:14 | self | +| local_dataflow.rb:137:14:137:14 | x | local_dataflow.rb:137:25:137:25 | x | +| local_dataflow.rb:137:14:137:14 | x | local_dataflow.rb:141:13:141:13 | x | +| local_dataflow.rb:137:20:137:26 | [false] ! ... | local_dataflow.rb:137:10:137:26 | [false] ... && ... | +| local_dataflow.rb:137:20:137:26 | [true] ! ... | local_dataflow.rb:137:10:137:26 | [true] ... && ... | +| local_dataflow.rb:137:21:137:26 | [post] self | local_dataflow.rb:141:9:141:14 | self | +| local_dataflow.rb:137:21:137:26 | call to use | local_dataflow.rb:137:20:137:26 | [false] ! ... | +| local_dataflow.rb:137:21:137:26 | call to use | local_dataflow.rb:137:20:137:26 | [true] ! ... | +| local_dataflow.rb:137:21:137:26 | self | local_dataflow.rb:141:9:141:14 | self | +| local_dataflow.rb:137:25:137:25 | x | local_dataflow.rb:141:13:141:13 | x | +| local_dataflow.rb:141:8:141:14 | [false] ! ... | local_dataflow.rb:141:8:141:37 | [false] ... \|\| ... | +| local_dataflow.rb:141:8:141:14 | [false] ! ... | local_dataflow.rb:141:8:141:37 | [true] ... \|\| ... | +| local_dataflow.rb:141:8:141:14 | [true] ! ... | local_dataflow.rb:141:8:141:37 | [true] ... \|\| ... | +| local_dataflow.rb:141:9:141:14 | [post] self | local_dataflow.rb:141:20:141:25 | self | +| local_dataflow.rb:141:9:141:14 | [post] self | local_dataflow.rb:147:5:147:10 | self | +| local_dataflow.rb:141:9:141:14 | call to use | local_dataflow.rb:141:8:141:14 | [false] ! ... | +| local_dataflow.rb:141:9:141:14 | call to use | local_dataflow.rb:141:8:141:14 | [true] ! ... | +| local_dataflow.rb:141:9:141:14 | self | local_dataflow.rb:141:20:141:25 | self | +| local_dataflow.rb:141:9:141:14 | self | local_dataflow.rb:147:5:147:10 | self | +| local_dataflow.rb:141:13:141:13 | x | local_dataflow.rb:141:24:141:24 | x | +| local_dataflow.rb:141:13:141:13 | x | local_dataflow.rb:147:9:147:9 | x | +| local_dataflow.rb:141:19:141:37 | [false] ( ... ) | local_dataflow.rb:141:8:141:37 | [false] ... \|\| ... | +| local_dataflow.rb:141:19:141:37 | [true] ( ... ) | local_dataflow.rb:141:8:141:37 | [true] ... \|\| ... | +| local_dataflow.rb:141:20:141:25 | [post] self | local_dataflow.rb:141:31:141:36 | self | +| local_dataflow.rb:141:20:141:25 | [post] self | local_dataflow.rb:143:11:143:16 | self | +| local_dataflow.rb:141:20:141:25 | call to use | local_dataflow.rb:141:20:141:36 | [false] ... && ... | +| local_dataflow.rb:141:20:141:25 | call to use | local_dataflow.rb:141:20:141:36 | [true] ... && ... | +| local_dataflow.rb:141:20:141:25 | self | local_dataflow.rb:141:31:141:36 | self | +| local_dataflow.rb:141:20:141:25 | self | local_dataflow.rb:143:11:143:16 | self | +| local_dataflow.rb:141:20:141:36 | [false] ... && ... | local_dataflow.rb:141:19:141:37 | [false] ( ... ) | +| local_dataflow.rb:141:20:141:36 | [true] ... && ... | local_dataflow.rb:141:19:141:37 | [true] ( ... ) | +| local_dataflow.rb:141:24:141:24 | x | local_dataflow.rb:141:35:141:35 | x | +| local_dataflow.rb:141:24:141:24 | x | local_dataflow.rb:143:15:143:15 | x | +| local_dataflow.rb:141:30:141:36 | [false] ! ... | local_dataflow.rb:141:20:141:36 | [false] ... && ... | +| local_dataflow.rb:141:30:141:36 | [true] ! ... | local_dataflow.rb:141:20:141:36 | [true] ... && ... | +| local_dataflow.rb:141:31:141:36 | [post] self | local_dataflow.rb:143:11:143:16 | self | +| local_dataflow.rb:141:31:141:36 | [post] self | local_dataflow.rb:147:5:147:10 | self | +| local_dataflow.rb:141:31:141:36 | call to use | local_dataflow.rb:141:30:141:36 | [false] ! ... | +| local_dataflow.rb:141:31:141:36 | call to use | local_dataflow.rb:141:30:141:36 | [true] ! ... | +| local_dataflow.rb:141:31:141:36 | self | local_dataflow.rb:143:11:143:16 | self | +| local_dataflow.rb:141:31:141:36 | self | local_dataflow.rb:147:5:147:10 | self | +| local_dataflow.rb:141:35:141:35 | x | local_dataflow.rb:143:15:143:15 | x | +| local_dataflow.rb:141:35:141:35 | x | local_dataflow.rb:147:9:147:9 | x | +| local_dataflow.rb:141:38:142:9 | then ... | local_dataflow.rb:141:5:145:7 | if ... | +| local_dataflow.rb:142:7:142:9 | nil | local_dataflow.rb:141:38:142:9 | then ... | +| local_dataflow.rb:143:5:144:16 | elsif ... | local_dataflow.rb:141:5:145:7 | if ... | +| local_dataflow.rb:143:11:143:16 | [post] self | local_dataflow.rb:143:21:143:26 | self | +| local_dataflow.rb:143:11:143:16 | [post] self | local_dataflow.rb:144:11:144:16 | self | +| local_dataflow.rb:143:11:143:16 | call to use | local_dataflow.rb:143:11:143:26 | [false] ... \|\| ... | +| local_dataflow.rb:143:11:143:16 | call to use | local_dataflow.rb:143:11:143:26 | [true] ... \|\| ... | +| local_dataflow.rb:143:11:143:16 | self | local_dataflow.rb:143:21:143:26 | self | +| local_dataflow.rb:143:11:143:16 | self | local_dataflow.rb:144:11:144:16 | self | +| local_dataflow.rb:143:15:143:15 | x | local_dataflow.rb:143:25:143:25 | x | +| local_dataflow.rb:143:15:143:15 | x | local_dataflow.rb:144:15:144:15 | x | +| local_dataflow.rb:143:21:143:26 | [post] self | local_dataflow.rb:144:11:144:16 | self | +| local_dataflow.rb:143:21:143:26 | [post] self | local_dataflow.rb:147:5:147:10 | self | +| local_dataflow.rb:143:21:143:26 | call to use | local_dataflow.rb:143:11:143:26 | [false] ... \|\| ... | +| local_dataflow.rb:143:21:143:26 | call to use | local_dataflow.rb:143:11:143:26 | [true] ... \|\| ... | +| local_dataflow.rb:143:21:143:26 | self | local_dataflow.rb:144:11:144:16 | self | +| local_dataflow.rb:143:21:143:26 | self | local_dataflow.rb:147:5:147:10 | self | +| local_dataflow.rb:143:25:143:25 | x | local_dataflow.rb:144:15:144:15 | x | +| local_dataflow.rb:143:25:143:25 | x | local_dataflow.rb:147:9:147:9 | x | +| local_dataflow.rb:143:27:144:16 | then ... | local_dataflow.rb:143:5:144:16 | elsif ... | +| local_dataflow.rb:144:11:144:16 | [post] self | local_dataflow.rb:147:5:147:10 | self | +| local_dataflow.rb:144:11:144:16 | call to use | local_dataflow.rb:143:27:144:16 | then ... | +| local_dataflow.rb:144:11:144:16 | self | local_dataflow.rb:147:5:147:10 | self | +| local_dataflow.rb:144:15:144:15 | x | local_dataflow.rb:147:9:147:9 | x | +| local_dataflow.rb:147:5:147:10 | [post] self | local_dataflow.rb:148:5:148:10 | self | +| local_dataflow.rb:147:5:147:10 | self | local_dataflow.rb:148:5:148:10 | self | +| local_dataflow.rb:147:9:147:9 | x | local_dataflow.rb:148:9:148:9 | x | +| local_dataflow.rb:148:5:148:10 | call to use | local_dataflow.rb:132:12:148:10 | then ... | diff --git a/ruby/ql/test/library-tests/dataflow/local/local_dataflow.rb b/ruby/ql/test/library-tests/dataflow/local/local_dataflow.rb index f3c6a0972735..d72ed8ac5d40 100644 --- a/ruby/ql/test/library-tests/dataflow/local/local_dataflow.rb +++ b/ruby/ql/test/library-tests/dataflow/local/local_dataflow.rb @@ -122,3 +122,29 @@ def kernel_tap def dup_tap sink(source(1).dup.tap { |x| puts "hello" }.dup) # $ hasValueFlow=1 end + +def use x + rand() +end + +def use_use_madness + x = "" + if use(x) + if use(x) || use(x) + use(x) + else + use(x) + if use(x) && !use(x) + end + end + + if !use(x) || (use(x) && !use(x)) + nil + elsif use(x) || use(x) + use(x) + end + + use(x) + use(x) + end +end \ No newline at end of file From 81a1fa167ab6569bb0956ede441af3e1b31bf63b Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Thu, 10 Nov 2022 16:40:58 +0100 Subject: [PATCH 2/5] SSA: Expose phi-reads --- shared/ssa/codeql/ssa/Ssa.qll | 587 +++++++++++++++++++++++++--------- 1 file changed, 429 insertions(+), 158 deletions(-) diff --git a/shared/ssa/codeql/ssa/Ssa.qll b/shared/ssa/codeql/ssa/Ssa.qll index 19f31f7c8bbe..f7f7683d3863 100644 --- a/shared/ssa/codeql/ssa/Ssa.qll +++ b/shared/ssa/codeql/ssa/Ssa.qll @@ -264,8 +264,22 @@ module Make { ) } + /** + * Holds if `bb` is in the dominance frontier of a block containing a + * read of `v`. + */ + pragma[nomagic] + private predicate inReadDominanceFrontier(BasicBlock bb, SourceVariable v) { + exists(BasicBlock readbb | inDominanceFrontier(readbb, bb) | + lastRefIsRead(readbb, v) + or + exists(TPhiReadNode(v, readbb)) and + not ref(readbb, _, v, _) + ) + } + cached - newtype TDefinition = + private newtype TDefinitionExt = TWriteDef(SourceVariable v, BasicBlock bb, int i) { variableWrite(bb, i, v, _) and liveAfterWrite(bb, i, v) @@ -273,8 +287,16 @@ module Make { TPhiNode(SourceVariable v, BasicBlock bb) { inDefDominanceFrontier(bb, v) and liveAtEntry(bb, v) + } or + TPhiReadNode(SourceVariable v, BasicBlock bb) { + inReadDominanceFrontier(bb, v) and + liveAtEntry(bb, v) and + // no need to create a phi-read if there is already a normal phi + not any(PhiNode def).definesAt(v, bb, _) } + private class TDefinition = TWriteDef or TPhiNode; + private module SsaDefReaches { newtype TSsaRefKind = SsaActualRead() or @@ -283,6 +305,10 @@ module Make { class SsaRead = SsaActualRead or SsaPhiRead; + class SsaDefExt = SsaDef or SsaPhiRead; + + SsaDefExt ssaDefExt() { any() } + /** * A classification of SSA variable references into reads and definitions. */ @@ -307,98 +333,27 @@ module Make { } } - /** - * Holds if `bb` is in the dominance frontier of a block containing a - * read of `v`. - */ - pragma[nomagic] - private predicate inReadDominanceFrontier(BasicBlock bb, SourceVariable v) { - exists(BasicBlock readbb | inDominanceFrontier(readbb, bb) | - lastRefIsRead(readbb, v) - or - phiRead(readbb, v) - ) - } - - /** - * Holds if a phi-read node should be inserted for variable `v` at the beginning - * of basic block `bb`. - * - * Phi-read nodes are like normal phi nodes, but they are inserted based on reads - * instead of writes, and only if the dominance-frontier block does not already - * contain a reference (read or write) to `v`. Unlike normal phi nodes, this is - * an internal implementation detail that is not exposed. - * - * The motivation for adding phi-reads is to improve performance of the use-use - * calculation in cases where there is a large number of reads that can reach the - * same join-point, and from there reach a large number of basic blocks. Example: - * - * ```cs - * if (a) - * use(x); - * else if (b) - * use(x); - * else if (c) - * use(x); - * else if (d) - * use(x); - * // many more ifs ... - * - * // phi-read for `x` inserted here - * - * // program not mentioning `x`, with large basic block graph - * - * use(x); - * ``` - * - * Without phi-reads, the analysis has to replicate reachability for each of - * the guarded uses of `x`. However, with phi-reads, the analysis will limit - * each conditional use of `x` to reach the basic block containing the phi-read - * node for `x`, and only that basic block will have to compute reachability - * through the remainder of the large program. - * - * Like normal reads, each phi-read node `phi-read` can be reached from exactly - * one SSA definition (without passing through another definition): Assume, for - * the sake of contradiction, that there are two reaching definitions `def1` and - * `def2`. Now, if both `def1` and `def2` dominate `phi-read`, then the nearest - * dominating definition will prevent the other from reaching `phi-read`. So, at - * least one of `def1` and `def2` cannot dominate `phi-read`; assume it is `def1`. - * Then `def1` must go through one of its dominance-frontier blocks in order to - * reach `phi-read`. However, such a block will always start with a (normal) phi - * node, which contradicts reachability. - * - * Also, like normal reads, the unique SSA definition `def` that reaches `phi-read`, - * will dominate `phi-read`. Assuming it doesn't means that the path from `def` - * to `phi-read` goes through a dominance-frontier block, and hence a phi node, - * which contradicts reachability. - */ - pragma[nomagic] - predicate phiRead(BasicBlock bb, SourceVariable v) { - inReadDominanceFrontier(bb, v) and - liveAtEntry(bb, v) and - // only if there are no other references to `v` inside `bb` - not ref(bb, _, v, _) and - not exists(Definition def | def.definesAt(v, bb, _)) - } - /** * Holds if the `i`th node of basic block `bb` is a reference to `v`, - * either a read (when `k` is `SsaRead()`) or an SSA definition (when `k` - * is `SsaDef()`). + * either a read (when `k` is `SsaActualRead()`), an SSA definition (when `k` + * is `SsaDef()`), or a phi-read (when `k` is `SsaPhiRead()`). * - * Unlike `Liveness::ref`, this includes `phi` nodes. + * Unlike `Liveness::ref`, this includes `phi` (read) nodes. */ pragma[nomagic] predicate ssaRef(BasicBlock bb, int i, SourceVariable v, SsaRefKind k) { variableRead(bb, i, v, _) and k = SsaActualRead() or - phiRead(bb, v) and - i = -1 and - k = SsaPhiRead() - or - any(Definition def).definesAt(v, bb, i) and - k = SsaDef() + any(DefinitionExt def).definesAt(v, bb, i, k) + } + + /** + * Holds if the `i`th node of basic block `bb` is a reference to `v`, and + * this reference is not a phi-read. + */ + predicate ssaRefNonPhiRead(BasicBlock bb, int i, SourceVariable v) { + ssaRef(bb, i, v, [SsaActualRead().(TSsaRefKind), SsaDef()]) } private newtype OrderedSsaRefIndex = @@ -445,37 +400,36 @@ module Make { * Holds if the SSA definition `def` reaches rank index `rnk` in its own * basic block `bb`. */ - predicate ssaDefReachesRank(BasicBlock bb, Definition def, int rnk, SourceVariable v) { + predicate ssaDefReachesRank(BasicBlock bb, DefinitionExt def, int rnk, SourceVariable v) { exists(int i | - rnk = ssaRefRank(bb, i, v, SsaDef()) and - def.definesAt(v, bb, i) + rnk = ssaRefRank(bb, i, v, ssaDefExt()) and + def.definesAt(v, bb, i, _) ) or ssaDefReachesRank(bb, def, rnk - 1, v) and - rnk = ssaRefRank(bb, _, v, any(SsaRead k)) + rnk = ssaRefRank(bb, _, v, SsaActualRead()) } /** * Holds if the SSA definition of `v` at `def` reaches index `i` in the same * basic block `bb`, without crossing another SSA definition of `v`. */ - predicate ssaDefReachesReadWithinBlock(SourceVariable v, Definition def, BasicBlock bb, int i) { + predicate ssaDefReachesReadWithinBlock(SourceVariable v, DefinitionExt def, BasicBlock bb, int i) { exists(int rnk | ssaDefReachesRank(bb, def, rnk, v) and - rnk = ssaRefRank(bb, i, v, any(SsaRead k)) + rnk = ssaRefRank(bb, i, v, SsaActualRead()) ) } /** * Same as `ssaRefRank()`, but restricted to a particular SSA definition `def`. */ - int ssaDefRank(Definition def, SourceVariable v, BasicBlock bb, int i, SsaRefKind k) { - v = def.getSourceVariable() and + int ssaDefRank(DefinitionExt def, SourceVariable v, BasicBlock bb, int i, SsaRefKind k) { result = ssaRefRank(bb, i, v, k) and ( - ssaDefReachesRead(_, def, bb, i) + ssaDefReachesReadExt(v, def, bb, i) or - def.definesAt(_, bb, i) + def.definesAt(v, bb, i, k) ) } @@ -484,18 +438,38 @@ module Make { * last reference to `v` inside `bb`. */ pragma[noinline] - predicate lastSsaRef(Definition def, SourceVariable v, BasicBlock bb, int i) { + predicate lastSsaRefExt(DefinitionExt def, SourceVariable v, BasicBlock bb, int i) { ssaDefRank(def, v, bb, i, _) = maxSsaRefRank(bb, v) } - predicate defOccursInBlock(Definition def, BasicBlock bb, SourceVariable v, SsaRefKind k) { + /** Gets a phi-read node into which `inp` is an input, if any. */ + pragma[nomagic] + private DefinitionExt getAPhiReadOutput(DefinitionExt inp) { + phiHasInputFromBlockExt(result.(PhiReadNode), inp, _) + } + + pragma[nomagic] + DefinitionExt getAnUltimateOutput(Definition def) { result = getAPhiReadOutput*(def) } + + /** + * Same as `lastSsaRefExt`, but ignores phi-reads. + */ + pragma[noinline] + predicate lastSsaRef(Definition def, SourceVariable v, BasicBlock bb, int i) { + lastSsaRefExt(getAnUltimateOutput(def), v, bb, i) and + ssaRefNonPhiRead(bb, i, v) + } + + predicate defOccursInBlock(DefinitionExt def, BasicBlock bb, SourceVariable v, SsaRefKind k) { exists(ssaDefRank(def, v, bb, _, k)) } pragma[noinline] - private predicate ssaDefReachesThroughBlock(Definition def, BasicBlock bb) { - ssaDefReachesEndOfBlock(bb, def, _) and - not defOccursInBlock(_, bb, def.getSourceVariable(), _) + private predicate ssaDefReachesThroughBlock(DefinitionExt def, BasicBlock bb) { + exists(SourceVariable v | + ssaDefReachesEndOfBlockExt(bb, def, v) and + not defOccursInBlock(_, bb, v, _) + ) } /** @@ -503,85 +477,114 @@ module Make { * `bb2` is a transitive successor of `bb1`, `def` is live at the end of _some_ * predecessor of `bb2`, and the underlying variable for `def` is neither read * nor written in any block on the path between `bb1` and `bb2`. - * - * Phi reads are considered as normal reads for this predicate. */ pragma[nomagic] - private predicate varBlockReachesInclPhiRead(Definition def, BasicBlock bb1, BasicBlock bb2) { - defOccursInBlock(def, bb1, _, _) and + predicate varBlockReachesExt(DefinitionExt def, SourceVariable v, BasicBlock bb1, BasicBlock bb2) { + defOccursInBlock(def, bb1, v, _) and bb2 = getABasicBlockSuccessor(bb1) or exists(BasicBlock mid | - varBlockReachesInclPhiRead(def, bb1, mid) and + varBlockReachesExt(def, v, bb1, mid) and ssaDefReachesThroughBlock(def, mid) and bb2 = getABasicBlockSuccessor(mid) ) } pragma[nomagic] - private predicate phiReadStep(Definition def, SourceVariable v, BasicBlock bb1, BasicBlock bb2) { - varBlockReachesInclPhiRead(def, bb1, bb2) and - defOccursInBlock(def, bb2, v, SsaPhiRead()) + private predicate phiReadStep(DefinitionExt def, PhiReadNode phi, BasicBlock bb1, BasicBlock bb2) { + exists(SourceVariable v | + varBlockReachesExt(pragma[only_bind_into](def), v, bb1, pragma[only_bind_into](bb2)) and + phi.definesAt(v, bb2, _, _) and + not ref(bb2, _, v, _) + ) } pragma[nomagic] - private predicate varBlockReachesExclPhiRead(Definition def, BasicBlock bb1, BasicBlock bb2) { - varBlockReachesInclPhiRead(pragma[only_bind_into](def), bb1, pragma[only_bind_into](bb2)) and - ssaRef(bb2, _, def.getSourceVariable(), [SsaActualRead().(TSsaRefKind), SsaDef()]) + private predicate varBlockReachesExclPhiRead( + DefinitionExt def, SourceVariable v, BasicBlock bb1, BasicBlock bb2 + ) { + varBlockReachesExt(def, v, bb1, bb2) and + ssaRefNonPhiRead(bb2, _, v) or - exists(BasicBlock mid | - varBlockReachesExclPhiRead(def, mid, bb2) and - phiReadStep(def, _, bb1, mid) + exists(PhiReadNode phi, BasicBlock mid | + varBlockReachesExclPhiRead(phi, v, mid, bb2) and + phiReadStep(def, phi, bb1, mid) ) } /** - * Holds if `def` is accessed in basic block `bb1` (either a read or a write), - * the underlying variable `v` of `def` is accessed in basic block `bb2` - * (either a read or a write), `bb2` is a transitive successor of `bb1`, and - * `v` is neither read nor written in any block on the path between `bb1` - * and `bb2`. + * Same as `varBlockReachesExt`, but ignores phi-reads, and furthermore + * `bb2` is restricted to blocks in which the underlying variable `v` of + * `def` is referenced (either a read or a write). */ pragma[nomagic] - predicate varBlockReaches(Definition def, BasicBlock bb1, BasicBlock bb2) { - varBlockReachesExclPhiRead(def, bb1, bb2) and - not defOccursInBlock(def, bb1, _, SsaPhiRead()) + predicate varBlockReachesRef(Definition def, SourceVariable v, BasicBlock bb1, BasicBlock bb2) { + varBlockReachesExclPhiRead(getAnUltimateOutput(def), v, bb1, bb2) and + ssaRefNonPhiRead(bb1, _, v) + } + + pragma[nomagic] + predicate defAdjacentReadExt(DefinitionExt def, BasicBlock bb1, BasicBlock bb2, int i2) { + exists(SourceVariable v | + varBlockReachesExt(def, v, bb1, bb2) and + ssaRefRank(bb2, i2, v, SsaActualRead()) = 1 + ) } pragma[nomagic] predicate defAdjacentRead(Definition def, BasicBlock bb1, BasicBlock bb2, int i2) { - varBlockReaches(def, bb1, bb2) and - ssaRefRank(bb2, i2, def.getSourceVariable(), SsaActualRead()) = 1 + exists(SourceVariable v | varBlockReachesRef(def, v, bb1, bb2) | + ssaRefRank(bb2, i2, v, SsaActualRead()) = 1 + or + ssaRefRank(bb2, _, v, SsaPhiRead()) = 1 and + ssaRefRank(bb2, i2, v, SsaActualRead()) = 2 + ) } /** * Holds if `def` is accessed in basic block `bb` (either a read or a write), - * `bb1` can reach a transitive successor `bb2` where `def` is no longer live, + * `bb` can reach a transitive successor `bb2` where `def` is no longer live, * and `v` is neither read nor written in any block on the path between `bb` * and `bb2`. */ pragma[nomagic] - predicate varBlockReachesExit(Definition def, BasicBlock bb) { - exists(BasicBlock bb2 | varBlockReachesInclPhiRead(def, bb, bb2) | + predicate varBlockReachesExitExt(DefinitionExt def, BasicBlock bb) { + exists(BasicBlock bb2 | varBlockReachesExt(def, _, bb, bb2) | not defOccursInBlock(def, bb2, _, _) and - not ssaDefReachesEndOfBlock(bb2, def, _) + not ssaDefReachesEndOfBlockExt(bb2, def, _) + ) + } + + pragma[nomagic] + private predicate varBlockReachesExitExclPhiRead(DefinitionExt def, BasicBlock bb) { + exists(BasicBlock bb2, SourceVariable v | + varBlockReachesExt(def, v, bb, bb2) and + not defOccursInBlock(def, bb2, _, _) and + not ssaDefReachesEndOfBlockExt(bb2, def, _) and + not any(PhiReadNode phi).definesAt(v, bb2, _, _) ) or - exists(BasicBlock mid | - varBlockReachesExit(def, mid) and - phiReadStep(def, _, bb, mid) + exists(PhiReadNode phi, BasicBlock bb2 | + varBlockReachesExitExclPhiRead(phi, bb2) and + phiReadStep(def, phi, bb, bb2) ) } - } - predicate phiReadExposedForTesting = phiRead/2; + /** + * Same as `varBlockReachesExitExt`, but ignores phi-reads. + */ + pragma[nomagic] + predicate varBlockReachesExit(Definition def, BasicBlock bb) { + varBlockReachesExitExclPhiRead(getAnUltimateOutput(def), bb) + } + } private import SsaDefReaches pragma[nomagic] - private predicate liveThrough(BasicBlock bb, SourceVariable v) { + private predicate liveThroughExt(BasicBlock bb, SourceVariable v) { liveAtExit(bb, v) and - not ssaRef(bb, _, v, SsaDef()) + not ssaRef(bb, _, v, ssaDefExt()) } /** @@ -592,7 +595,7 @@ module Make { * SSA definition of `v`. */ pragma[nomagic] - predicate ssaDefReachesEndOfBlock(BasicBlock bb, Definition def, SourceVariable v) { + predicate ssaDefReachesEndOfBlockExt(BasicBlock bb, DefinitionExt def, SourceVariable v) { exists(int last | last = maxSsaRefRank(pragma[only_bind_into](bb), pragma[only_bind_into](v)) and ssaDefReachesRank(bb, def, last, v) and @@ -605,8 +608,31 @@ module Make { // the node. If two definitions dominate a node then one must dominate the // other, so therefore the definition of _closest_ is given by the dominator // tree. Thus, reaching definitions can be calculated in terms of dominance. - ssaDefReachesEndOfBlock(getImmediateBasicBlockDominator(bb), def, pragma[only_bind_into](v)) and - liveThrough(bb, pragma[only_bind_into](v)) + ssaDefReachesEndOfBlockExt(getImmediateBasicBlockDominator(bb), def, pragma[only_bind_into](v)) and + liveThroughExt(bb, pragma[only_bind_into](v)) + } + + pragma[nomagic] + private predicate phiReadReachesEndOfBlock(BasicBlock pred, BasicBlock bb, SourceVariable v) { + exists(PhiReadNode phi | + ssaDefReachesEndOfBlockExt(bb, phi, v) and + pred = getImmediateBasicBlockDominator(phi.getBasicBlock()) + ) + } + + /** + * NB: If this predicate is exposed, it should be cached. + * + * Same as `ssaDefReachesEndOfBlockExt`, but ignores phi-reads. + */ + pragma[nomagic] + predicate ssaDefReachesEndOfBlock(BasicBlock bb, Definition def, SourceVariable v) { + ssaDefReachesEndOfBlockExt(bb, def, v) + or + exists(BasicBlock mid | + ssaDefReachesEndOfBlock(mid, def, v) and + phiReadReachesEndOfBlock(mid, bb, v) + ) } /** @@ -623,20 +649,50 @@ module Make { ) } + /** + * NB: If this predicate is exposed, it should be cached. + * + * Holds if `inp` is an input to the phi (read) node `phi` along the edge originating in `bb`. + */ + pragma[nomagic] + predicate phiHasInputFromBlockExt(DefinitionExt phi, DefinitionExt inp, BasicBlock bb) { + exists(SourceVariable v, BasicBlock bbDef | + phi.definesAt(v, bbDef, _, _) and + getABasicBlockPredecessor(bbDef) = bb and + ssaDefReachesEndOfBlockExt(bb, inp, v) + | + phi instanceof PhiNode or + phi instanceof PhiReadNode + ) + } + /** * NB: If this predicate is exposed, it should be cached. * * Holds if the SSA definition of `v` at `def` reaches a read at index `i` in - * basic block `bb`, without crossing another SSA definition of `v`. The read - * is of kind `rk`. + * basic block `bb`, without crossing another SSA definition of `v`. + */ + pragma[nomagic] + predicate ssaDefReachesReadExt(SourceVariable v, DefinitionExt def, BasicBlock bb, int i) { + ssaDefReachesReadWithinBlock(v, def, bb, i) + or + ssaRef(bb, i, v, SsaActualRead()) and + ssaDefReachesEndOfBlockExt(getABasicBlockPredecessor(bb), def, v) and + not ssaDefReachesReadWithinBlock(v, _, bb, i) + } + + /** + * NB: If this predicate is exposed, it should be cached. + * + * Same as `ssaDefReachesReadExt`, but ignores phi-reads. */ pragma[nomagic] predicate ssaDefReachesRead(SourceVariable v, Definition def, BasicBlock bb, int i) { ssaDefReachesReadWithinBlock(v, def, bb, i) or - ssaRef(bb, i, v, any(SsaRead k)) and + ssaRef(bb, i, v, SsaActualRead()) and ssaDefReachesEndOfBlock(getABasicBlockPredecessor(bb), def, v) and - not ssaDefReachesReadWithinBlock(v, _, bb, i) + not exists(Definition other | ssaDefReachesReadWithinBlock(v, other, bb, i)) } /** @@ -647,14 +703,32 @@ module Make { * path between them without any read of `def`. */ pragma[nomagic] - predicate adjacentDefRead(Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2) { + predicate adjacentDefReadExt( + DefinitionExt def, SourceVariable v, BasicBlock bb1, int i1, BasicBlock bb2, int i2 + ) { exists(int rnk | - rnk = ssaDefRank(def, _, bb1, i1, _) and - rnk + 1 = ssaDefRank(def, _, bb1, i2, SsaActualRead()) and - variableRead(bb1, i2, _, _) and + rnk = ssaDefRank(def, v, bb1, i1, _) and + rnk + 1 = ssaDefRank(def, v, bb1, i2, SsaActualRead()) and + variableRead(bb1, i2, v, _) and bb2 = bb1 ) or + lastSsaRefExt(def, v, bb1, i1) and + defAdjacentReadExt(def, bb1, bb2, i2) + } + + /** + * NB: If this predicate is exposed, it should be cached. + * + * Same as `adjacentDefReadExt`, but ignores phi-reads. + */ + pragma[nomagic] + predicate adjacentDefRead(Definition def, BasicBlock bb1, int i1, BasicBlock bb2, int i2) { + exists(SourceVariable v | + adjacentDefReadExt(getAnUltimateOutput(def), v, bb1, i1, bb2, i2) and + ssaRefNonPhiRead(bb1, i1, v) + ) + or lastSsaRef(def, _, bb1, i1) and defAdjacentRead(def, bb1, bb2, i2) } @@ -704,19 +778,41 @@ module Make { * without passing through another read or write. */ pragma[nomagic] + predicate lastRefRedefExt( + DefinitionExt def, SourceVariable v, BasicBlock bb, int i, DefinitionExt next + ) { + // Next reference to `v` inside `bb` is a write + exists(int rnk, int j | + rnk = ssaDefRank(def, v, bb, i, _) and + next.definesAt(v, bb, j, _) and + rnk + 1 = ssaRefRank(bb, j, v, ssaDefExt()) + ) + or + // Can reach a write using one or more steps + lastSsaRefExt(def, v, bb, i) and + exists(BasicBlock bb2 | + varBlockReachesExt(def, v, bb, bb2) and + 1 = ssaDefRank(next, v, bb2, _, ssaDefExt()) + ) + } + + /** + * NB: If this predicate is exposed, it should be cached. + * + * Same as `lastRefRedefExt`, but ignores phi-reads. + */ + pragma[nomagic] predicate lastRefRedef(Definition def, BasicBlock bb, int i, Definition next) { exists(SourceVariable v | - // Next reference to `v` inside `bb` is a write - exists(int rnk, int j | - rnk = ssaDefRank(def, v, bb, i, _) and - next.definesAt(v, bb, j) and - rnk + 1 = ssaRefRank(bb, j, v, SsaDef()) - ) - or - // Can reach a write using one or more steps + lastRefRedefExt(getAnUltimateOutput(def), v, bb, i, next) and + ssaRefNonPhiRead(bb, i, v) + ) + or + // Can reach a write using one or more steps + exists(SourceVariable v | lastSsaRef(def, v, bb, i) and exists(BasicBlock bb2 | - varBlockReaches(def, bb, bb2) and + varBlockReachesRef(def, v, bb, bb2) and 1 = ssaDefRank(next, v, bb2, _, SsaDef()) ) ) @@ -770,6 +866,25 @@ module Make { * another read. */ pragma[nomagic] + predicate lastRefExt(DefinitionExt def, BasicBlock bb, int i) { + // Can reach another definition + lastRefRedefExt(def, _, bb, i, _) + or + exists(SourceVariable v | lastSsaRefExt(def, v, bb, i) | + // Can reach exit directly + bb instanceof ExitBasicBlock + or + // Can reach a block using one or more steps, where `def` is no longer live + varBlockReachesExitExt(def, bb) + ) + } + + /** + * NB: If this predicate is exposed, it should be cached. + * + * Same as `lastRefExt`, but ignores phi-reads. + */ + pragma[nomagic] predicate lastRef(Definition def, BasicBlock bb, int i) { // Can reach another definition lastRefRedef(def, bb, i, _) @@ -819,7 +934,7 @@ module Make { final BasicBlock getBasicBlock() { this.definesAt(_, result, _) } /** Gets a textual representation of this SSA definition. */ - string toString() { none() } + string toString() { result = "SSA def(" + this.getSourceVariable() + ")" } } /** An SSA definition that corresponds to a write. */ @@ -829,13 +944,11 @@ module Make { private int i; WriteDefinition() { this = TWriteDef(v, bb, i) } - - override string toString() { result = "WriteDef" } } /** A phi node. */ class PhiNode extends Definition, TPhiNode { - override string toString() { result = "Phi" } + override string toString() { result = "SSA phi(" + this.getSourceVariable() + ")" } } /** @@ -851,6 +964,120 @@ module Make { } } + /** + * An extended static single assignment (SSA) definition. + * + * This is either a normal SSA definition (`Definition`) or a + * phi-read node (`PhiReadNode`). + */ + class DefinitionExt extends TDefinitionExt { + /** Gets the source variable underlying this SSA definition. */ + SourceVariable getSourceVariable() { this.definesAt(result, _, _, _) } + + /** + * Holds if this SSA definition defines `v` at index `i` in basic block `bb`. + * Phi nodes are considered to be at index `-1`, while normal variable writes + * are at the index of the control flow node they wrap. + */ + final predicate definesAt(SourceVariable v, BasicBlock bb, int i, SsaRefKind kind) { + this.(Definition).definesAt(v, bb, i) and + kind = SsaDef() + or + this = TPhiReadNode(v, bb) and i = -1 and kind = SsaPhiRead() + } + + /** Gets the basic block to which this SSA definition belongs. */ + final BasicBlock getBasicBlock() { this.definesAt(_, result, _, _) } + + /** Gets a textual representation of this SSA definition. */ + string toString() { result = this.(Definition).toString() } + } + + /** + * A phi-read node. + * + * Phi-read nodes are like normal phi nodes, but they are inserted based on reads + * instead of writes, and only if the dominance-frontier block does not already + * contain a normal phi node. + * + * The motivation for adding phi-reads is to improve performance of the use-use + * calculation in cases where there is a large number of reads that can reach the + * same join-point, and from there reach a large number of basic blocks. Example: + * + * ```cs + * if (a) + * use(x); + * else if (b) + * use(x); + * else if (c) + * use(x); + * else if (d) + * use(x); + * // many more ifs ... + * + * // phi-read for `x` inserted here + * + * // program not mentioning `x`, with large basic block graph + * + * use(x); + * ``` + * + * Without phi-reads, the analysis has to replicate reachability for each of + * the guarded uses of `x`. However, with phi-reads, the analysis will limit + * each conditional use of `x` to reach the basic block containing the phi-read + * node for `x`, and only that basic block will have to compute reachability + * through the remainder of the large program. + * + * Another motivation for phi-reads is when a large number of reads can reach + * another large number of reads: + * + * ```cs + * if (a) + * use(x); + * else if (b) + * use(x); + * else if (c) + * use(x); + * else if (d) + * use(x); + * // many more ifs ... + * + * // phi-read for `x` inserted here + * + * if (a) + * use(x); + * else if (b) + * use(x); + * else if (c) + * use(x); + * else if (d) + * use(x); + * // many more ifs ... + * ``` + * + * Without phi-reads, one needs to add `n*m` data-flow edges (assuming `n` reads + * before the phi-read and `m` reads after the phi-read), whereas if we include + * phi-reads in the data-flow graph, we only need to add `n+m` edges. + * + * Like normal reads, each phi-read node `phi-read` can be reached from exactly + * one SSA definition (without passing through another definition): Assume, for + * the sake of contradiction, that there are two reaching definitions `def1` and + * `def2`. Now, if both `def1` and `def2` dominate `phi-read`, then the nearest + * dominating definition will prevent the other from reaching `phi-read`. So, at + * least one of `def1` and `def2` cannot dominate `phi-read`; assume it is `def1`. + * Then `def1` must go through one of its dominance-frontier blocks in order to + * reach `phi-read`. However, such a block will always start with a (normal) phi + * node, which contradicts reachability. + * + * Also, like normal reads, the unique SSA definition `def` that reaches `phi-read`, + * will dominate `phi-read`. Assuming it doesn't means that the path from `def` + * to `phi-read` goes through a dominance-frontier block, and hence a phi node, + * which contradicts reachability. + */ + class PhiReadNode extends DefinitionExt, TPhiReadNode { + override string toString() { result = "SSA phi read(" + this.getSourceVariable() + ")" } + } + /** Provides a set of consistency queries. */ module Consistency { /** A definition that is relevant for the consistency queries. */ @@ -861,18 +1088,40 @@ module Make { ); } + /** A definition that is relevant for the consistency queries. */ + abstract class RelevantDefinitionExt extends DefinitionExt { + /** Override this predicate to ensure locations in consistency results. */ + abstract predicate hasLocationInfo( + string filepath, int startline, int startcolumn, int endline, int endcolumn + ); + } + /** Holds if a read can be reached from multiple definitions. */ query predicate nonUniqueDef(RelevantDefinition def, SourceVariable v, BasicBlock bb, int i) { ssaDefReachesRead(v, def, bb, i) and not exists(unique(Definition def0 | ssaDefReachesRead(v, def0, bb, i))) } + /** Holds if a read can be reached from multiple definitions. */ + query predicate nonUniqueDefExt( + RelevantDefinitionExt def, SourceVariable v, BasicBlock bb, int i + ) { + ssaDefReachesReadExt(v, def, bb, i) and + not exists(unique(DefinitionExt def0 | ssaDefReachesReadExt(v, def0, bb, i))) + } + /** Holds if a read cannot be reached from a definition. */ query predicate readWithoutDef(SourceVariable v, BasicBlock bb, int i) { variableRead(bb, i, v, _) and not ssaDefReachesRead(v, _, bb, i) } + /** Holds if a read cannot be reached from a definition. */ + query predicate readWithoutDefExt(SourceVariable v, BasicBlock bb, int i) { + variableRead(bb, i, v, _) and + not ssaDefReachesReadExt(v, _, bb, i) + } + /** Holds if a definition cannot reach a read. */ query predicate deadDef(RelevantDefinition def, SourceVariable v) { v = def.getSourceVariable() and @@ -881,6 +1130,14 @@ module Make { not uncertainWriteDefinitionInput(_, def) } + /** Holds if a definition cannot reach a read. */ + query predicate deadDefExt(RelevantDefinitionExt def, SourceVariable v) { + v = def.getSourceVariable() and + not ssaDefReachesReadExt(_, def, _, _) and + not phiHasInputFromBlockExt(_, def, _) and + not uncertainWriteDefinitionInput(_, def) + } + /** Holds if a read is not dominated by a definition. */ query predicate notDominatedByDef(RelevantDefinition def, SourceVariable v, BasicBlock bb, int i) { exists(BasicBlock bbDef, int iDef | def.definesAt(v, bbDef, iDef) | @@ -892,5 +1149,19 @@ module Make { not def.definesAt(v, getImmediateBasicBlockDominator*(bb), _) ) } + + /** Holds if a read is not dominated by a definition. */ + query predicate notDominatedByDefExt( + RelevantDefinitionExt def, SourceVariable v, BasicBlock bb, int i + ) { + exists(BasicBlock bbDef, int iDef | def.definesAt(v, bbDef, iDef, _) | + ssaDefReachesReadWithinBlock(v, def, bb, i) and + (bb != bbDef or i < iDef) + or + ssaDefReachesReadExt(v, def, bb, i) and + not ssaDefReachesReadWithinBlock(v, def, bb, i) and + not def.definesAt(v, getImmediateBasicBlockDominator*(bb), _, _) + ) + } } } From bd78e73131061aa7732278546656e19146016a61 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Thu, 10 Nov 2022 16:41:08 +0100 Subject: [PATCH 3/5] C#: Add tests for phi reads --- .../ql/consistency-queries/SsaConsistency.ql | 11 ++- .../lib/semmle/code/csharp/dataflow/SSA.qll | 38 +++----- .../code/csharp/dataflow/internal/SsaImpl.qll | 91 ++++++++++++++++--- .../dataflow/ssa/SSAPhiRead.expected | 34 ++++++- .../library-tests/dataflow/ssa/SSAPhiRead.ql | 17 +++- .../test/library-tests/dataflow/ssa/Test.cs | 2 +- 6 files changed, 144 insertions(+), 49 deletions(-) diff --git a/csharp/ql/consistency-queries/SsaConsistency.ql b/csharp/ql/consistency-queries/SsaConsistency.ql index bd666a71e493..225aeb4e6de4 100644 --- a/csharp/ql/consistency-queries/SsaConsistency.ql +++ b/csharp/ql/consistency-queries/SsaConsistency.ql @@ -1,5 +1,6 @@ import csharp -import semmle.code.csharp.dataflow.internal.SsaImpl::Consistency +import semmle.code.csharp.dataflow.internal.SsaImpl as Impl +import Impl::Consistency import Ssa class MyRelevantDefinition extends RelevantDefinition, Ssa::Definition { @@ -10,6 +11,14 @@ class MyRelevantDefinition extends RelevantDefinition, Ssa::Definition { } } +class MyRelevantDefinitionExt extends RelevantDefinitionExt, Impl::DefinitionExt { + override predicate hasLocationInfo( + string filepath, int startline, int startcolumn, int endline, int endcolumn + ) { + this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) + } +} + query predicate localDeclWithSsaDef(LocalVariableDeclExpr d) { // Local variables in C# must be initialized before every use, so uninitialized // local variables should not have an SSA definition, as that would imply that diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/SSA.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/SSA.qll index f377d94e15c2..8764da0a784d 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/SSA.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/SSA.qll @@ -138,25 +138,6 @@ module Ssa { } } - private string getSplitString(Definition def) { - exists(ControlFlow::BasicBlock bb, int i, ControlFlow::Node cfn | - def.definesAt(_, bb, i) and - result = cfn.(ControlFlow::Nodes::ElementNode).getSplitsString() - | - cfn = bb.getNode(i) - or - not exists(bb.getNode(i)) and - cfn = bb.getFirstNode() - ) - } - - private string getToStringPrefix(Definition def) { - result = "[" + getSplitString(def) + "] " - or - not exists(getSplitString(def)) and - result = "" - } - /** * A static single assignment (SSA) definition. Either an explicit variable * definition (`ExplicitDefinition`), an implicit variable definition @@ -521,8 +502,8 @@ module Ssa { override string toString() { if this.getADefinition() instanceof AssignableDefinitions::ImplicitParameterDefinition - then result = getToStringPrefix(this) + "SSA param(" + this.getSourceVariable() + ")" - else result = getToStringPrefix(this) + "SSA def(" + this.getSourceVariable() + ")" + then result = SsaImpl::getToStringPrefix(this) + "SSA param(" + this.getSourceVariable() + ")" + else result = SsaImpl::getToStringPrefix(this) + "SSA def(" + this.getSourceVariable() + ")" } override Location getLocation() { result = ad.getLocation() } @@ -570,8 +551,12 @@ module Ssa { override string toString() { if this.getSourceVariable().getAssignable() instanceof LocalScopeVariable - then result = getToStringPrefix(this) + "SSA capture def(" + this.getSourceVariable() + ")" - else result = getToStringPrefix(this) + "SSA entry def(" + this.getSourceVariable() + ")" + then + result = + SsaImpl::getToStringPrefix(this) + "SSA capture def(" + this.getSourceVariable() + ")" + else + result = + SsaImpl::getToStringPrefix(this) + "SSA entry def(" + this.getSourceVariable() + ")" } override Location getLocation() { result = this.getCallable().getLocation() } @@ -612,7 +597,7 @@ module Ssa { } override string toString() { - result = getToStringPrefix(this) + "SSA call def(" + this.getSourceVariable() + ")" + result = SsaImpl::getToStringPrefix(this) + "SSA call def(" + this.getSourceVariable() + ")" } override Location getLocation() { result = this.getCall().getLocation() } @@ -640,7 +625,8 @@ module Ssa { final Definition getQualifierDefinition() { result = q } override string toString() { - result = getToStringPrefix(this) + "SSA qualifier def(" + this.getSourceVariable() + ")" + result = + SsaImpl::getToStringPrefix(this) + "SSA qualifier def(" + this.getSourceVariable() + ")" } override Location getLocation() { result = this.getQualifierDefinition().getLocation() } @@ -682,7 +668,7 @@ module Ssa { } override string toString() { - result = getToStringPrefix(this) + "SSA phi(" + this.getSourceVariable() + ")" + result = SsaImpl::getToStringPrefix(this) + "SSA phi(" + this.getSourceVariable() + ")" } /* diff --git a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/SsaImpl.qll b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/SsaImpl.qll index adfacd2970a0..98a1cad843a0 100644 --- a/csharp/ql/lib/semmle/code/csharp/dataflow/internal/SsaImpl.qll +++ b/csharp/ql/lib/semmle/code/csharp/dataflow/internal/SsaImpl.qll @@ -49,7 +49,23 @@ private module SsaInput implements SsaImplCommon::InputSig { } } -import SsaImplCommon::Make +private import SsaImplCommon::Make as Impl + +class Definition = Impl::Definition; + +class WriteDefinition = Impl::WriteDefinition; + +class UncertainWriteDefinition = Impl::UncertainWriteDefinition; + +class PhiNode = Impl::PhiNode; + +module Consistency = Impl::Consistency; + +module ExposedForTestingOnly { + predicate ssaDefReachesReadExt = Impl::ssaDefReachesReadExt/4; + + predicate phiHasInputFromBlockExt = Impl::phiHasInputFromBlockExt/3; +} /** * Holds if the `i`th node of basic block `bb` reads source variable `v`. @@ -1072,7 +1088,7 @@ private predicate adjacentDefRead( Definition def, SsaInput::BasicBlock bb1, int i1, SsaInput::BasicBlock bb2, int i2, SsaInput::SourceVariable v ) { - adjacentDefRead(def, bb1, i1, bb2, i2) and + Impl::adjacentDefRead(def, bb1, i1, bb2, i2) and v = def.getSourceVariable() } @@ -1088,7 +1104,7 @@ private predicate adjacentDefReachesRead( exists(SsaInput::BasicBlock bb3, int i3 | adjacentDefReachesRead(def, bb1, i1, bb3, i3) and SsaInput::variableRead(bb3, i3, _, false) and - adjacentDefRead(def, bb3, i3, bb2, i2) + Impl::adjacentDefRead(def, bb3, i3, bb2, i2) ) } @@ -1111,11 +1127,11 @@ private predicate adjacentDefReachesUncertainRead( /** Same as `lastRefRedef`, but skips uncertain reads. */ pragma[nomagic] private predicate lastRefSkipUncertainReads(Definition def, SsaInput::BasicBlock bb, int i) { - lastRef(def, bb, i) and + Impl::lastRef(def, bb, i) and not SsaInput::variableRead(bb, i, def.getSourceVariable(), false) or exists(SsaInput::BasicBlock bb0, int i0 | - lastRef(def, bb0, i0) and + Impl::lastRef(def, bb0, i0) and adjacentDefReachesUncertainRead(def, bb, i, bb0, i0) ) } @@ -1237,7 +1253,7 @@ private module Cached { v = def.getSourceVariable() and capturedReadIn(_, _, v, edef.getSourceVariable(), c, additionalCalls) and def = def0.getAnUltimateDefinition() and - ssaDefReachesRead(_, def0, bb, i) and + Impl::ssaDefReachesRead(_, def0, bb, i) and capturedReadIn(bb, i, v, _, _, _) and c = bb.getNode(i) ) @@ -1264,18 +1280,18 @@ private module Cached { cached predicate isLiveAtEndOfBlock(Definition def, ControlFlow::BasicBlock bb) { - ssaDefReachesEndOfBlock(bb, def, _) + Impl::ssaDefReachesEndOfBlock(bb, def, _) } cached - Definition phiHasInputFromBlock(PhiNode phi, ControlFlow::BasicBlock bb) { - phiHasInputFromBlock(phi, result, bb) + Definition phiHasInputFromBlock(Ssa::PhiNode phi, ControlFlow::BasicBlock bb) { + Impl::phiHasInputFromBlock(phi, result, bb) } cached AssignableRead getAReadAtNode(Definition def, ControlFlow::Node cfn) { exists(Ssa::SourceVariable v, ControlFlow::BasicBlock bb, int i | - ssaDefReachesRead(v, def, bb, i) and + Impl::ssaDefReachesRead(v, def, bb, i) and variableReadActual(bb, i, v) and cfn = bb.getNode(i) and result.getAControlFlowNode() = cfn @@ -1313,11 +1329,11 @@ private module Cached { /** Same as `lastRefRedef`, but skips uncertain reads. */ cached predicate lastRefBeforeRedef(Definition def, ControlFlow::BasicBlock bb, int i, Definition next) { - lastRefRedef(def, bb, i, next) and + Impl::lastRefRedef(def, bb, i, next) and not SsaInput::variableRead(bb, i, def.getSourceVariable(), false) or exists(SsaInput::BasicBlock bb0, int i0 | - lastRefRedef(def, bb0, i0, next) and + Impl::lastRefRedef(def, bb0, i0, next) and adjacentDefReachesUncertainRead(def, bb, i, bb0, i0) ) } @@ -1333,7 +1349,7 @@ private module Cached { cached Definition uncertainWriteDefinitionInput(UncertainWriteDefinition def) { - uncertainWriteDefinitionInput(def, result) + Impl::uncertainWriteDefinitionInput(def, result) } cached @@ -1343,10 +1359,57 @@ private module Cached { v = def.getSourceVariable() and p = v.getAssignable() and def = def0.getAnUltimateDefinition() and - ssaDefReachesRead(_, def0, bb, i) and + Impl::ssaDefReachesRead(_, def0, bb, i) and outRefExitRead(bb, i, v) ) } } import Cached + +private string getSplitString(DefinitionExt def) { + exists(ControlFlow::BasicBlock bb, int i, ControlFlow::Node cfn | + def.definesAt(_, bb, i, _) and + result = cfn.(ControlFlow::Nodes::ElementNode).getSplitsString() + | + cfn = bb.getNode(i) + or + not exists(bb.getNode(i)) and + cfn = bb.getFirstNode() + ) +} + +string getToStringPrefix(DefinitionExt def) { + result = "[" + getSplitString(def) + "] " + or + not exists(getSplitString(def)) and + result = "" +} + +/** + * An extended static single assignment (SSA) definition. + * + * This is either a normal SSA definition (`Definition`) or a + * phi-read node (`PhiReadNode`). + * + * Only intended for internal use. + */ +class DefinitionExt extends Impl::DefinitionExt { + override string toString() { result = this.(Ssa::Definition).toString() } + + /** Gets the location of this definition. */ + Location getLocation() { result = this.(Ssa::Definition).getLocation() } +} + +/** + * A phi-read node. + * + * Only intended for internal use. + */ +class PhiReadNode extends DefinitionExt, Impl::PhiReadNode { + override string toString() { + result = getToStringPrefix(this) + "SSA phi read(" + this.getSourceVariable() + ")" + } + + override Location getLocation() { result = this.getBasicBlock().getLocation() } +} diff --git a/csharp/ql/test/library-tests/dataflow/ssa/SSAPhiRead.expected b/csharp/ql/test/library-tests/dataflow/ssa/SSAPhiRead.expected index 19c394b58fd1..970e6fce5244 100644 --- a/csharp/ql/test/library-tests/dataflow/ssa/SSAPhiRead.expected +++ b/csharp/ql/test/library-tests/dataflow/ssa/SSAPhiRead.expected @@ -1,4 +1,30 @@ -| DefUse.cs:63:9:63:14 | this.Field2 | DefUse.cs:80:30:80:31 | access to local variable x1 | -| Fields.cs:65:24:65:32 | this.LoopField | Fields.cs:63:16:63:28 | this access | -| Properties.cs:65:24:65:31 | this.LoopProp | Properties.cs:63:16:63:16 | access to parameter i | -| Test.cs:78:13:78:13 | x | Test.cs:90:9:97:9 | if (...) ... | +phiReadNode +| DefUse.cs:80:30:80:31 | SSA phi read(this.Field2) | DefUse.cs:63:9:63:14 | this.Field2 | +| Fields.cs:63:16:63:28 | SSA phi read(this.LoopField) | Fields.cs:65:24:65:32 | this.LoopField | +| Patterns.cs:20:9:38:9 | SSA phi read(o) | Patterns.cs:7:16:7:16 | o | +| Properties.cs:63:16:63:16 | SSA phi read(this.LoopProp) | Properties.cs:65:24:65:31 | this.LoopProp | +| Test.cs:25:16:25:16 | SSA phi read(x) | Test.cs:8:13:8:13 | x | +| Test.cs:90:9:97:9 | SSA phi read(x) | Test.cs:78:13:78:13 | x | +| Test.cs:99:9:99:15 | SSA phi read(x) | Test.cs:78:13:78:13 | x | +phiReadNodeRead +| DefUse.cs:80:30:80:31 | SSA phi read(this.Field2) | DefUse.cs:63:9:63:14 | this.Field2 | DefUse.cs:80:37:80:42 | access to field Field2 | +| Fields.cs:63:16:63:28 | SSA phi read(this.LoopField) | Fields.cs:65:24:65:32 | this.LoopField | Fields.cs:65:24:65:32 | access to field LoopField | +| Patterns.cs:20:9:38:9 | SSA phi read(o) | Patterns.cs:7:16:7:16 | o | Patterns.cs:20:17:20:17 | access to local variable o | +| Properties.cs:63:16:63:16 | SSA phi read(this.LoopProp) | Properties.cs:65:24:65:31 | this.LoopProp | Properties.cs:65:24:65:31 | access to property LoopProp | +| Test.cs:25:16:25:16 | SSA phi read(x) | Test.cs:8:13:8:13 | x | Test.cs:25:16:25:16 | access to local variable x | +| Test.cs:90:9:97:9 | SSA phi read(x) | Test.cs:78:13:78:13 | x | Test.cs:92:17:92:17 | access to local variable x | +| Test.cs:90:9:97:9 | SSA phi read(x) | Test.cs:78:13:78:13 | x | Test.cs:96:17:96:17 | access to local variable x | +| Test.cs:99:9:99:15 | SSA phi read(x) | Test.cs:78:13:78:13 | x | Test.cs:99:13:99:13 | access to local variable x | +| Test.cs:99:9:99:15 | SSA phi read(x) | Test.cs:78:13:78:13 | x | Test.cs:104:17:104:17 | access to local variable x | +phiReadInput +| DefUse.cs:80:30:80:31 | SSA phi read(this.Field2) | DefUse.cs:63:9:63:18 | SSA def(this.Field2) | +| DefUse.cs:80:30:80:31 | SSA phi read(this.Field2) | DefUse.cs:80:30:80:31 | SSA phi read(this.Field2) | +| Fields.cs:63:16:63:28 | SSA phi read(this.LoopField) | Fields.cs:61:17:61:17 | SSA entry def(this.LoopField) | +| Fields.cs:63:16:63:28 | SSA phi read(this.LoopField) | Fields.cs:63:16:63:28 | SSA phi read(this.LoopField) | +| Patterns.cs:20:9:38:9 | SSA phi read(o) | Patterns.cs:7:16:7:23 | SSA def(o) | +| Properties.cs:63:16:63:16 | SSA phi read(this.LoopProp) | Properties.cs:61:17:61:17 | SSA entry def(this.LoopProp) | +| Properties.cs:63:16:63:16 | SSA phi read(this.LoopProp) | Properties.cs:63:16:63:16 | SSA phi read(this.LoopProp) | +| Test.cs:25:16:25:16 | SSA phi read(x) | Test.cs:24:9:24:15 | SSA phi(x) | +| Test.cs:25:16:25:16 | SSA phi read(x) | Test.cs:25:16:25:16 | SSA phi read(x) | +| Test.cs:90:9:97:9 | SSA phi read(x) | Test.cs:78:13:78:17 | SSA def(x) | +| Test.cs:99:9:99:15 | SSA phi read(x) | Test.cs:90:9:97:9 | SSA phi read(x) | diff --git a/csharp/ql/test/library-tests/dataflow/ssa/SSAPhiRead.ql b/csharp/ql/test/library-tests/dataflow/ssa/SSAPhiRead.ql index f9603dc1da2f..8fee62217bf4 100644 --- a/csharp/ql/test/library-tests/dataflow/ssa/SSAPhiRead.ql +++ b/csharp/ql/test/library-tests/dataflow/ssa/SSAPhiRead.ql @@ -1,6 +1,17 @@ import csharp import semmle.code.csharp.dataflow.internal.SsaImpl +import ExposedForTestingOnly -from Ssa::SourceVariable v, ControlFlow::BasicBlock bb -where phiReadExposedForTesting(bb, v) -select v, bb +query predicate phiReadNode(PhiReadNode phi, Ssa::SourceVariable v) { phi.getSourceVariable() = v } + +query predicate phiReadNodeRead(PhiReadNode phi, Ssa::SourceVariable v, ControlFlow::Node read) { + phi.getSourceVariable() = v and + exists(ControlFlow::BasicBlock bb, int i | + ssaDefReachesReadExt(v, phi, bb, i) and + read = bb.getNode(i) + ) +} + +query predicate phiReadInput(PhiReadNode phi, DefinitionExt inp) { + phiHasInputFromBlockExt(phi, inp, _) +} diff --git a/csharp/ql/test/library-tests/dataflow/ssa/Test.cs b/csharp/ql/test/library-tests/dataflow/ssa/Test.cs index 5d321d0117d0..23fee7d47062 100644 --- a/csharp/ql/test/library-tests/dataflow/ssa/Test.cs +++ b/csharp/ql/test/library-tests/dataflow/ssa/Test.cs @@ -95,7 +95,7 @@ void phiReads(bool b1, bool b2, bool b3, bool b4, bool b5, bool b6) { use(x); } - // no phi_use for `x`, because actual use exists in the block + // phi_use for `x`, even though there is an actual use in the block use(x); From 67f31ffdf06e30fcf29caff37062a45f9266ede6 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Thu, 10 Nov 2022 14:28:35 +0100 Subject: [PATCH 4/5] Ruby: Add tests for phi reads --- ruby/ql/consistency-queries/SsaConsistency.ql | 11 ++- .../codeql/ruby/dataflow/internal/SsaImpl.qll | 67 +++++++++++++--- .../variables/parameter.expected | 4 + .../test/library-tests/variables/ssa.expected | 77 +++++++++++++++++++ ruby/ql/test/library-tests/variables/ssa.ql | 16 ++++ ruby/ql/test/library-tests/variables/ssa.rb | 15 ++++ .../variables/varaccess.expected | 34 ++++++++ .../library-tests/variables/variable.expected | 8 +- .../variables/varscopes.expected | 3 +- 9 files changed, 220 insertions(+), 15 deletions(-) diff --git a/ruby/ql/consistency-queries/SsaConsistency.ql b/ruby/ql/consistency-queries/SsaConsistency.ql index 7ba9262baa4c..30503e6aa1fb 100644 --- a/ruby/ql/consistency-queries/SsaConsistency.ql +++ b/ruby/ql/consistency-queries/SsaConsistency.ql @@ -1,5 +1,6 @@ import codeql.ruby.dataflow.SSA -import codeql.ruby.dataflow.internal.SsaImpl::Consistency +import codeql.ruby.dataflow.internal.SsaImpl +import Consistency class MyRelevantDefinition extends RelevantDefinition, Ssa::Definition { override predicate hasLocationInfo( @@ -8,3 +9,11 @@ class MyRelevantDefinition extends RelevantDefinition, Ssa::Definition { this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) } } + +class MyRelevantDefinitionExt extends RelevantDefinitionExt, DefinitionExt { + override predicate hasLocationInfo( + string filepath, int startline, int startcolumn, int endline, int endcolumn + ) { + this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn) + } +} diff --git a/ruby/ql/lib/codeql/ruby/dataflow/internal/SsaImpl.qll b/ruby/ql/lib/codeql/ruby/dataflow/internal/SsaImpl.qll index c7154b50d0fa..2f3b1e085b09 100644 --- a/ruby/ql/lib/codeql/ruby/dataflow/internal/SsaImpl.qll +++ b/ruby/ql/lib/codeql/ruby/dataflow/internal/SsaImpl.qll @@ -2,6 +2,7 @@ private import codeql.ssa.Ssa as SsaImplCommon private import codeql.ruby.AST private import codeql.ruby.CFG as Cfg private import codeql.ruby.controlflow.internal.ControlFlowGraphImplShared as ControlFlowGraphImplShared +private import codeql.ruby.dataflow.SSA private import codeql.ruby.ast.Variable private import Cfg::CfgNodes::ExprNodes @@ -61,7 +62,23 @@ private module SsaInput implements SsaImplCommon::InputSig { } } -import SsaImplCommon::Make +private import SsaImplCommon::Make as Impl + +class Definition = Impl::Definition; + +class WriteDefinition = Impl::WriteDefinition; + +class UncertainWriteDefinition = Impl::UncertainWriteDefinition; + +class PhiNode = Impl::PhiNode; + +module Consistency = Impl::Consistency; + +module ExposedForTestingOnly { + predicate ssaDefReachesReadExt = Impl::ssaDefReachesReadExt/4; + + predicate phiHasInputFromBlockExt = Impl::phiHasInputFromBlockExt/3; +} /** Holds if `v` is uninitialized at index `i` in entry block `bb`. */ predicate uninitializedWrite(Cfg::EntryBasicBlock bb, int i, LocalVariable v) { @@ -204,7 +221,7 @@ private predicate adjacentDefRead( Definition def, SsaInput::BasicBlock bb1, int i1, SsaInput::BasicBlock bb2, int i2, SsaInput::SourceVariable v ) { - adjacentDefRead(def, bb1, i1, bb2, i2) and + Impl::adjacentDefRead(def, bb1, i1, bb2, i2) and v = def.getSourceVariable() } @@ -220,7 +237,7 @@ private predicate adjacentDefReachesRead( exists(SsaInput::BasicBlock bb3, int i3 | adjacentDefReachesRead(def, bb1, i1, bb3, i3) and SsaInput::variableRead(bb3, i3, _, false) and - adjacentDefRead(def, bb3, i3, bb2, i2) + Impl::adjacentDefRead(def, bb3, i3, bb2, i2) ) } @@ -243,11 +260,11 @@ private predicate adjacentDefReachesUncertainRead( /** Same as `lastRefRedef`, but skips uncertain reads. */ pragma[nomagic] private predicate lastRefSkipUncertainReads(Definition def, SsaInput::BasicBlock bb, int i) { - lastRef(def, bb, i) and + Impl::lastRef(def, bb, i) and not SsaInput::variableRead(bb, i, def.getSourceVariable(), false) or exists(SsaInput::BasicBlock bb0, int i0 | - lastRef(def, bb0, i0) and + Impl::lastRef(def, bb0, i0) and adjacentDefReachesUncertainRead(def, bb, i, bb0, i0) ) } @@ -304,7 +321,7 @@ private module Cached { cached VariableReadAccessCfgNode getARead(Definition def) { exists(LocalVariable v, Cfg::BasicBlock bb, int i | - ssaDefReachesRead(v, def, bb, i) and + Impl::ssaDefReachesRead(v, def, bb, i) and variableReadActual(bb, i, v) and result = bb.getNode(i) ) @@ -315,7 +332,7 @@ private module Cached { Definition def, CallCfgNode call, LocalVariable v, Cfg::CfgScope scope ) { exists(Cfg::BasicBlock bb, int i | - ssaDefReachesRead(v, def, bb, i) and + Impl::ssaDefReachesRead(v, def, bb, i) and capturedCallRead(call, bb, i, v) and scope.getOuterCfgScope() = bb.getScope() ) @@ -360,7 +377,7 @@ private module Cached { Definition def, LocalVariable v, Cfg::CfgScope scope ) { exists(Cfg::BasicBlock bb, int i | - ssaDefReachesRead(v, def, bb, i) and + Impl::ssaDefReachesRead(v, def, bb, i) and capturedExitRead(bb, i, v) and scope = bb.getScope().getOuterCfgScope*() ) @@ -403,7 +420,7 @@ private module Cached { cached Definition phiHasInputFromBlock(PhiNode phi, Cfg::BasicBlock bb) { - phiHasInputFromBlock(phi, result, bb) + Impl::phiHasInputFromBlock(phi, result, bb) } /** @@ -459,19 +476,45 @@ private module Cached { */ cached predicate lastRefBeforeRedef(Definition def, Cfg::BasicBlock bb, int i, Definition next) { - lastRefRedef(def, bb, i, next) and + Impl::lastRefRedef(def, bb, i, next) and not SsaInput::variableRead(bb, i, def.getSourceVariable(), false) or exists(SsaInput::BasicBlock bb0, int i0 | - lastRefRedef(def, bb0, i0, next) and + Impl::lastRefRedef(def, bb0, i0, next) and adjacentDefReachesUncertainRead(def, bb, i, bb0, i0) ) } cached Definition uncertainWriteDefinitionInput(UncertainWriteDefinition def) { - uncertainWriteDefinitionInput(def, result) + Impl::uncertainWriteDefinitionInput(def, result) } } import Cached + +/** + * An extended static single assignment (SSA) definition. + * + * This is either a normal SSA definition (`Definition`) or a + * phi-read node (`PhiReadNode`). + * + * Only intended for internal use. + */ +class DefinitionExt extends Impl::DefinitionExt { + override string toString() { result = this.(Ssa::Definition).toString() } + + /** Gets the location of this definition. */ + Location getLocation() { result = this.(Ssa::Definition).getLocation() } +} + +/** + * A phi-read node. + * + * Only intended for internal use. + */ +class PhiReadNode extends DefinitionExt, Impl::PhiReadNode { + override string toString() { result = "SSA phi read(" + this.getSourceVariable() + ")" } + + override Location getLocation() { result = this.getBasicBlock().getLocation() } +} diff --git a/ruby/ql/test/library-tests/variables/parameter.expected b/ruby/ql/test/library-tests/variables/parameter.expected index 292ae6659640..6e6c8426f865 100644 --- a/ruby/ql/test/library-tests/variables/parameter.expected +++ b/ruby/ql/test/library-tests/variables/parameter.expected @@ -38,6 +38,10 @@ parameterVariable | ssa.rb:53:8:53:10 | foo | ssa.rb:53:8:53:10 | foo | | ssa.rb:64:8:64:8 | a | ssa.rb:64:8:64:8 | a | | ssa.rb:66:15:66:15 | a | ssa.rb:66:15:66:15 | a | +| ssa.rb:90:9:90:10 | b1 | ssa.rb:90:9:90:10 | b1 | +| ssa.rb:90:13:90:14 | b2 | ssa.rb:90:13:90:14 | b2 | +| ssa.rb:90:17:90:18 | b3 | ssa.rb:90:17:90:18 | b3 | +| ssa.rb:90:21:90:22 | b4 | ssa.rb:90:21:90:22 | b4 | parameterNoVariable | parameters.rb:45:22:45:22 | _ | parameterVariableNoAccess diff --git a/ruby/ql/test/library-tests/variables/ssa.expected b/ruby/ql/test/library-tests/variables/ssa.expected index e1df08d42855..20133a718574 100644 --- a/ruby/ql/test/library-tests/variables/ssa.expected +++ b/ruby/ql/test/library-tests/variables/ssa.expected @@ -164,6 +164,12 @@ definition | ssa.rb:83:7:87:5 | self | ssa.rb:81:1:88:3 | self | | ssa.rb:84:10:86:8 | captured | ssa.rb:82:3:82:10 | captured | | ssa.rb:84:10:86:8 | self | ssa.rb:81:1:88:3 | self | +| ssa.rb:90:1:103:3 | self (m12) | ssa.rb:90:1:103:3 | self | +| ssa.rb:90:9:90:10 | b1 | ssa.rb:90:9:90:10 | b1 | +| ssa.rb:90:13:90:14 | b2 | ssa.rb:90:13:90:14 | b2 | +| ssa.rb:90:17:90:18 | b3 | ssa.rb:90:17:90:18 | b3 | +| ssa.rb:90:21:90:22 | b4 | ssa.rb:90:21:90:22 | b4 | +| ssa.rb:91:3:91:7 | ... = ... | ssa.rb:91:3:91:3 | x | read | class_variables.rb:1:1:29:4 | self (class_variables.rb) | class_variables.rb:1:1:29:4 | self | class_variables.rb:3:1:3:5 | self | | class_variables.rb:5:1:7:3 | self (print) | class_variables.rb:5:1:7:3 | self | class_variables.rb:6:2:6:6 | self | @@ -347,6 +353,18 @@ read | ssa.rb:83:7:87:5 | self | ssa.rb:81:1:88:3 | self | ssa.rb:84:6:86:8 | self | | ssa.rb:84:10:86:8 | captured | ssa.rb:82:3:82:10 | captured | ssa.rb:85:15:85:22 | captured | | ssa.rb:84:10:86:8 | self | ssa.rb:81:1:88:3 | self | ssa.rb:85:10:85:22 | self | +| ssa.rb:90:1:103:3 | self (m12) | ssa.rb:90:1:103:3 | self | ssa.rb:93:5:93:10 | self | +| ssa.rb:90:1:103:3 | self (m12) | ssa.rb:90:1:103:3 | self | ssa.rb:95:5:95:10 | self | +| ssa.rb:90:1:103:3 | self (m12) | ssa.rb:90:1:103:3 | self | ssa.rb:99:5:99:10 | self | +| ssa.rb:90:1:103:3 | self (m12) | ssa.rb:90:1:103:3 | self | ssa.rb:101:5:101:10 | self | +| ssa.rb:90:9:90:10 | b1 | ssa.rb:90:9:90:10 | b1 | ssa.rb:92:7:92:8 | b1 | +| ssa.rb:90:13:90:14 | b2 | ssa.rb:90:13:90:14 | b2 | ssa.rb:94:10:94:11 | b2 | +| ssa.rb:90:17:90:18 | b3 | ssa.rb:90:17:90:18 | b3 | ssa.rb:98:7:98:8 | b3 | +| ssa.rb:90:21:90:22 | b4 | ssa.rb:90:21:90:22 | b4 | ssa.rb:100:10:100:11 | b4 | +| ssa.rb:91:3:91:7 | ... = ... | ssa.rb:91:3:91:3 | x | ssa.rb:93:10:93:10 | x | +| ssa.rb:91:3:91:7 | ... = ... | ssa.rb:91:3:91:3 | x | ssa.rb:95:10:95:10 | x | +| ssa.rb:91:3:91:7 | ... = ... | ssa.rb:91:3:91:3 | x | ssa.rb:99:10:99:10 | x | +| ssa.rb:91:3:91:7 | ... = ... | ssa.rb:91:3:91:3 | x | ssa.rb:101:10:101:10 | x | firstRead | class_variables.rb:1:1:29:4 | self (class_variables.rb) | class_variables.rb:1:1:29:4 | self | class_variables.rb:3:1:3:5 | self | | class_variables.rb:5:1:7:3 | self (print) | class_variables.rb:5:1:7:3 | self | class_variables.rb:6:2:6:6 | self | @@ -485,6 +503,18 @@ firstRead | ssa.rb:83:7:87:5 | self | ssa.rb:81:1:88:3 | self | ssa.rb:84:6:86:8 | self | | ssa.rb:84:10:86:8 | captured | ssa.rb:82:3:82:10 | captured | ssa.rb:85:15:85:22 | captured | | ssa.rb:84:10:86:8 | self | ssa.rb:81:1:88:3 | self | ssa.rb:85:10:85:22 | self | +| ssa.rb:90:1:103:3 | self (m12) | ssa.rb:90:1:103:3 | self | ssa.rb:93:5:93:10 | self | +| ssa.rb:90:1:103:3 | self (m12) | ssa.rb:90:1:103:3 | self | ssa.rb:95:5:95:10 | self | +| ssa.rb:90:1:103:3 | self (m12) | ssa.rb:90:1:103:3 | self | ssa.rb:99:5:99:10 | self | +| ssa.rb:90:1:103:3 | self (m12) | ssa.rb:90:1:103:3 | self | ssa.rb:101:5:101:10 | self | +| ssa.rb:90:9:90:10 | b1 | ssa.rb:90:9:90:10 | b1 | ssa.rb:92:7:92:8 | b1 | +| ssa.rb:90:13:90:14 | b2 | ssa.rb:90:13:90:14 | b2 | ssa.rb:94:10:94:11 | b2 | +| ssa.rb:90:17:90:18 | b3 | ssa.rb:90:17:90:18 | b3 | ssa.rb:98:7:98:8 | b3 | +| ssa.rb:90:21:90:22 | b4 | ssa.rb:90:21:90:22 | b4 | ssa.rb:100:10:100:11 | b4 | +| ssa.rb:91:3:91:7 | ... = ... | ssa.rb:91:3:91:3 | x | ssa.rb:93:10:93:10 | x | +| ssa.rb:91:3:91:7 | ... = ... | ssa.rb:91:3:91:3 | x | ssa.rb:95:10:95:10 | x | +| ssa.rb:91:3:91:7 | ... = ... | ssa.rb:91:3:91:3 | x | ssa.rb:99:10:99:10 | x | +| ssa.rb:91:3:91:7 | ... = ... | ssa.rb:91:3:91:3 | x | ssa.rb:101:10:101:10 | x | lastRead | class_variables.rb:1:1:29:4 | self (class_variables.rb) | class_variables.rb:1:1:29:4 | self | class_variables.rb:3:1:3:5 | self | | class_variables.rb:5:1:7:3 | self (print) | class_variables.rb:5:1:7:3 | self | class_variables.rb:6:2:6:6 | self | @@ -624,6 +654,18 @@ lastRead | ssa.rb:83:7:87:5 | self | ssa.rb:81:1:88:3 | self | ssa.rb:84:6:86:8 | self | | ssa.rb:84:10:86:8 | captured | ssa.rb:82:3:82:10 | captured | ssa.rb:85:15:85:22 | captured | | ssa.rb:84:10:86:8 | self | ssa.rb:81:1:88:3 | self | ssa.rb:85:10:85:22 | self | +| ssa.rb:90:1:103:3 | self (m12) | ssa.rb:90:1:103:3 | self | ssa.rb:93:5:93:10 | self | +| ssa.rb:90:1:103:3 | self (m12) | ssa.rb:90:1:103:3 | self | ssa.rb:95:5:95:10 | self | +| ssa.rb:90:1:103:3 | self (m12) | ssa.rb:90:1:103:3 | self | ssa.rb:99:5:99:10 | self | +| ssa.rb:90:1:103:3 | self (m12) | ssa.rb:90:1:103:3 | self | ssa.rb:101:5:101:10 | self | +| ssa.rb:90:9:90:10 | b1 | ssa.rb:90:9:90:10 | b1 | ssa.rb:92:7:92:8 | b1 | +| ssa.rb:90:13:90:14 | b2 | ssa.rb:90:13:90:14 | b2 | ssa.rb:94:10:94:11 | b2 | +| ssa.rb:90:17:90:18 | b3 | ssa.rb:90:17:90:18 | b3 | ssa.rb:98:7:98:8 | b3 | +| ssa.rb:90:21:90:22 | b4 | ssa.rb:90:21:90:22 | b4 | ssa.rb:100:10:100:11 | b4 | +| ssa.rb:91:3:91:7 | ... = ... | ssa.rb:91:3:91:3 | x | ssa.rb:93:10:93:10 | x | +| ssa.rb:91:3:91:7 | ... = ... | ssa.rb:91:3:91:3 | x | ssa.rb:95:10:95:10 | x | +| ssa.rb:91:3:91:7 | ... = ... | ssa.rb:91:3:91:3 | x | ssa.rb:99:10:99:10 | x | +| ssa.rb:91:3:91:7 | ... = ... | ssa.rb:91:3:91:3 | x | ssa.rb:101:10:101:10 | x | adjacentReads | class_variables.rb:26:1:29:3 | self (N) | class_variables.rb:26:1:29:3 | self | class_variables.rb:27:3:27:11 | self | class_variables.rb:28:3:28:7 | self | | instance_variables.rb:1:1:44:4 | self (instance_variables.rb) | instance_variables.rb:1:1:44:4 | self | instance_variables.rb:1:1:1:4 | self | instance_variables.rb:11:1:11:9 | self | @@ -674,6 +716,14 @@ adjacentReads | ssa.rb:38:1:42:3 | self (m4) | ssa.rb:38:1:42:3 | self | ssa.rb:39:8:39:9 | self | ssa.rb:41:3:41:13 | self | | ssa.rb:66:11:70:5 | captured | ssa.rb:65:3:65:10 | captured | ssa.rb:68:10:68:17 | captured | ssa.rb:69:5:69:12 | captured | | ssa.rb:66:11:70:5 | self | ssa.rb:64:1:72:3 | self | ssa.rb:67:5:67:10 | self | ssa.rb:68:5:68:17 | self | +| ssa.rb:90:1:103:3 | self (m12) | ssa.rb:90:1:103:3 | self | ssa.rb:93:5:93:10 | self | ssa.rb:99:5:99:10 | self | +| ssa.rb:90:1:103:3 | self (m12) | ssa.rb:90:1:103:3 | self | ssa.rb:93:5:93:10 | self | ssa.rb:101:5:101:10 | self | +| ssa.rb:90:1:103:3 | self (m12) | ssa.rb:90:1:103:3 | self | ssa.rb:95:5:95:10 | self | ssa.rb:99:5:99:10 | self | +| ssa.rb:90:1:103:3 | self (m12) | ssa.rb:90:1:103:3 | self | ssa.rb:95:5:95:10 | self | ssa.rb:101:5:101:10 | self | +| ssa.rb:91:3:91:7 | ... = ... | ssa.rb:91:3:91:3 | x | ssa.rb:93:10:93:10 | x | ssa.rb:99:10:99:10 | x | +| ssa.rb:91:3:91:7 | ... = ... | ssa.rb:91:3:91:3 | x | ssa.rb:93:10:93:10 | x | ssa.rb:101:10:101:10 | x | +| ssa.rb:91:3:91:7 | ... = ... | ssa.rb:91:3:91:3 | x | ssa.rb:95:10:95:10 | x | ssa.rb:99:10:99:10 | x | +| ssa.rb:91:3:91:7 | ... = ... | ssa.rb:91:3:91:3 | x | ssa.rb:95:10:95:10 | x | ssa.rb:101:10:101:10 | x | phi | parameters.rb:37:3:37:18 | phi | parameters.rb:35:16:35:16 | b | parameters.rb:35:1:38:3 | | | parameters.rb:37:3:37:18 | phi | parameters.rb:35:16:35:16 | b | parameters.rb:35:16:35:20 | ... = ... | @@ -689,3 +739,30 @@ phi | ssa.rb:45:3:45:12 | phi | ssa.rb:45:3:45:3 | x | ssa.rb:45:3:45:7 | ... = ... | | ssa.rb:50:3:50:8 | phi | ssa.rb:49:14:49:14 | y | ssa.rb:49:1:51:3 | | | ssa.rb:50:3:50:8 | phi | ssa.rb:49:14:49:14 | y | ssa.rb:49:14:49:19 | ... = ... | +phiReadNode +| parameters.rb:26:3:26:11 | SSA phi read(name) | parameters.rb:25:15:25:18 | name | +| ssa.rb:5:3:13:5 | SSA phi read(self) | ssa.rb:1:1:16:3 | self | +| ssa.rb:19:9:19:9 | SSA phi read(self) | ssa.rb:18:1:23:3 | self | +| ssa.rb:92:3:96:5 | SSA phi read(self) | ssa.rb:90:1:103:3 | self | +| ssa.rb:92:3:96:5 | SSA phi read(x) | ssa.rb:91:3:91:3 | x | +| ssa.rb:94:3:95:10 | SSA phi read(self) | ssa.rb:90:1:103:3 | self | +| ssa.rb:94:3:95:10 | SSA phi read(x) | ssa.rb:91:3:91:3 | x | +phiReadNodeRead +| parameters.rb:26:3:26:11 | SSA phi read(name) | parameters.rb:25:15:25:18 | name | parameters.rb:26:8:26:11 | name | +| ssa.rb:5:3:13:5 | SSA phi read(self) | ssa.rb:1:1:16:3 | self | ssa.rb:15:3:15:8 | self | +| ssa.rb:19:9:19:9 | SSA phi read(self) | ssa.rb:18:1:23:3 | self | ssa.rb:20:5:20:10 | self | +| ssa.rb:92:3:96:5 | SSA phi read(self) | ssa.rb:90:1:103:3 | self | ssa.rb:99:5:99:10 | self | +| ssa.rb:92:3:96:5 | SSA phi read(self) | ssa.rb:90:1:103:3 | self | ssa.rb:101:5:101:10 | self | +| ssa.rb:92:3:96:5 | SSA phi read(x) | ssa.rb:91:3:91:3 | x | ssa.rb:99:10:99:10 | x | +| ssa.rb:92:3:96:5 | SSA phi read(x) | ssa.rb:91:3:91:3 | x | ssa.rb:101:10:101:10 | x | +phiReadInput +| parameters.rb:26:3:26:11 | SSA phi read(name) | parameters.rb:25:15:25:18 | name | +| ssa.rb:5:3:13:5 | SSA phi read(self) | ssa.rb:1:1:16:3 | self (m) | +| ssa.rb:19:9:19:9 | SSA phi read(self) | ssa.rb:18:1:23:3 | self (m1) | +| ssa.rb:19:9:19:9 | SSA phi read(self) | ssa.rb:19:9:19:9 | SSA phi read(self) | +| ssa.rb:92:3:96:5 | SSA phi read(self) | ssa.rb:90:1:103:3 | self (m12) | +| ssa.rb:92:3:96:5 | SSA phi read(self) | ssa.rb:94:3:95:10 | SSA phi read(self) | +| ssa.rb:92:3:96:5 | SSA phi read(x) | ssa.rb:91:3:91:7 | ... = ... | +| ssa.rb:92:3:96:5 | SSA phi read(x) | ssa.rb:94:3:95:10 | SSA phi read(x) | +| ssa.rb:94:3:95:10 | SSA phi read(self) | ssa.rb:90:1:103:3 | self (m12) | +| ssa.rb:94:3:95:10 | SSA phi read(x) | ssa.rb:91:3:91:7 | ... = ... | diff --git a/ruby/ql/test/library-tests/variables/ssa.ql b/ruby/ql/test/library-tests/variables/ssa.ql index 26f3d5f8c0dc..b7a8378e8ff0 100644 --- a/ruby/ql/test/library-tests/variables/ssa.ql +++ b/ruby/ql/test/library-tests/variables/ssa.ql @@ -1,6 +1,8 @@ import codeql.ruby.AST import codeql.ruby.CFG import codeql.ruby.dataflow.SSA +import codeql.ruby.dataflow.internal.SsaImpl +import ExposedForTestingOnly query predicate definition(Ssa::Definition def, Variable v) { def.getSourceVariable() = v } @@ -24,3 +26,17 @@ query predicate adjacentReads(Ssa::Definition def, Variable v, CfgNode read1, Cf query predicate phi(Ssa::PhiNode phi, Variable v, Ssa::Definition input) { phi.getSourceVariable() = v and input = phi.getAnInput() } + +query predicate phiReadNode(PhiReadNode phi, Variable v) { phi.getSourceVariable() = v } + +query predicate phiReadNodeRead(PhiReadNode phi, Variable v, CfgNode read) { + phi.getSourceVariable() = v and + exists(BasicBlock bb, int i | + ssaDefReachesReadExt(v, phi, bb, i) and + read = bb.getNode(i) + ) +} + +query predicate phiReadInput(PhiReadNode phi, DefinitionExt inp) { + phiHasInputFromBlockExt(phi, inp, _) +} diff --git a/ruby/ql/test/library-tests/variables/ssa.rb b/ruby/ql/test/library-tests/variables/ssa.rb index bb13dd6c4c98..c8a28e39f070 100644 --- a/ruby/ql/test/library-tests/variables/ssa.rb +++ b/ruby/ql/test/library-tests/variables/ssa.rb @@ -85,4 +85,19 @@ def m11 puts captured end end +end + +def m12(b1, b2, b3, b4) + x = 0 + if (b1) then + puts x + elsif (b2) then + puts x + end + # phi read for x + if (b3) then + puts x + elsif (b4) then + puts x + end end \ No newline at end of file diff --git a/ruby/ql/test/library-tests/variables/varaccess.expected b/ruby/ql/test/library-tests/variables/varaccess.expected index 59a5ee362f62..4443373e8c2c 100644 --- a/ruby/ql/test/library-tests/variables/varaccess.expected +++ b/ruby/ql/test/library-tests/variables/varaccess.expected @@ -279,6 +279,23 @@ variableAccess | ssa.rb:84:6:86:8 | self | ssa.rb:81:1:88:3 | self | ssa.rb:81:1:88:3 | m11 | | ssa.rb:85:10:85:22 | self | ssa.rb:81:1:88:3 | self | ssa.rb:81:1:88:3 | m11 | | ssa.rb:85:15:85:22 | captured | ssa.rb:82:3:82:10 | captured | ssa.rb:81:1:88:3 | m11 | +| ssa.rb:90:9:90:10 | b1 | ssa.rb:90:9:90:10 | b1 | ssa.rb:90:1:103:3 | m12 | +| ssa.rb:90:13:90:14 | b2 | ssa.rb:90:13:90:14 | b2 | ssa.rb:90:1:103:3 | m12 | +| ssa.rb:90:17:90:18 | b3 | ssa.rb:90:17:90:18 | b3 | ssa.rb:90:1:103:3 | m12 | +| ssa.rb:90:21:90:22 | b4 | ssa.rb:90:21:90:22 | b4 | ssa.rb:90:1:103:3 | m12 | +| ssa.rb:91:3:91:3 | x | ssa.rb:91:3:91:3 | x | ssa.rb:90:1:103:3 | m12 | +| ssa.rb:92:7:92:8 | b1 | ssa.rb:90:9:90:10 | b1 | ssa.rb:90:1:103:3 | m12 | +| ssa.rb:93:5:93:10 | self | ssa.rb:90:1:103:3 | self | ssa.rb:90:1:103:3 | m12 | +| ssa.rb:93:10:93:10 | x | ssa.rb:91:3:91:3 | x | ssa.rb:90:1:103:3 | m12 | +| ssa.rb:94:10:94:11 | b2 | ssa.rb:90:13:90:14 | b2 | ssa.rb:90:1:103:3 | m12 | +| ssa.rb:95:5:95:10 | self | ssa.rb:90:1:103:3 | self | ssa.rb:90:1:103:3 | m12 | +| ssa.rb:95:10:95:10 | x | ssa.rb:91:3:91:3 | x | ssa.rb:90:1:103:3 | m12 | +| ssa.rb:98:7:98:8 | b3 | ssa.rb:90:17:90:18 | b3 | ssa.rb:90:1:103:3 | m12 | +| ssa.rb:99:5:99:10 | self | ssa.rb:90:1:103:3 | self | ssa.rb:90:1:103:3 | m12 | +| ssa.rb:99:10:99:10 | x | ssa.rb:91:3:91:3 | x | ssa.rb:90:1:103:3 | m12 | +| ssa.rb:100:10:100:11 | b4 | ssa.rb:90:21:90:22 | b4 | ssa.rb:90:1:103:3 | m12 | +| ssa.rb:101:5:101:10 | self | ssa.rb:90:1:103:3 | self | ssa.rb:90:1:103:3 | m12 | +| ssa.rb:101:10:101:10 | x | ssa.rb:91:3:91:3 | x | ssa.rb:90:1:103:3 | m12 | explicitWrite | class_variables.rb:1:1:1:3 | @@x | class_variables.rb:1:1:1:8 | ... = ... | | class_variables.rb:19:3:19:5 | @@x | class_variables.rb:19:3:19:10 | ... = ... | @@ -349,6 +366,7 @@ explicitWrite | ssa.rb:69:5:69:12 | captured | ssa.rb:69:5:69:17 | ... = ... | | ssa.rb:75:3:75:10 | captured | ssa.rb:75:3:75:14 | ... = ... | | ssa.rb:82:3:82:10 | captured | ssa.rb:82:3:82:14 | ... = ... | +| ssa.rb:91:3:91:3 | x | ssa.rb:91:3:91:7 | ... = ... | implicitWrite | nested_scopes.rb:15:23:15:23 | a | | nested_scopes.rb:16:26:16:26 | x | @@ -390,6 +408,10 @@ implicitWrite | ssa.rb:53:8:53:10 | foo | | ssa.rb:64:8:64:8 | a | | ssa.rb:66:15:66:15 | a | +| ssa.rb:90:9:90:10 | b1 | +| ssa.rb:90:13:90:14 | b2 | +| ssa.rb:90:17:90:18 | b3 | +| ssa.rb:90:21:90:22 | b4 | readAccess | class_variables.rb:3:1:3:5 | self | | class_variables.rb:3:3:3:5 | @@x | @@ -582,3 +604,15 @@ readAccess | ssa.rb:84:6:86:8 | self | | ssa.rb:85:10:85:22 | self | | ssa.rb:85:15:85:22 | captured | +| ssa.rb:92:7:92:8 | b1 | +| ssa.rb:93:5:93:10 | self | +| ssa.rb:93:10:93:10 | x | +| ssa.rb:94:10:94:11 | b2 | +| ssa.rb:95:5:95:10 | self | +| ssa.rb:95:10:95:10 | x | +| ssa.rb:98:7:98:8 | b3 | +| ssa.rb:99:5:99:10 | self | +| ssa.rb:99:10:99:10 | x | +| ssa.rb:100:10:100:11 | b4 | +| ssa.rb:101:5:101:10 | self | +| ssa.rb:101:10:101:10 | x | diff --git a/ruby/ql/test/library-tests/variables/variable.expected b/ruby/ql/test/library-tests/variables/variable.expected index 541ed3946530..ccab8a3cdf45 100644 --- a/ruby/ql/test/library-tests/variables/variable.expected +++ b/ruby/ql/test/library-tests/variables/variable.expected @@ -120,7 +120,7 @@ | scopes.rb:43:2:43:4 | foo | | scopes.rb:46:5:46:8 | var2 | | ssa.rb:1:1:16:3 | self | -| ssa.rb:1:1:88:3 | self | +| ssa.rb:1:1:103:3 | self | | ssa.rb:1:7:1:7 | b | | ssa.rb:2:3:2:3 | i | | ssa.rb:18:1:23:3 | self | @@ -152,3 +152,9 @@ | ssa.rb:75:3:75:10 | captured | | ssa.rb:81:1:88:3 | self | | ssa.rb:82:3:82:10 | captured | +| ssa.rb:90:1:103:3 | self | +| ssa.rb:90:9:90:10 | b1 | +| ssa.rb:90:13:90:14 | b2 | +| ssa.rb:90:17:90:18 | b3 | +| ssa.rb:90:21:90:22 | b4 | +| ssa.rb:91:3:91:3 | x | diff --git a/ruby/ql/test/library-tests/variables/varscopes.expected b/ruby/ql/test/library-tests/variables/varscopes.expected index 1859ab015503..6b64ca6f97d8 100644 --- a/ruby/ql/test/library-tests/variables/varscopes.expected +++ b/ruby/ql/test/library-tests/variables/varscopes.expected @@ -57,7 +57,7 @@ | scopes.rb:37:1:39:3 | foo | | scopes.rb:41:1:49:3 | M | | ssa.rb:1:1:16:3 | m | -| ssa.rb:1:1:88:3 | ssa.rb | +| ssa.rb:1:1:103:3 | ssa.rb | | ssa.rb:18:1:23:3 | m1 | | ssa.rb:25:1:30:3 | m2 | | ssa.rb:26:3:28:5 | { ... } | @@ -75,3 +75,4 @@ | ssa.rb:81:1:88:3 | m11 | | ssa.rb:83:7:87:5 | do ... end | | ssa.rb:84:10:86:8 | do ... end | +| ssa.rb:90:1:103:3 | m12 | From 67e8ec1a5fb19f353ddfd4f911a43ad68e99f296 Mon Sep 17 00:00:00 2001 From: Tom Hvitved Date: Wed, 16 Nov 2022 11:40:45 +0100 Subject: [PATCH 5/5] Swift: Update expected test output --- .../dataflow/dataflow/LocalFlow.expected | 298 +++++++++--------- 1 file changed, 149 insertions(+), 149 deletions(-) diff --git a/swift/ql/test/library-tests/dataflow/dataflow/LocalFlow.expected b/swift/ql/test/library-tests/dataflow/dataflow/LocalFlow.expected index 987d7073b87a..a4a883a2808a 100644 --- a/swift/ql/test/library-tests/dataflow/dataflow/LocalFlow.expected +++ b/swift/ql/test/library-tests/dataflow/dataflow/LocalFlow.expected @@ -1,199 +1,199 @@ -| test.swift:6:9:6:13 | WriteDef | test.swift:7:15:7:15 | t1 | -| test.swift:6:19:6:26 | call to source() | test.swift:6:9:6:13 | WriteDef | +| test.swift:6:9:6:13 | SSA def(t1) | test.swift:7:15:7:15 | t1 | +| test.swift:6:19:6:26 | call to source() | test.swift:6:9:6:13 | SSA def(t1) | | test.swift:7:15:7:15 | t1 | test.swift:8:10:8:10 | t1 | -| test.swift:8:5:8:10 | WriteDef | test.swift:10:15:10:15 | t2 | -| test.swift:8:10:8:10 | t1 | test.swift:8:5:8:10 | WriteDef | +| test.swift:8:5:8:10 | SSA def(t2) | test.swift:10:15:10:15 | t2 | +| test.swift:8:10:8:10 | t1 | test.swift:8:5:8:10 | SSA def(t2) | | test.swift:8:10:8:10 | t1 | test.swift:9:15:9:15 | t1 | | test.swift:9:15:9:15 | t1 | test.swift:11:8:11:8 | t1 | -| test.swift:12:9:12:14 | WriteDef | test.swift:13:19:13:19 | t2 | -| test.swift:12:14:12:14 | 0 | test.swift:12:9:12:14 | WriteDef | -| test.swift:15:5:15:5 | Phi | test.swift:15:15:15:15 | t2 | -| test.swift:17:5:17:10 | WriteDef | test.swift:21:15:21:15 | t1 | -| test.swift:17:10:17:10 | 0 | test.swift:17:5:17:10 | WriteDef | -| test.swift:29:18:29:21 | WriteDef | test.swift:30:15:30:15 | x | -| test.swift:29:18:29:21 | x | test.swift:29:18:29:21 | WriteDef | -| test.swift:29:26:29:29 | WriteDef | test.swift:31:15:31:15 | y | -| test.swift:29:26:29:29 | y | test.swift:29:26:29:29 | WriteDef | -| test.swift:42:16:42:19 | WriteDef | test.swift:45:8:45:8 | b | -| test.swift:42:16:42:19 | b | test.swift:42:16:42:19 | WriteDef | -| test.swift:43:9:43:13 | WriteDef | test.swift:46:13:46:13 | t1 | -| test.swift:43:19:43:26 | call to source() | test.swift:43:9:43:13 | WriteDef | -| test.swift:46:9:46:13 | WriteDef | test.swift:50:5:50:5 | Phi | -| test.swift:46:13:46:13 | t1 | test.swift:46:9:46:13 | WriteDef | -| test.swift:48:9:48:13 | WriteDef | test.swift:50:5:50:5 | Phi | -| test.swift:48:13:48:13 | 1 | test.swift:48:9:48:13 | WriteDef | -| test.swift:50:5:50:5 | Phi | test.swift:50:15:50:15 | t | -| test.swift:54:5:54:18 | WriteDef | test.swift:53:1:56:1 | arg[return] | -| test.swift:54:11:54:18 | call to source() | test.swift:54:5:54:18 | WriteDef | -| test.swift:59:9:59:12 | WriteDef | test.swift:60:15:60:15 | x | -| test.swift:59:18:59:18 | 0 | test.swift:59:9:59:12 | WriteDef | +| test.swift:12:9:12:14 | SSA def(t2) | test.swift:13:19:13:19 | t2 | +| test.swift:12:14:12:14 | 0 | test.swift:12:9:12:14 | SSA def(t2) | +| test.swift:15:5:15:5 | SSA phi(t2) | test.swift:15:15:15:15 | t2 | +| test.swift:17:5:17:10 | SSA def(t1) | test.swift:21:15:21:15 | t1 | +| test.swift:17:10:17:10 | 0 | test.swift:17:5:17:10 | SSA def(t1) | +| test.swift:29:18:29:21 | SSA def(x) | test.swift:30:15:30:15 | x | +| test.swift:29:18:29:21 | x | test.swift:29:18:29:21 | SSA def(x) | +| test.swift:29:26:29:29 | SSA def(y) | test.swift:31:15:31:15 | y | +| test.swift:29:26:29:29 | y | test.swift:29:26:29:29 | SSA def(y) | +| test.swift:42:16:42:19 | SSA def(b) | test.swift:45:8:45:8 | b | +| test.swift:42:16:42:19 | b | test.swift:42:16:42:19 | SSA def(b) | +| test.swift:43:9:43:13 | SSA def(t1) | test.swift:46:13:46:13 | t1 | +| test.swift:43:19:43:26 | call to source() | test.swift:43:9:43:13 | SSA def(t1) | +| test.swift:46:9:46:13 | SSA def(t) | test.swift:50:5:50:5 | SSA phi(t) | +| test.swift:46:13:46:13 | t1 | test.swift:46:9:46:13 | SSA def(t) | +| test.swift:48:9:48:13 | SSA def(t) | test.swift:50:5:50:5 | SSA phi(t) | +| test.swift:48:13:48:13 | 1 | test.swift:48:9:48:13 | SSA def(t) | +| test.swift:50:5:50:5 | SSA phi(t) | test.swift:50:15:50:15 | t | +| test.swift:54:5:54:18 | SSA def(arg) | test.swift:53:1:56:1 | arg[return] | +| test.swift:54:11:54:18 | call to source() | test.swift:54:5:54:18 | SSA def(arg) | +| test.swift:59:9:59:12 | SSA def(x) | test.swift:60:15:60:15 | x | +| test.swift:59:18:59:18 | 0 | test.swift:59:9:59:12 | SSA def(x) | | test.swift:60:15:60:15 | x | test.swift:61:23:61:23 | x | | test.swift:61:22:61:23 | &... | test.swift:62:15:62:15 | x | | test.swift:61:22:61:23 | [post] &... | test.swift:62:15:62:15 | x | | test.swift:61:23:61:23 | x | test.swift:61:22:61:23 | &... | -| test.swift:65:16:65:28 | WriteDef | test.swift:66:21:66:21 | arg1 | -| test.swift:65:16:65:28 | arg1 | test.swift:65:16:65:28 | WriteDef | -| test.swift:65:33:65:45 | WriteDef | test.swift:67:12:67:12 | arg2 | -| test.swift:65:33:65:45 | arg2 | test.swift:65:33:65:45 | WriteDef | -| test.swift:66:9:66:15 | WriteDef | test.swift:68:12:68:12 | temp | -| test.swift:66:21:66:21 | arg1 | test.swift:66:9:66:15 | WriteDef | -| test.swift:67:5:67:12 | WriteDef | test.swift:65:1:70:1 | arg1[return] | -| test.swift:67:12:67:12 | arg2 | test.swift:67:5:67:12 | WriteDef | -| test.swift:68:5:68:12 | WriteDef | test.swift:65:1:70:1 | arg2[return] | -| test.swift:68:12:68:12 | temp | test.swift:68:5:68:12 | WriteDef | -| test.swift:73:9:73:12 | WriteDef | test.swift:75:22:75:22 | x | -| test.swift:73:18:73:25 | call to source() | test.swift:73:9:73:12 | WriteDef | -| test.swift:74:9:74:12 | WriteDef | test.swift:75:32:75:32 | y | -| test.swift:74:18:74:18 | 0 | test.swift:74:9:74:12 | WriteDef | +| test.swift:65:16:65:28 | SSA def(arg1) | test.swift:66:21:66:21 | arg1 | +| test.swift:65:16:65:28 | arg1 | test.swift:65:16:65:28 | SSA def(arg1) | +| test.swift:65:33:65:45 | SSA def(arg2) | test.swift:67:12:67:12 | arg2 | +| test.swift:65:33:65:45 | arg2 | test.swift:65:33:65:45 | SSA def(arg2) | +| test.swift:66:9:66:15 | SSA def(temp) | test.swift:68:12:68:12 | temp | +| test.swift:66:21:66:21 | arg1 | test.swift:66:9:66:15 | SSA def(temp) | +| test.swift:67:5:67:12 | SSA def(arg1) | test.swift:65:1:70:1 | arg1[return] | +| test.swift:67:12:67:12 | arg2 | test.swift:67:5:67:12 | SSA def(arg1) | +| test.swift:68:5:68:12 | SSA def(arg2) | test.swift:65:1:70:1 | arg2[return] | +| test.swift:68:12:68:12 | temp | test.swift:68:5:68:12 | SSA def(arg2) | +| test.swift:73:9:73:12 | SSA def(x) | test.swift:75:22:75:22 | x | +| test.swift:73:18:73:25 | call to source() | test.swift:73:9:73:12 | SSA def(x) | +| test.swift:74:9:74:12 | SSA def(y) | test.swift:75:32:75:32 | y | +| test.swift:74:18:74:18 | 0 | test.swift:74:9:74:12 | SSA def(y) | | test.swift:75:21:75:22 | &... | test.swift:76:15:76:15 | x | | test.swift:75:21:75:22 | [post] &... | test.swift:76:15:76:15 | x | | test.swift:75:22:75:22 | x | test.swift:75:21:75:22 | &... | | test.swift:75:31:75:32 | &... | test.swift:77:15:77:15 | y | | test.swift:75:31:75:32 | [post] &... | test.swift:77:15:77:15 | y | | test.swift:75:32:75:32 | y | test.swift:75:31:75:32 | &... | -| test.swift:81:5:81:18 | WriteDef | test.swift:80:1:82:1 | arg[return] | -| test.swift:81:11:81:18 | call to source() | test.swift:81:5:81:18 | WriteDef | -| test.swift:84:1:91:1 | Phi | test.swift:84:1:91:1 | arg[return] | -| test.swift:84:48:84:54 | WriteDef | test.swift:85:8:85:8 | bool | -| test.swift:84:48:84:54 | bool | test.swift:84:48:84:54 | WriteDef | -| test.swift:86:9:86:22 | WriteDef | test.swift:84:1:91:1 | Phi | -| test.swift:86:15:86:22 | call to source() | test.swift:86:9:86:22 | WriteDef | -| test.swift:89:9:89:22 | WriteDef | test.swift:84:1:91:1 | Phi | -| test.swift:89:15:89:22 | call to source() | test.swift:89:9:89:22 | WriteDef | -| test.swift:93:17:93:23 | WriteDef | test.swift:104:50:104:50 | bool | -| test.swift:93:17:93:23 | bool | test.swift:93:17:93:23 | WriteDef | -| test.swift:95:13:95:16 | WriteDef | test.swift:96:19:96:19 | x | -| test.swift:95:22:95:22 | 0 | test.swift:95:13:95:16 | WriteDef | +| test.swift:81:5:81:18 | SSA def(arg) | test.swift:80:1:82:1 | arg[return] | +| test.swift:81:11:81:18 | call to source() | test.swift:81:5:81:18 | SSA def(arg) | +| test.swift:84:1:91:1 | SSA phi(arg) | test.swift:84:1:91:1 | arg[return] | +| test.swift:84:48:84:54 | SSA def(bool) | test.swift:85:8:85:8 | bool | +| test.swift:84:48:84:54 | bool | test.swift:84:48:84:54 | SSA def(bool) | +| test.swift:86:9:86:22 | SSA def(arg) | test.swift:84:1:91:1 | SSA phi(arg) | +| test.swift:86:15:86:22 | call to source() | test.swift:86:9:86:22 | SSA def(arg) | +| test.swift:89:9:89:22 | SSA def(arg) | test.swift:84:1:91:1 | SSA phi(arg) | +| test.swift:89:15:89:22 | call to source() | test.swift:89:9:89:22 | SSA def(arg) | +| test.swift:93:17:93:23 | SSA def(bool) | test.swift:104:50:104:50 | bool | +| test.swift:93:17:93:23 | bool | test.swift:93:17:93:23 | SSA def(bool) | +| test.swift:95:13:95:16 | SSA def(x) | test.swift:96:19:96:19 | x | +| test.swift:95:22:95:22 | 0 | test.swift:95:13:95:16 | SSA def(x) | | test.swift:96:19:96:19 | x | test.swift:97:40:97:40 | x | | test.swift:97:39:97:40 | &... | test.swift:98:19:98:19 | x | | test.swift:97:39:97:40 | [post] &... | test.swift:98:19:98:19 | x | | test.swift:97:40:97:40 | x | test.swift:97:39:97:40 | &... | -| test.swift:102:13:102:16 | WriteDef | test.swift:103:19:103:19 | x | -| test.swift:102:22:102:22 | 0 | test.swift:102:13:102:16 | WriteDef | +| test.swift:102:13:102:16 | SSA def(x) | test.swift:103:19:103:19 | x | +| test.swift:102:22:102:22 | 0 | test.swift:102:13:102:16 | SSA def(x) | | test.swift:103:19:103:19 | x | test.swift:104:41:104:41 | x | | test.swift:104:40:104:41 | &... | test.swift:105:19:105:19 | x | | test.swift:104:40:104:41 | [post] &... | test.swift:105:19:105:19 | x | | test.swift:104:41:104:41 | x | test.swift:104:40:104:41 | &... | -| test.swift:109:9:109:14 | WriteDef | test.swift:110:12:110:12 | arg | -| test.swift:109:9:109:14 | arg | test.swift:109:9:109:14 | WriteDef | -| test.swift:113:14:113:19 | WriteDef | test.swift:114:19:114:19 | arg | -| test.swift:113:14:113:19 | arg | test.swift:113:14:113:19 | WriteDef | -| test.swift:113:24:113:41 | WriteDef | test.swift:114:12:114:12 | lambda | -| test.swift:113:24:113:41 | lambda | test.swift:113:24:113:41 | WriteDef | -| test.swift:118:9:118:12 | WriteDef | test.swift:119:31:119:31 | x | -| test.swift:118:18:118:25 | call to source() | test.swift:118:9:118:12 | WriteDef | -| test.swift:119:9:119:12 | WriteDef | test.swift:120:15:120:15 | y | -| test.swift:119:18:119:44 | call to forward(arg:lambda:) | test.swift:119:9:119:12 | WriteDef | -| test.swift:122:9:122:12 | WriteDef | test.swift:126:15:126:15 | z | -| test.swift:122:18:125:6 | call to forward(arg:lambda:) | test.swift:122:9:122:12 | WriteDef | -| test.swift:123:10:123:13 | WriteDef | test.swift:124:16:124:16 | i | -| test.swift:123:10:123:13 | i | test.swift:123:10:123:13 | WriteDef | -| test.swift:128:9:128:16 | WriteDef | test.swift:132:15:132:15 | clean | -| test.swift:128:22:131:6 | call to forward(arg:lambda:) | test.swift:128:9:128:16 | WriteDef | -| test.swift:141:9:141:9 | WriteDef | test.swift:145:15:145:15 | lambda2 | -| test.swift:141:19:144:5 | { ... } | test.swift:141:9:141:9 | WriteDef | -| test.swift:142:10:142:13 | WriteDef | test.swift:143:16:143:16 | i | -| test.swift:142:10:142:13 | i | test.swift:142:10:142:13 | WriteDef | -| test.swift:147:9:147:9 | WriteDef | test.swift:151:15:151:15 | lambdaSource | -| test.swift:147:24:150:5 | { ... } | test.swift:147:9:147:9 | WriteDef | +| test.swift:109:9:109:14 | SSA def(arg) | test.swift:110:12:110:12 | arg | +| test.swift:109:9:109:14 | arg | test.swift:109:9:109:14 | SSA def(arg) | +| test.swift:113:14:113:19 | SSA def(arg) | test.swift:114:19:114:19 | arg | +| test.swift:113:14:113:19 | arg | test.swift:113:14:113:19 | SSA def(arg) | +| test.swift:113:24:113:41 | SSA def(lambda) | test.swift:114:12:114:12 | lambda | +| test.swift:113:24:113:41 | lambda | test.swift:113:24:113:41 | SSA def(lambda) | +| test.swift:118:9:118:12 | SSA def(x) | test.swift:119:31:119:31 | x | +| test.swift:118:18:118:25 | call to source() | test.swift:118:9:118:12 | SSA def(x) | +| test.swift:119:9:119:12 | SSA def(y) | test.swift:120:15:120:15 | y | +| test.swift:119:18:119:44 | call to forward(arg:lambda:) | test.swift:119:9:119:12 | SSA def(y) | +| test.swift:122:9:122:12 | SSA def(z) | test.swift:126:15:126:15 | z | +| test.swift:122:18:125:6 | call to forward(arg:lambda:) | test.swift:122:9:122:12 | SSA def(z) | +| test.swift:123:10:123:13 | SSA def(i) | test.swift:124:16:124:16 | i | +| test.swift:123:10:123:13 | i | test.swift:123:10:123:13 | SSA def(i) | +| test.swift:128:9:128:16 | SSA def(clean) | test.swift:132:15:132:15 | clean | +| test.swift:128:22:131:6 | call to forward(arg:lambda:) | test.swift:128:9:128:16 | SSA def(clean) | +| test.swift:141:9:141:9 | SSA def(lambda2) | test.swift:145:15:145:15 | lambda2 | +| test.swift:141:19:144:5 | { ... } | test.swift:141:9:141:9 | SSA def(lambda2) | +| test.swift:142:10:142:13 | SSA def(i) | test.swift:143:16:143:16 | i | +| test.swift:142:10:142:13 | i | test.swift:142:10:142:13 | SSA def(i) | +| test.swift:147:9:147:9 | SSA def(lambdaSource) | test.swift:151:15:151:15 | lambdaSource | +| test.swift:147:24:150:5 | { ... } | test.swift:147:9:147:9 | SSA def(lambdaSource) | | test.swift:151:15:151:15 | lambdaSource | test.swift:159:16:159:16 | lambdaSource | -| test.swift:153:9:153:9 | WriteDef | test.swift:157:5:157:5 | lambdaSink | -| test.swift:153:22:156:5 | { ... } | test.swift:153:9:153:9 | WriteDef | -| test.swift:154:10:154:13 | WriteDef | test.swift:155:19:155:19 | i | -| test.swift:154:10:154:13 | i | test.swift:154:10:154:13 | WriteDef | +| test.swift:153:9:153:9 | SSA def(lambdaSink) | test.swift:157:5:157:5 | lambdaSink | +| test.swift:153:22:156:5 | { ... } | test.swift:153:9:153:9 | SSA def(lambdaSink) | +| test.swift:154:10:154:13 | SSA def(i) | test.swift:155:19:155:19 | i | +| test.swift:154:10:154:13 | i | test.swift:154:10:154:13 | SSA def(i) | | test.swift:157:5:157:5 | lambdaSink | test.swift:159:5:159:5 | lambdaSink | -| test.swift:162:7:162:7 | WriteDef | test.swift:162:7:162:7 | self[return] | -| test.swift:162:7:162:7 | self | test.swift:162:7:162:7 | WriteDef | -| test.swift:163:7:163:7 | self | test.swift:163:7:163:7 | WriteDef | -| test.swift:163:7:163:7 | self | test.swift:163:7:163:7 | WriteDef | -| test.swift:163:7:163:7 | self | test.swift:163:7:163:7 | WriteDef | -| test.swift:163:7:163:7 | value | test.swift:163:7:163:7 | WriteDef | -| test.swift:165:3:165:3 | WriteDef | test.swift:166:5:166:5 | self | -| test.swift:165:3:165:3 | self | test.swift:165:3:165:3 | WriteDef | +| test.swift:162:7:162:7 | SSA def(self) | test.swift:162:7:162:7 | self[return] | +| test.swift:162:7:162:7 | self | test.swift:162:7:162:7 | SSA def(self) | +| test.swift:163:7:163:7 | self | test.swift:163:7:163:7 | SSA def(self) | +| test.swift:163:7:163:7 | self | test.swift:163:7:163:7 | SSA def(self) | +| test.swift:163:7:163:7 | self | test.swift:163:7:163:7 | SSA def(self) | +| test.swift:163:7:163:7 | value | test.swift:163:7:163:7 | SSA def(value) | +| test.swift:165:3:165:3 | SSA def(self) | test.swift:166:5:166:5 | self | +| test.swift:165:3:165:3 | self | test.swift:165:3:165:3 | SSA def(self) | | test.swift:166:5:166:5 | [post] self | test.swift:165:3:167:3 | self[return] | | test.swift:166:5:166:5 | self | test.swift:165:3:167:3 | self[return] | -| test.swift:169:8:169:8 | WriteDef | test.swift:170:5:170:5 | self | -| test.swift:169:8:169:8 | self | test.swift:169:8:169:8 | WriteDef | -| test.swift:169:12:169:22 | WriteDef | test.swift:170:9:170:9 | value | -| test.swift:169:12:169:22 | value | test.swift:169:12:169:22 | WriteDef | +| test.swift:169:8:169:8 | SSA def(self) | test.swift:170:5:170:5 | self | +| test.swift:169:8:169:8 | self | test.swift:169:8:169:8 | SSA def(self) | +| test.swift:169:12:169:22 | SSA def(value) | test.swift:170:9:170:9 | value | +| test.swift:169:12:169:22 | value | test.swift:169:12:169:22 | SSA def(value) | | test.swift:170:5:170:5 | [post] self | test.swift:169:3:171:3 | self[return] | | test.swift:170:5:170:5 | self | test.swift:169:3:171:3 | self[return] | -| test.swift:173:8:173:8 | WriteDef | test.swift:174:12:174:12 | self | -| test.swift:173:8:173:8 | self | test.swift:173:8:173:8 | WriteDef | +| test.swift:173:8:173:8 | SSA def(self) | test.swift:174:12:174:12 | self | +| test.swift:173:8:173:8 | self | test.swift:173:8:173:8 | SSA def(self) | | test.swift:174:12:174:12 | [post] self | test.swift:173:3:175:3 | self[return] | | test.swift:174:12:174:12 | self | test.swift:173:3:175:3 | self[return] | -| test.swift:179:7:179:7 | WriteDef | test.swift:180:3:180:3 | a | -| test.swift:179:11:179:13 | call to init() | test.swift:179:7:179:7 | WriteDef | +| test.swift:179:7:179:7 | SSA def(a) | test.swift:180:3:180:3 | a | +| test.swift:179:11:179:13 | call to init() | test.swift:179:7:179:7 | SSA def(a) | | test.swift:180:3:180:3 | [post] a | test.swift:181:13:181:13 | a | | test.swift:180:3:180:3 | a | test.swift:181:13:181:13 | a | -| test.swift:184:7:184:7 | WriteDef | test.swift:184:7:184:7 | self[return] | -| test.swift:184:7:184:7 | self | test.swift:184:7:184:7 | WriteDef | -| test.swift:185:7:185:7 | self | test.swift:185:7:185:7 | WriteDef | -| test.swift:185:7:185:7 | self | test.swift:185:7:185:7 | WriteDef | -| test.swift:185:7:185:7 | self | test.swift:185:7:185:7 | WriteDef | -| test.swift:185:7:185:7 | value | test.swift:185:7:185:7 | WriteDef | -| test.swift:187:3:187:3 | WriteDef | test.swift:188:5:188:5 | self | -| test.swift:187:3:187:3 | self | test.swift:187:3:187:3 | WriteDef | +| test.swift:184:7:184:7 | SSA def(self) | test.swift:184:7:184:7 | self[return] | +| test.swift:184:7:184:7 | self | test.swift:184:7:184:7 | SSA def(self) | +| test.swift:185:7:185:7 | self | test.swift:185:7:185:7 | SSA def(self) | +| test.swift:185:7:185:7 | self | test.swift:185:7:185:7 | SSA def(self) | +| test.swift:185:7:185:7 | self | test.swift:185:7:185:7 | SSA def(self) | +| test.swift:185:7:185:7 | value | test.swift:185:7:185:7 | SSA def(value) | +| test.swift:187:3:187:3 | SSA def(self) | test.swift:188:5:188:5 | self | +| test.swift:187:3:187:3 | self | test.swift:187:3:187:3 | SSA def(self) | | test.swift:188:5:188:5 | [post] self | test.swift:187:3:189:3 | self[return] | | test.swift:188:5:188:5 | self | test.swift:187:3:189:3 | self[return] | -| test.swift:193:7:193:7 | WriteDef | test.swift:194:3:194:3 | b | -| test.swift:193:11:193:13 | call to init() | test.swift:193:7:193:7 | WriteDef | +| test.swift:193:7:193:7 | SSA def(b) | test.swift:194:3:194:3 | b | +| test.swift:193:11:193:13 | call to init() | test.swift:193:7:193:7 | SSA def(b) | | test.swift:194:3:194:3 | [post] b | test.swift:195:13:195:13 | b | | test.swift:194:3:194:3 | b | test.swift:195:13:195:13 | b | -| test.swift:199:7:199:7 | WriteDef | test.swift:200:3:200:3 | a | -| test.swift:199:11:199:13 | call to init() | test.swift:199:7:199:7 | WriteDef | +| test.swift:199:7:199:7 | SSA def(a) | test.swift:200:3:200:3 | a | +| test.swift:199:11:199:13 | call to init() | test.swift:199:7:199:7 | SSA def(a) | | test.swift:200:3:200:3 | [post] a | test.swift:201:13:201:13 | a | | test.swift:200:3:200:3 | a | test.swift:201:13:201:13 | a | -| test.swift:205:7:205:7 | WriteDef | test.swift:206:3:206:3 | a | -| test.swift:205:11:205:13 | call to init() | test.swift:205:7:205:7 | WriteDef | +| test.swift:205:7:205:7 | SSA def(a) | test.swift:206:3:206:3 | a | +| test.swift:205:11:205:13 | call to init() | test.swift:205:7:205:7 | SSA def(a) | | test.swift:206:3:206:3 | [post] a | test.swift:207:13:207:13 | a | | test.swift:206:3:206:3 | a | test.swift:207:13:207:13 | a | -| test.swift:211:7:211:7 | WriteDef | test.swift:212:3:212:3 | a | -| test.swift:211:11:211:13 | call to init() | test.swift:211:7:211:7 | WriteDef | +| test.swift:211:7:211:7 | SSA def(a) | test.swift:212:3:212:3 | a | +| test.swift:211:11:211:13 | call to init() | test.swift:211:7:211:7 | SSA def(a) | | test.swift:212:3:212:3 | [post] a | test.swift:213:13:213:13 | a | | test.swift:212:3:212:3 | a | test.swift:213:13:213:13 | a | -| test.swift:217:7:217:7 | WriteDef | test.swift:218:3:218:3 | b | -| test.swift:217:11:217:13 | call to init() | test.swift:217:7:217:7 | WriteDef | +| test.swift:217:7:217:7 | SSA def(b) | test.swift:218:3:218:3 | b | +| test.swift:217:11:217:13 | call to init() | test.swift:217:7:217:7 | SSA def(b) | | test.swift:218:3:218:3 | [post] b | test.swift:219:13:219:13 | b | | test.swift:218:3:218:3 | b | test.swift:219:13:219:13 | b | -| test.swift:222:7:222:7 | WriteDef | test.swift:222:7:222:7 | self[return] | -| test.swift:222:7:222:7 | WriteDef | test.swift:222:7:222:7 | self[return] | -| test.swift:222:7:222:7 | self | test.swift:222:7:222:7 | WriteDef | -| test.swift:222:7:222:7 | self | test.swift:222:7:222:7 | WriteDef | -| test.swift:223:7:223:7 | self | test.swift:223:7:223:7 | WriteDef | -| test.swift:224:5:224:5 | WriteDef | test.swift:224:5:226:5 | self[return] | -| test.swift:224:5:224:5 | self | test.swift:224:5:224:5 | WriteDef | -| test.swift:227:5:227:5 | WriteDef | test.swift:227:5:229:5 | self[return] | -| test.swift:227:5:227:5 | self | test.swift:227:5:227:5 | WriteDef | -| test.swift:234:7:234:7 | WriteDef | test.swift:235:13:235:13 | a | -| test.swift:234:11:234:31 | call to init() | test.swift:234:7:234:7 | WriteDef | +| test.swift:222:7:222:7 | SSA def(self) | test.swift:222:7:222:7 | self[return] | +| test.swift:222:7:222:7 | SSA def(self) | test.swift:222:7:222:7 | self[return] | +| test.swift:222:7:222:7 | self | test.swift:222:7:222:7 | SSA def(self) | +| test.swift:222:7:222:7 | self | test.swift:222:7:222:7 | SSA def(self) | +| test.swift:223:7:223:7 | self | test.swift:223:7:223:7 | SSA def(self) | +| test.swift:224:5:224:5 | SSA def(self) | test.swift:224:5:226:5 | self[return] | +| test.swift:224:5:224:5 | self | test.swift:224:5:224:5 | SSA def(self) | +| test.swift:227:5:227:5 | SSA def(self) | test.swift:227:5:229:5 | self[return] | +| test.swift:227:5:227:5 | self | test.swift:227:5:227:5 | SSA def(self) | +| test.swift:234:7:234:7 | SSA def(a) | test.swift:235:13:235:13 | a | +| test.swift:234:11:234:31 | call to init() | test.swift:234:7:234:7 | SSA def(a) | | test.swift:235:13:235:13 | [post] a | test.swift:237:3:237:3 | a | | test.swift:235:13:235:13 | a | test.swift:237:3:237:3 | a | | test.swift:237:3:237:3 | [post] a | test.swift:238:13:238:13 | a | | test.swift:237:3:237:3 | a | test.swift:238:13:238:13 | a | -| test.swift:242:9:242:9 | self | test.swift:242:9:242:9 | WriteDef | -| test.swift:242:9:242:9 | self | test.swift:242:9:242:9 | WriteDef | -| test.swift:242:9:242:9 | self | test.swift:242:9:242:9 | WriteDef | -| test.swift:242:9:242:9 | value | test.swift:242:9:242:9 | WriteDef | -| test.swift:243:9:243:9 | WriteDef | test.swift:243:18:243:18 | self | -| test.swift:243:9:243:9 | self | test.swift:243:9:243:9 | WriteDef | +| test.swift:242:9:242:9 | self | test.swift:242:9:242:9 | SSA def(self) | +| test.swift:242:9:242:9 | self | test.swift:242:9:242:9 | SSA def(self) | +| test.swift:242:9:242:9 | self | test.swift:242:9:242:9 | SSA def(self) | +| test.swift:242:9:242:9 | value | test.swift:242:9:242:9 | SSA def(value) | +| test.swift:243:9:243:9 | SSA def(self) | test.swift:243:18:243:18 | self | +| test.swift:243:9:243:9 | self | test.swift:243:9:243:9 | SSA def(self) | | test.swift:243:18:243:18 | [post] self | test.swift:243:9:243:42 | self[return] | | test.swift:243:18:243:18 | self | test.swift:243:9:243:42 | self[return] | -| test.swift:246:5:246:5 | WriteDef | test.swift:247:9:247:9 | self | -| test.swift:246:5:246:5 | self | test.swift:246:5:246:5 | WriteDef | +| test.swift:246:5:246:5 | SSA def(self) | test.swift:247:9:247:9 | self | +| test.swift:246:5:246:5 | self | test.swift:246:5:246:5 | SSA def(self) | | test.swift:247:9:247:9 | [post] self | test.swift:246:5:248:5 | self[return] | | test.swift:247:9:247:9 | self | test.swift:246:5:248:5 | self[return] | -| test.swift:252:23:252:23 | value | test.swift:252:23:252:23 | WriteDef | -| test.swift:263:9:263:9 | WriteDef | test.swift:264:15:264:15 | x | -| test.swift:263:13:263:28 | call to optionalSource() | test.swift:263:9:263:9 | WriteDef | +| test.swift:252:23:252:23 | value | test.swift:252:23:252:23 | SSA def(value) | +| test.swift:263:9:263:9 | SSA def(x) | test.swift:264:15:264:15 | x | +| test.swift:263:13:263:28 | call to optionalSource() | test.swift:263:9:263:9 | SSA def(x) | | test.swift:264:15:264:15 | x | test.swift:264:15:264:16 | ...! | | test.swift:264:15:264:15 | x | test.swift:266:15:266:15 | x | | test.swift:266:15:266:15 | x | test.swift:266:15:266:16 | ...? | | test.swift:266:15:266:15 | x | test.swift:267:15:267:15 | x | | test.swift:266:15:266:25 | call to signum() | test.swift:266:15:266:25 | OptionalEvaluationExpr | | test.swift:267:15:267:15 | x | test.swift:268:16:268:16 | x | -| test.swift:277:9:277:9 | WriteDef | test.swift:279:15:279:15 | t1 | -| test.swift:277:14:277:26 | (...) | test.swift:277:9:277:9 | WriteDef | +| test.swift:277:9:277:9 | SSA def(t1) | test.swift:279:15:279:15 | t1 | +| test.swift:277:14:277:26 | (...) | test.swift:277:9:277:9 | SSA def(t1) | | test.swift:279:15:279:15 | t1 | test.swift:280:15:280:15 | t1 | | test.swift:280:15:280:15 | [post] t1 | test.swift:281:15:281:15 | t1 | | test.swift:280:15:280:15 | t1 | test.swift:281:15:281:15 | t1 | @@ -211,17 +211,17 @@ | test.swift:291:15:291:15 | t1 | test.swift:292:15:292:15 | t1 | | test.swift:292:15:292:15 | [post] t1 | test.swift:293:15:293:15 | t1 | | test.swift:292:15:292:15 | t1 | test.swift:293:15:293:15 | t1 | -| test.swift:297:9:297:9 | WriteDef | test.swift:298:14:298:14 | t1 | -| test.swift:297:14:297:45 | (...) | test.swift:297:9:297:9 | WriteDef | -| test.swift:298:9:298:9 | WriteDef | test.swift:305:15:305:15 | t2 | -| test.swift:298:14:298:14 | t1 | test.swift:298:9:298:9 | WriteDef | +| test.swift:297:9:297:9 | SSA def(t1) | test.swift:298:14:298:14 | t1 | +| test.swift:297:14:297:45 | (...) | test.swift:297:9:297:9 | SSA def(t1) | +| test.swift:298:9:298:9 | SSA def(t2) | test.swift:305:15:305:15 | t2 | +| test.swift:298:14:298:14 | t1 | test.swift:298:9:298:9 | SSA def(t2) | | test.swift:298:14:298:14 | t1 | test.swift:299:21:299:21 | t1 | -| test.swift:299:9:299:17 | WriteDef | test.swift:309:15:309:15 | a | -| test.swift:299:9:299:17 | WriteDef | test.swift:310:15:310:15 | b | -| test.swift:299:9:299:17 | WriteDef | test.swift:311:15:311:15 | c | -| test.swift:299:21:299:21 | t1 | test.swift:299:9:299:17 | WriteDef | -| test.swift:299:21:299:21 | t1 | test.swift:299:9:299:17 | WriteDef | -| test.swift:299:21:299:21 | t1 | test.swift:299:9:299:17 | WriteDef | +| test.swift:299:9:299:17 | SSA def(a) | test.swift:309:15:309:15 | a | +| test.swift:299:9:299:17 | SSA def(b) | test.swift:310:15:310:15 | b | +| test.swift:299:9:299:17 | SSA def(c) | test.swift:311:15:311:15 | c | +| test.swift:299:21:299:21 | t1 | test.swift:299:9:299:17 | SSA def(a) | +| test.swift:299:21:299:21 | t1 | test.swift:299:9:299:17 | SSA def(b) | +| test.swift:299:21:299:21 | t1 | test.swift:299:9:299:17 | SSA def(c) | | test.swift:299:21:299:21 | t1 | test.swift:301:15:301:15 | t1 | | test.swift:301:15:301:15 | t1 | test.swift:302:15:302:15 | t1 | | test.swift:302:15:302:15 | [post] t1 | test.swift:303:15:303:15 | t1 |