Merge pull request #14398 from rdmarsh2/rdmarsh2/swift/autoclosure-cfg

Swift: add CFG for normal autoclosures
This commit is contained in:
Robert Marsh
2023-10-17 11:50:24 -04:00
committed by GitHub
14 changed files with 147 additions and 11 deletions

View File

@@ -125,7 +125,6 @@ lib/codeql/swift/elements/expr/ErrorExpr.qll 8a68131297e574625a22fbbb28f3f09097e
lib/codeql/swift/elements/expr/ErrorExprConstructor.qll dd2bec0e35121e0a65d47600100834963a7695c268e3832aad513e70b1b92a75 e85dcf686403511c5f72b25ae9cf62f77703575137c39610e61562efc988bbac
lib/codeql/swift/elements/expr/ExistentialMetatypeToObjectExpr.qll 420d534f76e192e89f29c71a7282e0697d259c00a7edc3e168ca895b0dc4f1d1 c0b5811c8665f3324b04d40f5952a62e631ec4b3f00db8e9cc13cb5d60028178
lib/codeql/swift/elements/expr/ExistentialMetatypeToObjectExprConstructor.qll 1a735425a59f8a2bd208a845e3b4fc961632c82db3b69d0b71a1bc2875090f3b 769b6a80a451c64cbf9ce09729b34493a59330d4ef54ab0d51d8ff81305b680f
lib/codeql/swift/elements/expr/ExplicitClosureExpr.qll 77626fd66735b1954e6ec80a50a36ce94dd725110a5051ab4034600c8ce5ca6f 4e169380503b98d00efd9f38e549621c21971ed9e92dbce601fb46df2f44de78
lib/codeql/swift/elements/expr/ExplicitClosureExprConstructor.qll 171d9f028bfb80754ddc917d0f6a24185d30643c6c2c80a8a5681dba16a4c48e 0e560df706726c7d45ea95532a9e4df00c03e860b840179f973bab8009c437ab
lib/codeql/swift/elements/expr/FloatLiteralExprConstructor.qll 4dfb34d32e4022b55caadcfbe147e94ebe771395c59f137228213a51a744ba10 1eb78fcda9e0b70d1993e02408fb6032035991bf937c4267149ab9c7c6a99d3a
lib/codeql/swift/elements/expr/ForceTryExprConstructor.qll 48cbc408bb34a50558d25aa092188e1ad0f68d83e98836e05072037f3d8b49af 62ce7b92410bf712ecd49d3eb7dd9b195b9157415713aaf59712542339f37e4c

1
swift/ql/.gitattributes generated vendored
View File

@@ -127,7 +127,6 @@
/lib/codeql/swift/elements/expr/ErrorExprConstructor.qll linguist-generated
/lib/codeql/swift/elements/expr/ExistentialMetatypeToObjectExpr.qll linguist-generated
/lib/codeql/swift/elements/expr/ExistentialMetatypeToObjectExprConstructor.qll linguist-generated
/lib/codeql/swift/elements/expr/ExplicitClosureExpr.qll linguist-generated
/lib/codeql/swift/elements/expr/ExplicitClosureExprConstructor.qll linguist-generated
/lib/codeql/swift/elements/expr/FloatLiteralExprConstructor.qll linguist-generated
/lib/codeql/swift/elements/expr/ForceTryExprConstructor.qll linguist-generated

View File

@@ -0,0 +1,5 @@
---
category: minorAnalysis
---
* The contents of autoclosure function parameters are now included in the control flow graph and data flow libraries.

View File

