Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit dd954ea

Browse files
committed
CFG: correct flow for lambda bodies
Lambda bodies are parsed as nested do-blocks or normal blocks. This is actually incorrect, as the body of a lambda can't have parameters. However, we can "inline" such blocks to get the desired control flow.
1 parent eafec43 commit dd954ea

3 files changed

Lines changed: 32 additions & 20 deletions

File tree

ql/src/codeql_ruby/controlflow/ControlFlowGraph.qll

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ private module CfgScope {
7676
}
7777

7878
private class DoBlockScope extends Range, Generated::DoBlock {
79+
DoBlockScope() { not this.getParent() instanceof Generated::Lambda }
80+
7981
final override string getName() { result = "do block" }
8082

8183
final override predicate entry(Generated::AstNode first) {
@@ -88,6 +90,8 @@ private module CfgScope {
8890
}
8991

9092
private class BlockScope extends Range, Generated::Block {
93+
BlockScope() { not this.getParent() instanceof Generated::Lambda }
94+
9195
final override string getName() { result = "block" }
9296

9397
final override predicate entry(Generated::AstNode first) {
@@ -103,11 +107,22 @@ private module CfgScope {
103107
final override string getName() { result = "lambda" }
104108

105109
final override predicate entry(Generated::AstNode first) {
106-
first(this.(Trees::LambdaTree).getFirstChildNode(), first)
110+
first(this.getParameters(), first)
111+
or
112+
not exists(this.getParameters()) and
113+
(
114+
first(this.getBody().(Trees::DoBlockTree).firstBody(), first)
115+
or
116+
first(this.getBody().(Trees::BlockTree).getFirstChildNode(), first)
117+
)
107118
}
108119

109120
final override predicate exit(Generated::AstNode last, Completion c) {
110-
last(this.(Trees::LambdaTree).getLastChildNode(), last, c)
121+
last(this.getBody().(Trees::BlockTree).getLastChildNode(), last, c)
122+
or
123+
this.getBody().(Trees::RescueEnsureBlockTree).lastBody(last, c)
124+
or
125+
not exists(this.getBody()) and last(this.getParameters(), last, c)
111126
}
112127
}
113128
}

ql/src/codeql_ruby/controlflow/internal/ControlFlowGraphImpl.qll

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -431,7 +431,7 @@ module Trees {
431431
override predicate isHidden() { any() }
432432
}
433433

434-
private class DoBlockTree extends RescueEnsureBlockTree, PostOrderTree, DoBlock {
434+
class DoBlockTree extends RescueEnsureBlockTree, PostOrderTree, DoBlock {
435435
final override predicate first(AstNode first) { first = this }
436436

437437
final override AstNode getChildNode(int i, boolean rescuable) {
@@ -679,11 +679,19 @@ module Trees {
679679
final override AstNode getDefaultValue() { result = this.getValue() }
680680
}
681681

682-
class LambdaTree extends StandardNode, PreOrderTree, PostOrderTree, Lambda {
683-
final override AstNode getChildNode(int i) {
684-
result = this.getParameters() and i = 0
682+
class LambdaTree extends PreOrderTree, PostOrderTree, Lambda {
683+
final override predicate propagatesAbnormal(AstNode child) { child = this.getParameters() }
684+
685+
final override predicate succ(AstNode pred, AstNode succ, Completion c) {
686+
this.getBody().(ControlFlowTree).succ(pred, succ, c)
685687
or
686-
result = this.getBody() and i = 1
688+
last(this.getParameters(), pred, c) and
689+
c instanceof NormalCompletion and
690+
(
691+
first(this.getBody().(DoBlockTree).firstBody(), succ)
692+
or
693+
first(this.getBody().(BlockTree).getFirstChildNode(), succ)
694+
)
687695
}
688696
}
689697

ql/test/library-tests/controlflow/graph/Cfg.expected

Lines changed: 2 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,6 @@ cfg.rb:
4949
# 120| enter lambda
5050
#-----| -> x
5151

52-
# 120| enter block
53-
#-----| -> y
54-
5552
# 142| enter print
5653
#-----| -> puts
5754

@@ -1375,19 +1372,16 @@ cfg.rb:
13751372
#-----| -> swap
13761373

13771374
# 120| DestructuredParameter
1378-
#-----| -> Block
1375+
#-----| -> y
13791376

13801377
# 120| x
13811378
#-----| -> y
13821379

13831380
# 120| y
13841381
#-----| -> DestructuredParameter
13851382

1386-
# 120| Block
1387-
#-----| -> exit lambda (normal)
1388-
13891383
# 120| Array
1390-
#-----| -> exit block (normal)
1384+
#-----| -> exit lambda (normal)
13911385

13921386
# 120| y
13931387
#-----| -> x
@@ -3690,8 +3684,6 @@ cfg.rb:
36903684

36913685
# 120| exit lambda
36923686

3693-
# 120| exit block
3694-
36953687
# 142| exit print
36963688

36973689
# 149| exit method
@@ -3821,9 +3813,6 @@ cfg.rb:
38213813
# 120| exit lambda (normal)
38223814
#-----| -> exit lambda
38233815

3824-
# 120| exit block (normal)
3825-
#-----| -> exit block
3826-
38273816
# 142| exit print (normal)
38283817
#-----| -> exit print
38293818

0 commit comments

Comments
 (0)