Skip to content

Commit bd4e515

Browse files
authored
Merge pull request #22589 from aschackmull/unified/cfg-try-exception
Unified: Add exception CFG edges from try expressions.
2 parents bac3357 + ea20259 commit bd4e515

6 files changed

Lines changed: 71 additions & 20 deletions

File tree

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

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ module;
77
private import unified
88
private import codeql.controlflow.ControlFlowGraph
99
private import codeql.controlflow.SuccessorType
10+
private import ControlFlowGraphPlugin
1011

1112
private module Cfg0 = Make0<Location, Ast>;
1213

@@ -221,6 +222,8 @@ private module Ast implements AstSig<Location> {
221222
}
222223
}
223224

225+
private predicate mayThrow(AstNode ast) { any(ControlFlowGraphPlugin p).mayThrow(ast) }
226+
224227
private module Input implements InputSig1, InputSig2 {
225228
private import codeql.util.Void
226229

@@ -256,7 +259,10 @@ private module Input implements InputSig1, InputSig2 {
256259
predicate beginAbruptCompletion(
257260
AstNode ast, PreControlFlowNode n, AbruptCompletion c, boolean always
258261
) {
259-
none()
262+
mayThrow(ast) and
263+
n.isIn(ast) and
264+
c.asSimpleAbruptCompletion() instanceof ExceptionSuccessor and
265+
always = false
260266
}
261267

262268
predicate endAbruptCompletion(AstNode ast, PreControlFlowNode n, AbruptCompletion c) { none() }
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
private import unified
2+
private import codeql.util.Unit
3+
4+
private module Plugins {
5+
private import ControlFlowGraphPluginSwift
6+
}
7+
8+
class ControlFlowGraphPlugin extends Unit {
9+
predicate mayThrow(AstNode ast) { none() }
10+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
private import unified
2+
private import ControlFlowGraphPlugin
3+
4+
private predicate inTry(AstNode ast) {
5+
ast.(UnaryExpr).getOperator().(Token).getValue() = "try"
6+
or
7+
exists(AstNode parent |
8+
parent = ast.getParent() and
9+
inTry(ast.getParent()) and
10+
not parent instanceof Callable
11+
)
12+
}
13+
14+
private class ControlFlowGraphPluginSwift extends ControlFlowGraphPlugin {
15+
override predicate mayThrow(AstNode ast) { ast instanceof CallExpr and inTry(ast) }
16+
}

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

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,10 +19,22 @@
1919
| 28 | cfg.swift:28:1:45:1 | FunctionDeclaration | 'FunctionDeclaration' |
2020
| 28 | cfg.swift:28:15:28:15 | x | 'x -^ Block' |
2121
| 29 | cfg.swift:29:3:43:3 | TryExpr | 'TryExpr -V Block' |
22-
| 30 | cfg.swift:30:9:30:18 | mightThrow | 'mightThrow -> Argument -V 0 -^ CallExpr -^ try -^ UnaryExpr' |
22+
| 30 | cfg.swift:30:5:30:24 | try | 'try -^ UnaryExpr' |
23+
| 30 | cfg.swift:30:9:30:18 | mightThrow | 'mightThrow -> Argument -V 0 -^ CallExpr' |
2324
| 31 | cfg.swift:31:5:31:9 | print | 'print -> Argument -V "Did not throw." -^ CallExpr' |
2425
| 32 | cfg.swift:32:10:32:19 | mightThrow | 'mightThrow -> Argument -V 0 -^ CallExpr -^ try! -^ UnaryExpr' |
2526
| 33 | cfg.swift:33:5:33:9 | print | 'print -> Argument -V "Still did not throw." -^ CallExpr' |
27+
| 35 | cfg.swift:35:5:37:3 | CatchClause | 'CatchClause -V MyError -^ MemberAccessExpr -> isZero -> Argument -V x -^ CallExpr -? MyError -^ MemberAccessExpr -^ ConditionalPattern -^ OrPattern' |
28+
| 35 | cfg.swift:35:62:37:3 | Block | 'Block' |
29+
| 36 | cfg.swift:36:12:36:12 | 0 | '0 -^ ReturnExpr' |
30+
| 37 | cfg.swift:37:5:39:3 | CatchClause | 'CatchClause -V MyError -^ MemberAccessExpr -> Argument -V withParam -^ ExprPattern -^ CallExpr' |
31+
| 37 | cfg.swift:37:41:39:3 | Block | 'Block' |
32+
| 38 | cfg.swift:38:12:38:20 | withParam | 'withParam -^ ReturnExpr' |
33+
| 39 | cfg.swift:39:5:41:3 | CatchClause | 'CatchClause -V ' |
34+
| 39 | cfg.swift:39:22:41:3 | Block | 'Block' |
35+
| 40 | cfg.swift:40:5:40:9 | print | 'print -> Argument -V "MyError" -^ CallExpr' |
36+
| 41 | cfg.swift:41:5:43:3 | CatchClause | 'CatchClause -V Block' |
37+
| 42 | cfg.swift:42:5:42:9 | print | 'print -> Argument -V Unknown error -> interpolation -V Argument -V error -^ CallExpr -> -^ StringInterpolationExpr -^ CallExpr' |
2638
| 44 | cfg.swift:44:10:44:10 | 0 | '0 -^ ReturnExpr' |
2739
| 47 | cfg.swift:47:1:51:1 | FunctionDeclaration | 'FunctionDeclaration' |
2840
| 47 | cfg.swift:47:21:47:21 | s | 's -^ Block' |
@@ -311,7 +323,8 @@
311323
| 396 | cfg.swift:396:1:404:1 | FunctionDeclaration | 'FunctionDeclaration' |
312324
| 396 | cfg.swift:396:21:396:21 | x | 'x -^ Block' |
313325
| 397 | cfg.swift:397:3:402:3 | TryExpr | 'TryExpr -V Block' |
314-
| 398 | cfg.swift:398:9:398:18 | mightThrow | 'mightThrow -> Argument -V 0 -^ CallExpr -^ try -^ UnaryExpr' |
326+
| 398 | cfg.swift:398:5:398:24 | try | 'try -^ UnaryExpr' |
327+
| 398 | cfg.swift:398:9:398:18 | mightThrow | 'mightThrow -> Argument -V 0 -^ CallExpr' |
315328
| 399 | cfg.swift:399:5:399:9 | print | 'print -> Argument -V "Did not throw." -^ CallExpr' |
316329
| 400 | cfg.swift:400:10:400:19 | mightThrow | 'mightThrow -> Argument -V 0 -^ CallExpr -^ try! -^ UnaryExpr' |
317330
| 401 | cfg.swift:401:5:401:9 | print | 'print -> Argument -V "Still did not throw." -^ CallExpr' |

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

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,17 @@ bbContinues
44
| cfg.swift:525:78:525:78 | Block | 'Block goto Task(+2)' |
55
| cfg.swift:526:9:526:20 | continuation | 'continuation goto Block(-1)' |
66
bbStep
7+
| cfg.swift:30:9:30:24 | CallExpr | 'CallExpr : exception -> CatchClause(+5)' |
8+
| cfg.swift:30:9:30:24 | CallExpr | 'CallExpr : successor -> try(+0)' |
9+
| cfg.swift:33:5:33:33 | CallExpr | 'CallExpr : successor -> 0(+11)' |
10+
| cfg.swift:35:5:35:5 | OrPattern | 'OrPattern : match -> Block(+0)' |
11+
| cfg.swift:35:5:35:5 | OrPattern | 'OrPattern : no-match -> CatchClause(+2)' |
12+
| cfg.swift:37:11:37:39 | CallExpr | 'CallExpr : match -> Block(+0)' |
13+
| cfg.swift:37:11:37:39 | CallExpr | 'CallExpr : no-match -> CatchClause(+2)' |
14+
| cfg.swift:39:11:39:20 | | ' : match -> Block(+0)' |
15+
| cfg.swift:39:11:39:20 | | ' : no-match -> CatchClause(+2)' |
16+
| cfg.swift:40:5:40:20 | CallExpr | 'CallExpr : successor -> 0(+4)' |
17+
| cfg.swift:42:5:42:35 | CallExpr | 'CallExpr : successor -> 0(+2)' |
718
| cfg.swift:140:12:140:17 | BinaryExpr | 'BinaryExpr : empty -> SwitchExpr(+3)' |
819
| cfg.swift:140:12:140:17 | BinaryExpr | 'BinaryExpr : non-empty -> _(+0)' |
920
| cfg.swift:141:9:141:12 | Block | 'Block : successor -> SwitchExpr(+2)' |
@@ -80,6 +91,7 @@ bbStep
8091
| cfg.swift:360:3:360:3 | WhileStmt | 'WhileStmt : successor -> x(+0)' |
8192
| cfg.swift:360:9:360:14 | BinaryExpr | 'BinaryExpr : true -> Block(+0)' |
8293
| cfg.swift:361:5:361:10 | CompoundAssignExpr | 'CompoundAssignExpr : successor -> x(-1)' |
94+
| cfg.swift:398:9:398:24 | CallExpr | 'CallExpr : successor -> try(+0)' |
8395
| cfg.swift:500:6:500:28 | | ' : false -> IfExpr(+4)' |
8496
| cfg.swift:500:6:500:28 | | ' : true -> Block(+0)' |
8597
| cfg.swift:501:5:501:10 | CompoundAssignExpr | 'CompoundAssignExpr : successor -> IfExpr(+3)' |
@@ -116,13 +128,6 @@ bbStep
116128
noCfg
117129
| cfg.swift:23:9:23:9 | x |
118130
| cfg.swift:24:5:24:42 | ThrowExpr |
119-
| cfg.swift:35:11:35:17 | MyError |
120-
| cfg.swift:36:5:36:12 | ReturnExpr |
121-
| cfg.swift:37:11:37:17 | MyError |
122-
| cfg.swift:38:5:38:20 | ReturnExpr |
123-
| cfg.swift:39:11:39:20 | |
124-
| cfg.swift:40:5:40:9 | print |
125-
| cfg.swift:42:5:42:9 | print |
126131
| cfg.swift:47:42:47:47 | String |
127132
| cfg.swift:53:34:53:34 | _ |
128133
| cfg.swift:60:34:60:34 | _ |
@@ -152,6 +157,7 @@ noCfg
152157
| cfg.swift:559:6:559:20 | autoclosureTest |
153158
nonSimple
154159
| cfg.swift:10:1:10:1 | ClassLikeDeclaration | 'ClassLikeDeclaration -V MyError -^ BaseType -V Error' |
160+
| cfg.swift:35:5:35:5 | CatchClause | 'CatchClause -V MyError -^ MemberAccessExpr -> isZero -> Argument -V x -^ CallExpr -? MyError -^ MemberAccessExpr -^ ConditionalPattern -^ OrPattern' |
155161
| cfg.swift:209:5:209:5 | x | 'x -> x -? - -^ UnaryExpr -^ AssignExpr' |
156162
| cfg.swift:390:1:390:1 | ClassLikeDeclaration | 'ClassLikeDeclaration -V Derived -^ BaseType -V C' |
157163
| cfg.swift:527:13:527:16 | Task | 'Task -^ MemberAccessExpr -^ Argument -V FunctionExpr -^ CallExpr' |

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

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -27,19 +27,19 @@ func mightThrow(x : Int) throws -> Void {
2727

2828
func tryCatch(x : Int) -> Int {
2929
do {
30-
try mightThrow(x: 0)
30+
try mightThrow(x: 0) // $ bbStep='CallExpr : exception -> CatchClause(+5)' bbStep='CallExpr : successor -> try(+0)'
3131
print("Did not throw.")
3232
try! mightThrow(x: 0)
33-
print("Still did not throw.")
33+
print("Still did not throw.") // $ bbStep='CallExpr : successor -> 0(+11)'
3434

35-
} catch MyError.error1 , MyError.error2 where isZero(x: x) { // $ noCfg
36-
return 0 // $ noCfg
37-
} catch MyError.error3(let withParam) { // $ noCfg
38-
return withParam // $ noCfg
39-
} catch is MyError { // $ noCfg
40-
print("MyError") // $ noCfg
35+
} catch MyError.error1 , MyError.error2 where isZero(x: x) { // $ bbStep='OrPattern : match -> Block(+0)' bbStep='OrPattern : no-match -> CatchClause(+2)' nonSimple='CatchClause -V MyError -^ MemberAccessExpr -> isZero -> Argument -V x -^ CallExpr -? MyError -^ MemberAccessExpr -^ ConditionalPattern -^ OrPattern'
36+
return 0
37+
} catch MyError.error3(let withParam) { // $ bbStep='CallExpr : match -> Block(+0)' bbStep='CallExpr : no-match -> CatchClause(+2)'
38+
return withParam
39+
} catch is MyError { // $ bbStep=' : match -> Block(+0)' bbStep=' : no-match -> CatchClause(+2)'
40+
print("MyError") // $ bbStep='CallExpr : successor -> 0(+4)'
4141
} catch {
42-
print("Unknown error \(error)") // $ noCfg
42+
print("Unknown error \(error)") // $ bbStep='CallExpr : successor -> 0(+2)'
4343
}
4444
return 0
4545
}
@@ -395,7 +395,7 @@ class Derived : C { // $ nonSimple='ClassLikeDeclaration -V Derived -^ BaseType
395395

396396
func doWithoutCatch(x : Int) throws -> Int {
397397
do {
398-
try mightThrow(x: 0)
398+
try mightThrow(x: 0) // $ bbStep='CallExpr : successor -> try(+0)'
399399
print("Did not throw.")
400400
try! mightThrow(x: 0)
401401
print("Still did not throw.")

0 commit comments

Comments
 (0)