Skip to content

Commit 049ea0d

Browse files
committed
Unified: Support defer in CFG.
1 parent b101aee commit 049ea0d

4 files changed

Lines changed: 47 additions & 12 deletions

File tree

‎unified/ql/lib/codeql/unified/internal/ControlFlowGraph.qll‎

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -35,12 +35,17 @@ module Ast implements AstSig<Location> {
3535
not e.fromSource()
3636
}
3737

38+
private AstNode adjustedGetChild(AstNode n, int index) { deferScope(n, index, result) }
39+
3840
AstNode getChild(AstNode n, int index) {
3941
result.getParent() = n and
4042
result.getParentIndex() = index and
4143
not n instanceof Callable and
4244
not skipControlFlow(n) and
43-
not skipControlFlow(result)
45+
not skipControlFlow(result) and
46+
not adjustedGetChild(_, _) = result
47+
or
48+
adjustedGetChild(n, index) = result
4449
or
4550
n.(FunctionExpr).getCaptureDeclaration(index) = result
4651
}
@@ -74,7 +79,25 @@ module Ast implements AstSig<Location> {
7479

7580
class Expr = U::Expr;
7681

77-
class BlockStmt = U::Block;
82+
private predicate deferScope(U::DeferStmt defer, int n, Stmt s) {
83+
exists(U::Block block, int deferIdx | block.getStmt(deferIdx) = defer |
84+
block.getStmt(deferIdx + 1) = s and n = 0
85+
or
86+
exists(Stmt mid |
87+
deferScope(defer, n - 1, mid) and
88+
not mid instanceof U::DeferStmt and
89+
block.getStmt(deferIdx + 1 + n) = s
90+
)
91+
)
92+
}
93+
94+
class BlockStmt extends Stmt instanceof U::Block {
95+
Stmt getStmt(int n) { result = super.getStmt(n) and not deferScope(_, _, result) }
96+
97+
Stmt getLastStmt() {
98+
exists(int i | result = this.getStmt(i) and not exists(this.getStmt(i + 1)))
99+
}
100+
}
78101

79102
class ExprStmt extends Stmt {
80103
ExprStmt() { none() }
@@ -150,12 +173,18 @@ module Ast implements AstSig<Location> {
150173
Expr getExpr() { result = super.getValue() }
151174
}
152175

153-
class TryStmt extends U::TryExpr {
154-
AstNode getBody(int index) { index = 0 and result = super.getBody() }
176+
class TryStmt extends Stmt {
177+
TryStmt() { this instanceof U::TryExpr or this instanceof U::DeferStmt }
178+
179+
AstNode getBody(int index) {
180+
index = 0 and result = this.(U::TryExpr).getBody()
181+
or
182+
deferScope(this, index, result)
183+
}
155184

156-
CatchClause getCatch(int index) { result = super.getCatchClause(index) }
185+
CatchClause getCatch(int index) { result = this.(U::TryExpr).getCatchClause(index) }
157186

158-
Stmt getFinally() { none() }
187+
Stmt getFinally() { result = this.(U::DeferStmt).getBody() }
159188
}
160189

161190
class CatchClause extends U::CatchClause {

‎unified/ql/test/library-tests/controlflow/basicblock-slices.expected‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -147,9 +147,11 @@
147147
| 171 | cfg.swift:171:12:171:16 | false | 'false -^ ReturnExpr' |
148148
| 175 | cfg.swift:175:1:191:1 | func testDefer | 'func testDefer' |
149149
| 175 | cfg.swift:175:16:175:16 | x | 'x -> Block' |
150-
| 177 | cfg.swift:177:3:179:3 | DeferStmt | 'DeferStmt -V Block' |
150+
| 177 | cfg.swift:177:3:179:3 | DeferStmt | 'DeferStmt' |
151+
| 177 | cfg.swift:177:9:179:3 | Block | 'Block' |
151152
| 178 | cfg.swift:178:5:178:9 | print | 'print -> Argument -V "4" -^ print(...)' |
152-
| 181 | cfg.swift:181:3:183:3 | DeferStmt | 'DeferStmt -V Block' |
153+
| 181 | cfg.swift:181:3:183:3 | DeferStmt | 'DeferStmt' |
154+
| 181 | cfg.swift:181:9:183:3 | Block | 'Block' |
153155
| 182 | cfg.swift:182:5:182:9 | print | 'print -> Argument -V "3" -^ print(...)' |
154156
| 185 | cfg.swift:185:3:190:3 | DeferStmt | 'DeferStmt -V Block' |
155157
| 186 | cfg.swift:186:5:186:9 | print | 'print -> Argument -V "1" -^ print(...)' |

‎unified/ql/test/library-tests/controlflow/cfg.expected‎

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
11
bbContinues
2+
| cfg.swift:177:3:177:3 | DeferStmt | 'DeferStmt goto DeferStmt(+4)' |
3+
| cfg.swift:181:3:181:3 | DeferStmt | 'DeferStmt goto DeferStmt(+4)' |
4+
| cfg.swift:182:5:182:14 | print(...) | 'print(...) goto Block(-5)' |
5+
| cfg.swift:188:7:188:16 | print(...) | 'print(...) goto Block(-7)' |
26
bbStep
37
| cfg.swift:20:9:20:14 | ... >= ... | '... >= ... : false -> Block(+0)' |
48
| cfg.swift:20:9:20:14 | ... >= ... | '... >= ... : true -> GuardIfStmt(+3)' |

‎unified/ql/test/library-tests/controlflow/cfg.swift‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -174,18 +174,18 @@ func patterns(x : Int) -> Bool {
174174

175175
func testDefer(x : inout Int) {
176176
// Will print 1, 2, 3, 4
177-
defer {
177+
defer { // $ bbContinues='DeferStmt goto DeferStmt(+4)'
178178
print("4")
179179
}
180180

181-
defer {
182-
print("3")
181+
defer { // $ bbContinues='DeferStmt goto DeferStmt(+4)'
182+
print("3") // $ bbContinues='print(...) goto Block(-5)'
183183
}
184184

185185
defer {
186186
print("1")
187187
defer {
188-
print("2")
188+
print("2") // $ bbContinues='print(...) goto Block(-7)'
189189
}
190190
}
191191
}

0 commit comments

Comments
 (0)