@@ -4,7 +4,7 @@ cached
newtype TControlFlowElement =
TAstElement(AstNode n) or
TFuncDeclElement(Function func) { func.hasBody() } or
TClosureElement(ExplicitClosureExpr clos) or
TClosureElement(ClosureExpr clos) { isNormalAutoClosureOrExplicitClosure(clos) } or
TPropertyGetterElement(Decl accessor, Expr ref) { isPropertyGetterElement(accessor, ref) } or
TPropertySetterElement(Accessor accessor, AssignExpr assign) {
isPropertySetterElement(accessor, assign)
@@ -41,6 +41,15 @@ predicate isPropertyGetterElement(PropertyGetterElement pge, Accessor accessor,
pge = TPropertyGetterElement(accessor, ref)
}
predicate isNormalAutoClosureOrExplicitClosure(ClosureExpr clos) {
// short-circuiting operators have a `BinaryExpr` as the parent of the `AutoClosureExpr`,
// so we exclude them by checking for a `CallExpr`.
clos instanceof AutoClosureExpr and
exists(CallExpr call | call.getAnArgument().getExpr() = clos)
or
clos instanceof ExplicitClosureExpr
}
private predicate hasDirectToImplementationSemantics(Expr e) {
e.(MemberRefExpr).hasDirectToImplementationSemantics()
or
@@ -194,14 +203,18 @@ class KeyPathElement extends ControlFlowElement, TKeyPathElement {
override string toString() { result = expr.toString() }
}
/**
* A control flow element representing a closure in its role as a control flow
* scope.
*/
class ClosureElement extends ControlFlowElement, TClosureElement {
ExplicitClosureExpr expr;
ClosureExpr expr;
ClosureElement() { this = TClosureElement(expr) }
override Location getLocation() { result = expr.getLocation() }
ExplicitClosureExpr getAst() { result = expr }
ClosureExpr getAst() { result = expr }
override string toString() { result = expr.toString() }
}

View File

@@ -67,10 +67,13 @@ module CfgScope {
final override predicate exit(ControlFlowElement last, Completion c) { last(tree, last, c) }
}
private class ClosureExprScope extends Range_ instanceof ExplicitClosureExpr {
private class ClosureExprScope extends Range_ instanceof ClosureExpr {
Exprs::ClosureExprTree tree;
ClosureExprScope() { tree.getAst() = this }
ClosureExprScope() {
isNormalAutoClosureOrExplicitClosure(this) and
tree.getAst() = this
}
final override predicate entry(ControlFlowElement first) { first(tree, first) }
@@ -1145,12 +1148,16 @@ module Exprs {
}
}
/**
* The control flow for an explicit closure or a normal autoclosure in its
* role as a control flow scope.
*/
class ClosureExprTree extends StandardPreOrderTree, TClosureElement {
ExplicitClosureExpr expr;
ClosureExpr expr;
ClosureExprTree() { this = TClosureElement(expr) }
ExplicitClosureExpr getAst() { result = expr }
ClosureExpr getAst() { result = expr }
final override ControlFlowElement getChildElement(int i) {
result.asAstNode() = expr.getParam(i)

View File

@@ -4,7 +4,8 @@ private import codeql.swift.elements.expr.Expr
/**
* A Swift autoclosure expression, that is, a closure automatically generated
* around an argument when the parameter has the `@autoclosure` attribute. For
* around an argument when the parameter has the `@autoclosure` attribute or
* for the right-hand operand of short-circuiting logical operations. For
* example, there is an `AutoClosureExpr` around the value `0` in:
* ```
* func myFunction(_ expr: @autoclosure () -> Int) {

View File

@@ -1,4 +1,8 @@
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
private import codeql.swift.generated.expr.ExplicitClosureExpr
/**
* A Swift explicit closure expr, that is, a closure written using
* `{ ... -> ... in ... }` syntax rather than automatically generated by the
* compiler.
*/
class ExplicitClosureExpr extends Generated::ExplicitClosureExpr { }

View File

@@ -3366,6 +3366,24 @@ cfg.swift:
# 545| getElse(): [BraceStmt] { ... }
# 546| getElement(0): [ReturnStmt] return ...
# 546| getResult(): [IntegerLiteralExpr] 0
# 550| [NamedFunction] usesAutoclosure(_:)
# 550| InterfaceType = (@autoclosure () -> Int) -> Int
# 550| getParam(0): [ParamDecl] expr
# 550| Type = () -> Int
# 550| getBody(): [BraceStmt] { ... }
# 551| getElement(0): [ReturnStmt] return ...
# 551| getResult(): [CallExpr] call to ...
# 551| getFunction(): [DeclRefExpr] expr
# 554| [NamedFunction] autoclosureTest()
# 554| InterfaceType = () -> ()
# 554| getBody(): [BraceStmt] { ... }
# 555| getElement(0): [CallExpr] call to usesAutoclosure(_:)
# 555| getFunction(): [DeclRefExpr] usesAutoclosure(_:)
# 555| getArgument(0): [Argument] : { ... }
# 555| getExpr(): [AutoClosureExpr] { ... }
# 555| getBody(): [BraceStmt] { ... }
# 555| getElement(0): [ReturnStmt] return ...
# 555| getResult(): [IntegerLiteralExpr] 1
declarations.swift:
# 1| [StructDecl] Foo
# 2| getMember(0): [PatternBindingDecl] var ... = ...

View File

@@ -546,3 +546,11 @@ func testNilCoalescing2(x: Bool?) -> Int {
return 0
}
}
func usesAutoclosure(_ expr: @autoclosure () -> Int) -> Int {
return expr()
}
func autoclosureTest() {
usesAutoclosure(1)
}

View File

@@ -6317,3 +6317,63 @@ cfg.swift:
# 546| 0
#-----| -> return ...
# 550| enter usesAutoclosure(_:)
#-----| -> usesAutoclosure(_:)
# 550| exit usesAutoclosure(_:)
# 550| exit usesAutoclosure(_:) (normal)
#-----| -> exit usesAutoclosure(_:)
# 550| usesAutoclosure(_:)
#-----| -> expr
# 550| expr
#-----| -> expr
# 551| return ...
#-----| return -> exit usesAutoclosure(_:) (normal)
# 551| expr
#-----| -> call to ...
# 551| call to ...
#-----| -> return ...
# 554| autoclosureTest()
#-----| -> usesAutoclosure(_:)
# 554| enter autoclosureTest()
#-----| -> autoclosureTest()
# 554| exit autoclosureTest()
# 554| exit autoclosureTest() (normal)
#-----| -> exit autoclosureTest()
# 555| usesAutoclosure(_:)
#-----| -> { ... }
# 555| call to usesAutoclosure(_:)
#-----| -> exit autoclosureTest() (normal)
# 555| 1
#-----| -> return ...
# 555| enter { ... }
#-----| -> { ... }
# 555| exit { ... }
# 555| exit { ... } (normal)
#-----| -> exit { ... }
# 555| return ...
#-----| -> exit { ... } (normal)
# 555| { ... }
#-----| -> 1
# 555| { ... }
#-----| -> call to usesAutoclosure(_:)

View File

@@ -546,3 +546,11 @@ func testNilCoalescing2(x: Bool?) -> Int {
return 0
}
}
func usesAutoclosure(_ expr: @autoclosure () -> Int) -> Int {
return expr()
}
func autoclosureTest() {
usesAutoclosure(1)
}

View File

@@ -603,6 +603,7 @@ edges
| test.swift:883:21:883:39 | call to makeIterator() [Collection element] | test.swift:884:15:884:15 | generator [Collection element] |
| test.swift:884:15:884:15 | generator [Collection element] | test.swift:884:15:884:30 | call to next() [some:0] |
| test.swift:884:15:884:30 | call to next() [some:0] | test.swift:884:15:884:31 | ...! |
| test.swift:908:19:908:26 | call to source() | test.swift:904:13:904:18 | call to ... |
nodes
| file://:0:0:0:0 | .a [x] | semmle.label | .a [x] |
| file://:0:0:0:0 | .s [x] | semmle.label | .s [x] |
@@ -1251,6 +1252,8 @@ nodes
| test.swift:884:15:884:15 | generator [Collection element] | semmle.label | generator [Collection element] |
| test.swift:884:15:884:30 | call to next() [some:0] | semmle.label | call to next() [some:0] |
| test.swift:884:15:884:31 | ...! | semmle.label | ...! |
| test.swift:904:13:904:18 | call to ... | semmle.label | call to ... |
| test.swift:908:19:908:26 | call to source() | semmle.label | call to source() |
subpaths
| test.swift:75:22:75:22 | x | test.swift:65:16:65:28 | arg1 | test.swift:65:1:70:1 | arg2[return] | test.swift:75:32:75:32 | [post] y |
| test.swift:114:19:114:19 | arg | test.swift:109:9:109:14 | arg | test.swift:110:12:110:12 | arg | test.swift:114:12:114:22 | call to ... |
@@ -1448,3 +1451,4 @@ subpaths
| test.swift:867:15:867:38 | \\...[...] | test.swift:873:24:873:31 | call to source() | test.swift:867:15:867:38 | \\...[...] | result |
| test.swift:880:19:880:19 | elem | test.swift:877:21:877:28 | call to source() | test.swift:880:19:880:19 | elem | result |
| test.swift:884:15:884:31 | ...! | test.swift:877:21:877:28 | call to source() | test.swift:884:15:884:31 | ...! | result |
| test.swift:904:13:904:18 | call to ... | test.swift:908:19:908:26 | call to source() | test.swift:904:13:904:18 | call to ... | result |

View File

@@ -1145,3 +1145,5 @@
| test.swift:898:24:898:24 | $i$generator | test.swift:898:24:898:24 | SSA def($i$generator) |
| test.swift:898:24:898:24 | SSA def($i$generator) | test.swift:898:5:898:5 | $i$generator |
| test.swift:898:24:898:24 | call to makeAsyncIterator() | test.swift:898:24:898:24 | $i$generator |
| test.swift:903:22:903:49 | SSA def(expr) | test.swift:904:13:904:13 | expr |
| test.swift:903:22:903:49 | expr | test.swift:903:22:903:49 | SSA def(expr) |

View File

@@ -898,4 +898,12 @@ func testAsyncFor () async {
for try await i in stream {
sink(arg: i) // $ MISSING: flow=892
}
}
func usesAutoclosure(_ expr: @autoclosure () -> Int) {
sink(arg: expr()) // $ flow=908
}
func autoclosureTest() {
usesAutoclosure(source())
}