Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ module;
private import unified
private import codeql.controlflow.ControlFlowGraph
private import codeql.controlflow.SuccessorType
private import ControlFlowGraphPlugin

private module Cfg0 = Make0<Location, Ast>;

Expand Down Expand Up @@ -221,6 +222,8 @@ private module Ast implements AstSig<Location> {
}
}

private predicate mayThrow(AstNode ast) { any(ControlFlowGraphPlugin p).mayThrow(ast) }

private module Input implements InputSig1, InputSig2 {
private import codeql.util.Void

Expand Down Expand Up @@ -256,7 +259,10 @@ private module Input implements InputSig1, InputSig2 {
predicate beginAbruptCompletion(
AstNode ast, PreControlFlowNode n, AbruptCompletion c, boolean always
) {
none()
mayThrow(ast) and
n.isIn(ast) and
c.asSimpleAbruptCompletion() instanceof ExceptionSuccessor and
always = false
}

predicate endAbruptCompletion(AstNode ast, PreControlFlowNode n, AbruptCompletion c) { none() }
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
private import unified
private import codeql.util.Unit

private module Plugins {
private import ControlFlowGraphPluginSwift
}

class ControlFlowGraphPlugin extends Unit {
predicate mayThrow(AstNode ast) { none() }
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
private import unified
private import ControlFlowGraphPlugin

private predicate inTry(AstNode ast) {
ast.(UnaryExpr).getOperator().(Token).getValue() = "try"
or
exists(AstNode parent |
parent = ast.getParent() and
inTry(ast.getParent()) and
not parent instanceof Callable
)
}

private class ControlFlowGraphPluginSwift extends ControlFlowGraphPlugin {
override predicate mayThrow(AstNode ast) { ast instanceof CallExpr and inTry(ast) }
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,22 @@
| 28 | cfg.swift:28:1:45:1 | FunctionDeclaration | 'FunctionDeclaration' |
| 28 | cfg.swift:28:15:28:15 | x | 'x -^ Block' |
| 29 | cfg.swift:29:3:43:3 | TryExpr | 'TryExpr -V Block' |
| 30 | cfg.swift:30:9:30:18 | mightThrow | 'mightThrow -> Argument -V 0 -^ CallExpr -^ try -^ UnaryExpr' |
| 30 | cfg.swift:30:5:30:24 | try | 'try -^ UnaryExpr' |
| 30 | cfg.swift:30:9:30:18 | mightThrow | 'mightThrow -> Argument -V 0 -^ CallExpr' |
| 31 | cfg.swift:31:5:31:9 | print | 'print -> Argument -V "Did not throw." -^ CallExpr' |
| 32 | cfg.swift:32:10:32:19 | mightThrow | 'mightThrow -> Argument -V 0 -^ CallExpr -^ try! -^ UnaryExpr' |
| 33 | cfg.swift:33:5:33:9 | print | 'print -> Argument -V "Still did not throw." -^ CallExpr' |
| 35 | cfg.swift:35:5:37:3 | CatchClause | 'CatchClause -V MyError -^ MemberAccessExpr -> isZero -> Argument -V x -^ CallExpr -? MyError -^ MemberAccessExpr -^ ConditionalPattern -^ OrPattern' |
| 35 | cfg.swift:35:62:37:3 | Block | 'Block' |
| 36 | cfg.swift:36:12:36:12 | 0 | '0 -^ ReturnExpr' |
| 37 | cfg.swift:37:5:39:3 | CatchClause | 'CatchClause -V MyError -^ MemberAccessExpr -> Argument -V withParam -^ ExprPattern -^ CallExpr' |
| 37 | cfg.swift:37:41:39:3 | Block | 'Block' |
| 38 | cfg.swift:38:12:38:20 | withParam | 'withParam -^ ReturnExpr' |
| 39 | cfg.swift:39:5:41:3 | CatchClause | 'CatchClause -V ' |
| 39 | cfg.swift:39:22:41:3 | Block | 'Block' |
| 40 | cfg.swift:40:5:40:9 | print | 'print -> Argument -V "MyError" -^ CallExpr' |
| 41 | cfg.swift:41:5:43:3 | CatchClause | 'CatchClause -V Block' |
| 42 | cfg.swift:42:5:42:9 | print | 'print -> Argument -V Unknown error -> interpolation -V Argument -V error -^ CallExpr -> -^ StringInterpolationExpr -^ CallExpr' |
| 44 | cfg.swift:44:10:44:10 | 0 | '0 -^ ReturnExpr' |
| 47 | cfg.swift:47:1:51:1 | FunctionDeclaration | 'FunctionDeclaration' |
| 47 | cfg.swift:47:21:47:21 | s | 's -^ Block' |
Expand Down Expand Up @@ -311,7 +323,8 @@
| 396 | cfg.swift:396:1:404:1 | FunctionDeclaration | 'FunctionDeclaration' |
| 396 | cfg.swift:396:21:396:21 | x | 'x -^ Block' |
| 397 | cfg.swift:397:3:402:3 | TryExpr | 'TryExpr -V Block' |
| 398 | cfg.swift:398:9:398:18 | mightThrow | 'mightThrow -> Argument -V 0 -^ CallExpr -^ try -^ UnaryExpr' |
| 398 | cfg.swift:398:5:398:24 | try | 'try -^ UnaryExpr' |
| 398 | cfg.swift:398:9:398:18 | mightThrow | 'mightThrow -> Argument -V 0 -^ CallExpr' |
| 399 | cfg.swift:399:5:399:9 | print | 'print -> Argument -V "Did not throw." -^ CallExpr' |
| 400 | cfg.swift:400:10:400:19 | mightThrow | 'mightThrow -> Argument -V 0 -^ CallExpr -^ try! -^ UnaryExpr' |
| 401 | cfg.swift:401:5:401:9 | print | 'print -> Argument -V "Still did not throw." -^ CallExpr' |
Expand Down
20 changes: 13 additions & 7 deletions unified/ql/test/library-tests/controlflow/cfg.expected
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,17 @@ bbContinues
| cfg.swift:525:78:525:78 | Block | 'Block goto Task(+2)' |
| cfg.swift:526:9:526:20 | continuation | 'continuation goto Block(-1)' |
bbStep
| cfg.swift:30:9:30:24 | CallExpr | 'CallExpr : exception -> CatchClause(+5)' |
| cfg.swift:30:9:30:24 | CallExpr | 'CallExpr : successor -> try(+0)' |
| cfg.swift:33:5:33:33 | CallExpr | 'CallExpr : successor -> 0(+11)' |
| cfg.swift:35:5:35:5 | OrPattern | 'OrPattern : match -> Block(+0)' |
| cfg.swift:35:5:35:5 | OrPattern | 'OrPattern : no-match -> CatchClause(+2)' |
| cfg.swift:37:11:37:39 | CallExpr | 'CallExpr : match -> Block(+0)' |
| cfg.swift:37:11:37:39 | CallExpr | 'CallExpr : no-match -> CatchClause(+2)' |
| cfg.swift:39:11:39:20 | | ' : match -> Block(+0)' |
| cfg.swift:39:11:39:20 | | ' : no-match -> CatchClause(+2)' |
| cfg.swift:40:5:40:20 | CallExpr | 'CallExpr : successor -> 0(+4)' |
| cfg.swift:42:5:42:35 | CallExpr | 'CallExpr : successor -> 0(+2)' |
| cfg.swift:140:12:140:17 | BinaryExpr | 'BinaryExpr : empty -> SwitchExpr(+3)' |
| cfg.swift:140:12:140:17 | BinaryExpr | 'BinaryExpr : non-empty -> _(+0)' |
| cfg.swift:141:9:141:12 | Block | 'Block : successor -> SwitchExpr(+2)' |
Expand Down Expand Up @@ -80,6 +91,7 @@ bbStep
| cfg.swift:360:3:360:3 | WhileStmt | 'WhileStmt : successor -> x(+0)' |
| cfg.swift:360:9:360:14 | BinaryExpr | 'BinaryExpr : true -> Block(+0)' |
| cfg.swift:361:5:361:10 | CompoundAssignExpr | 'CompoundAssignExpr : successor -> x(-1)' |
| cfg.swift:398:9:398:24 | CallExpr | 'CallExpr : successor -> try(+0)' |
| cfg.swift:500:6:500:28 | | ' : false -> IfExpr(+4)' |
| cfg.swift:500:6:500:28 | | ' : true -> Block(+0)' |
| cfg.swift:501:5:501:10 | CompoundAssignExpr | 'CompoundAssignExpr : successor -> IfExpr(+3)' |
Expand Down Expand Up @@ -116,13 +128,6 @@ bbStep
noCfg
| cfg.swift:23:9:23:9 | x |
| cfg.swift:24:5:24:42 | ThrowExpr |
| cfg.swift:35:11:35:17 | MyError |
| cfg.swift:36:5:36:12 | ReturnExpr |
| cfg.swift:37:11:37:17 | MyError |
| cfg.swift:38:5:38:20 | ReturnExpr |
| cfg.swift:39:11:39:20 | |
| cfg.swift:40:5:40:9 | print |
| cfg.swift:42:5:42:9 | print |
| cfg.swift:47:42:47:47 | String |
| cfg.swift:53:34:53:34 | _ |
| cfg.swift:60:34:60:34 | _ |
Expand Down Expand Up @@ -152,6 +157,7 @@ noCfg
| cfg.swift:559:6:559:20 | autoclosureTest |
nonSimple
| cfg.swift:10:1:10:1 | ClassLikeDeclaration | 'ClassLikeDeclaration -V MyError -^ BaseType -V Error' |
| cfg.swift:35:5:35:5 | CatchClause | 'CatchClause -V MyError -^ MemberAccessExpr -> isZero -> Argument -V x -^ CallExpr -? MyError -^ MemberAccessExpr -^ ConditionalPattern -^ OrPattern' |
| cfg.swift:209:5:209:5 | x | 'x -> x -? - -^ UnaryExpr -^ AssignExpr' |
| cfg.swift:390:1:390:1 | ClassLikeDeclaration | 'ClassLikeDeclaration -V Derived -^ BaseType -V C' |
| cfg.swift:527:13:527:16 | Task | 'Task -^ MemberAccessExpr -^ Argument -V FunctionExpr -^ CallExpr' |
Expand Down
20 changes: 10 additions & 10 deletions unified/ql/test/library-tests/controlflow/cfg.swift
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,19 @@ func mightThrow(x : Int) throws -> Void {

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

} catch MyError.error1 , MyError.error2 where isZero(x: x) { // $ noCfg
return 0 // $ noCfg
} catch MyError.error3(let withParam) { // $ noCfg
return withParam // $ noCfg
} catch is MyError { // $ noCfg
print("MyError") // $ noCfg
} 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'
return 0
} catch MyError.error3(let withParam) { // $ bbStep='CallExpr : match -> Block(+0)' bbStep='CallExpr : no-match -> CatchClause(+2)'
return withParam
} catch is MyError { // $ bbStep=' : match -> Block(+0)' bbStep=' : no-match -> CatchClause(+2)'
print("MyError") // $ bbStep='CallExpr : successor -> 0(+4)'
} catch {
print("Unknown error \(error)") // $ noCfg
print("Unknown error \(error)") // $ bbStep='CallExpr : successor -> 0(+2)'
}
return 0
}
Expand Down Expand Up @@ -395,7 +395,7 @@ class Derived : C { // $ nonSimple='ClassLikeDeclaration -V Derived -^ BaseType

func doWithoutCatch(x : Int) throws -> Int {
do {
try mightThrow(x: 0)
try mightThrow(x: 0) // $ bbStep='CallExpr : successor -> try(+0)'
print("Did not throw.")
try! mightThrow(x: 0)
print("Still did not throw.")
Expand Down
Loading