Skip to content

Commit c4521a3

Browse files
authored
Merge pull request github#14113 from geoffw0/implicitflow
Swift: Flow through OpenExistentialExpr
2 parents 4e08ba6 + 1929dea commit c4521a3

File tree

12 files changed

+424
-7
lines changed

12 files changed

+424
-7
lines changed
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
5+
* Flow through 'open existential expressions', implicit expressions created by the compiler when a method is called on a protocol. This may apply, for example, when the method is a modelled taint source.

swift/ql/lib/codeql/swift/dataflow/internal/DataFlowPrivate.qll

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -261,6 +261,9 @@ private module Cached {
261261
nodeFrom.asExpr() = ie.getBranch(_)
262262
)
263263
or
264+
// flow through OpenExistentialExpr (compiler generated expression wrapper)
265+
nodeFrom.asExpr() = nodeTo.asExpr().(OpenExistentialExpr).getSubExpr()
266+
or
264267
// flow from Expr to Pattern
265268
exists(Expr e, Pattern p |
266269
nodeFrom.asExpr() = e and

swift/ql/test/extractor-tests/statements/statements.swift

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,5 +91,3 @@ if #available(macOS 155, *) {
9191
if #unavailable(macOS 42) {
9292
print(42)
9393
}
94-
95-

swift/ql/test/library-tests/ast/PrintAst.expected

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3384,6 +3384,100 @@ cfg.swift:
33843384
# 555| getBody(): [BraceStmt] { ... }
33853385
# 555| getElement(0): [ReturnStmt] return ...
33863386
# 555| getResult(): [IntegerLiteralExpr] 1
3387+
# 558| [Comment] // ---
3388+
# 558|
3389+
# 560| [ProtocolDecl] MyProtocol
3390+
#-----| getGenericTypeParam(0): [GenericTypeParamDecl] Self
3391+
# 561| getMember(0): [NamedFunction] source()
3392+
# 561| InterfaceType = <Self where Self : MyProtocol> (Self) -> () -> Int
3393+
# 561| getSelfParam(): [ParamDecl] self
3394+
# 561| Type = Self
3395+
# 564| [ClassDecl] MyProcotolImpl
3396+
# 565| getMember(0): [NamedFunction] source()
3397+
# 565| InterfaceType = (MyProcotolImpl) -> () -> Int
3398+
# 565| getSelfParam(): [ParamDecl] self
3399+
# 565| Type = MyProcotolImpl
3400+
# 565| getBody(): [BraceStmt] { ... }
3401+
# 565| getElement(0): [ReturnStmt] return ...
3402+
# 565| getResult(): [IntegerLiteralExpr] 0
3403+
# 564| getMember(1): [Deinitializer] MyProcotolImpl.deinit()
3404+
# 564| InterfaceType = (MyProcotolImpl) -> () -> ()
3405+
# 564| getSelfParam(): [ParamDecl] self
3406+
# 564| Type = MyProcotolImpl
3407+
# 564| getBody(): [BraceStmt] { ... }
3408+
# 564| getMember(2): [Initializer] MyProcotolImpl.init()
3409+
# 564| InterfaceType = (MyProcotolImpl.Type) -> () -> MyProcotolImpl
3410+
# 564| getSelfParam(): [ParamDecl] self
3411+
# 564| Type = MyProcotolImpl
3412+
# 564| getBody(): [BraceStmt] { ... }
3413+
# 564| getElement(0): [ReturnStmt] return
3414+
# 568| [NamedFunction] getMyProtocol()
3415+
# 568| InterfaceType = () -> MyProtocol
3416+
# 568| getBody(): [BraceStmt] { ... }
3417+
# 568| getElement(0): [ReturnStmt] return ...
3418+
# 568| getResult(): [CallExpr] call to MyProcotolImpl.init()
3419+
# 568| getFunction(): [MethodLookupExpr] MyProcotolImpl.init()
3420+
# 568| getBase(): [TypeExpr] MyProcotolImpl.Type
3421+
# 568| getTypeRepr(): [TypeRepr] MyProcotolImpl
3422+
# 568| getMethodRef(): [DeclRefExpr] MyProcotolImpl.init()
3423+
# 568| getResult().getFullyConverted(): [ErasureExpr] (MyProtocol) ...
3424+
# 569| [NamedFunction] getMyProtocolImpl()
3425+
# 569| InterfaceType = () -> MyProcotolImpl
3426+
# 569| getBody(): [BraceStmt] { ... }
3427+
# 569| getElement(0): [ReturnStmt] return ...
3428+
# 569| getResult(): [CallExpr] call to MyProcotolImpl.init()
3429+
# 569| getFunction(): [MethodLookupExpr] MyProcotolImpl.init()
3430+
# 569| getBase(): [TypeExpr] MyProcotolImpl.Type
3431+
# 569| getTypeRepr(): [TypeRepr] MyProcotolImpl
3432+
# 569| getMethodRef(): [DeclRefExpr] MyProcotolImpl.init()
3433+
# 571| [NamedFunction] sink(arg:)
3434+
# 571| InterfaceType = (Int) -> ()
3435+
# 571| getParam(0): [ParamDecl] arg
3436+
# 571| Type = Int
3437+
# 571| getBody(): [BraceStmt] { ... }
3438+
# 573| [NamedFunction] testOpenExistentialExpr(x:y:)
3439+
# 573| InterfaceType = (MyProtocol, MyProcotolImpl) -> ()
3440+
# 573| getParam(0): [ParamDecl] x
3441+
# 573| Type = MyProtocol
3442+
# 573| getParam(1): [ParamDecl] y
3443+
# 573| Type = MyProcotolImpl
3444+
# 573| getBody(): [BraceStmt] { ... }
3445+
# 574| getElement(0): [CallExpr] call to sink(arg:)
3446+
# 574| getFunction(): [DeclRefExpr] sink(arg:)
3447+
# 574| getArgument(0): [Argument] arg: OpenExistentialExpr
3448+
# 574| getExpr(): [OpenExistentialExpr] OpenExistentialExpr
3449+
# 574| getSubExpr(): [CallExpr] call to source()
3450+
# 574| getFunction(): [MethodLookupExpr] .source()
3451+
# 574| getBase(): [OpaqueValueExpr] OpaqueValueExpr
3452+
# 574| getMethodRef(): [DeclRefExpr] source()
3453+
# 574| getExistential(): [DeclRefExpr] x
3454+
# 575| getElement(1): [CallExpr] call to sink(arg:)
3455+
# 575| getFunction(): [DeclRefExpr] sink(arg:)
3456+
# 575| getArgument(0): [Argument] arg: call to source()
3457+
# 575| getExpr(): [CallExpr] call to source()
3458+
# 575| getFunction(): [MethodLookupExpr] .source()
3459+
# 575| getBase(): [DeclRefExpr] y
3460+
# 575| getMethodRef(): [DeclRefExpr] source()
3461+
# 576| getElement(2): [CallExpr] call to sink(arg:)
3462+
# 576| getFunction(): [DeclRefExpr] sink(arg:)
3463+
# 576| getArgument(0): [Argument] arg: OpenExistentialExpr
3464+
# 576| getExpr(): [OpenExistentialExpr] OpenExistentialExpr
3465+
# 576| getSubExpr(): [CallExpr] call to source()
3466+
# 576| getFunction(): [MethodLookupExpr] .source()
3467+
# 576| getBase(): [OpaqueValueExpr] OpaqueValueExpr
3468+
# 576| getMethodRef(): [DeclRefExpr] source()
3469+
# 576| getExistential(): [CallExpr] call to getMyProtocol()
3470+
# 576| getFunction(): [DeclRefExpr] getMyProtocol()
3471+
# 577| getElement(3): [CallExpr] call to sink(arg:)
3472+
# 577| getFunction(): [DeclRefExpr] sink(arg:)
3473+
# 577| getArgument(0): [Argument] arg: call to source()
3474+
# 577| getExpr(): [CallExpr] call to source()
3475+
# 577| getFunction(): [MethodLookupExpr] .source()
3476+
# 577| getBase(): [CallExpr] call to getMyProtocolImpl()
3477+
# 577| getFunction(): [DeclRefExpr] getMyProtocolImpl()
3478+
# 577| getMethodRef(): [DeclRefExpr] source()
3479+
# 580| [Comment] // ---
3480+
# 580|
33873481
declarations.swift:
33883482
# 1| [StructDecl] Foo
33893483
# 2| getMember(0): [PatternBindingDecl] var ... = ...

swift/ql/test/library-tests/ast/cfg.swift

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -554,3 +554,27 @@ func usesAutoclosure(_ expr: @autoclosure () -> Int) -> Int {
554554
func autoclosureTest() {
555555
usesAutoclosure(1)
556556
}
557+
558+
// ---
559+
560+
protocol MyProtocol {
561+
func source() -> Int
562+
}
563+
564+
class MyProcotolImpl : MyProtocol {
565+
func source() -> Int { return 0 }
566+
}
567+
568+
func getMyProtocol() -> MyProtocol { return MyProcotolImpl() }
569+
func getMyProtocolImpl() -> MyProcotolImpl { return MyProcotolImpl() }
570+
571+
func sink(arg: Int) { }
572+
573+
func testOpenExistentialExpr(x: MyProtocol, y: MyProcotolImpl) {
574+
sink(arg: x.source())
575+
sink(arg: y.source())
576+
sink(arg: getMyProtocol().source())
577+
sink(arg: getMyProtocolImpl().source())
578+
}
579+
580+
// ---

swift/ql/test/library-tests/ast/statements.swift

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -91,5 +91,3 @@ if #available(macOS 155, *) {
9191
if #unavailable(macOS 42) {
9292
print(42)
9393
}
94-
95-

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

Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6377,3 +6377,218 @@ cfg.swift:
63776377

63786378
# 555| { ... }
63796379
#-----| -> call to usesAutoclosure(_:)
6380+
6381+
# 564| MyProcotolImpl.deinit()
6382+
#-----| -> self
6383+
6384+
# 564| MyProcotolImpl.init()
6385+
#-----| -> self
6386+
6387+
# 564| enter MyProcotolImpl.deinit()
6388+
#-----| -> MyProcotolImpl.deinit()
6389+
6390+
# 564| enter MyProcotolImpl.init()
6391+
#-----| -> MyProcotolImpl.init()
6392+
6393+
# 564| exit MyProcotolImpl.deinit()
6394+
6395+
# 564| exit MyProcotolImpl.deinit() (normal)
6396+
#-----| -> exit MyProcotolImpl.deinit()
6397+
6398+
# 564| exit MyProcotolImpl.init()
6399+
6400+
# 564| exit MyProcotolImpl.init() (normal)
6401+
#-----| -> exit MyProcotolImpl.init()
6402+
6403+
# 564| return
6404+
#-----| return -> exit MyProcotolImpl.init() (normal)
6405+
6406+
# 564| self
6407+
#-----| -> { ... }
6408+
6409+
# 564| self
6410+
#-----| -> return
6411+
6412+
# 564| { ... }
6413+
#-----| -> exit MyProcotolImpl.deinit() (normal)
6414+
6415+
# 565| enter source()
6416+
#-----| -> source()
6417+
6418+
# 565| exit source()
6419+
6420+
# 565| exit source() (normal)
6421+
#-----| -> exit source()
6422+
6423+
# 565| source()
6424+
#-----| -> self
6425+
6426+
# 565| self
6427+
#-----| -> 0
6428+
6429+
# 565| return ...
6430+
#-----| return -> exit source() (normal)
6431+
6432+
# 565| 0
6433+
#-----| -> return ...
6434+
6435+
# 568| enter getMyProtocol()
6436+
#-----| -> getMyProtocol()
6437+
6438+
# 568| exit getMyProtocol()
6439+
6440+
# 568| exit getMyProtocol() (normal)
6441+
#-----| -> exit getMyProtocol()
6442+
6443+
# 568| getMyProtocol()
6444+
#-----| -> MyProcotolImpl.init()
6445+
6446+
# 568| return ...
6447+
#-----| return -> exit getMyProtocol() (normal)
6448+
6449+
# 568| MyProcotolImpl.Type
6450+
#-----| -> call to MyProcotolImpl.init()
6451+
6452+
# 568| MyProcotolImpl.init()
6453+
#-----| -> MyProcotolImpl.Type
6454+
6455+
# 568| (MyProtocol) ...
6456+
#-----| -> return ...
6457+
6458+
# 568| call to MyProcotolImpl.init()
6459+
#-----| -> (MyProtocol) ...
6460+
6461+
# 569| enter getMyProtocolImpl()
6462+
#-----| -> getMyProtocolImpl()
6463+
6464+
# 569| exit getMyProtocolImpl()
6465+
6466+
# 569| exit getMyProtocolImpl() (normal)
6467+
#-----| -> exit getMyProtocolImpl()
6468+
6469+
# 569| getMyProtocolImpl()
6470+
#-----| -> MyProcotolImpl.init()
6471+
6472+
# 569| return ...
6473+
#-----| return -> exit getMyProtocolImpl() (normal)
6474+
6475+
# 569| MyProcotolImpl.Type
6476+
#-----| -> call to MyProcotolImpl.init()
6477+
6478+
# 569| MyProcotolImpl.init()
6479+
#-----| -> MyProcotolImpl.Type
6480+
6481+
# 569| call to MyProcotolImpl.init()
6482+
#-----| -> return ...
6483+
6484+
# 571| enter sink(arg:)
6485+
#-----| -> sink(arg:)
6486+
6487+
# 571| exit sink(arg:)
6488+
6489+
# 571| exit sink(arg:) (normal)
6490+
#-----| -> exit sink(arg:)
6491+
6492+
# 571| sink(arg:)
6493+
#-----| -> arg
6494+
6495+
# 571| arg
6496+
#-----| -> { ... }
6497+
6498+
# 571| { ... }
6499+
#-----| -> exit sink(arg:) (normal)
6500+
6501+
# 573| enter testOpenExistentialExpr(x:y:)
6502+
#-----| -> testOpenExistentialExpr(x:y:)
6503+
6504+
# 573| exit testOpenExistentialExpr(x:y:)
6505+
6506+
# 573| exit testOpenExistentialExpr(x:y:) (normal)
6507+
#-----| -> exit testOpenExistentialExpr(x:y:)
6508+
6509+
# 573| testOpenExistentialExpr(x:y:)
6510+
#-----| -> x
6511+
6512+
# 573| x
6513+
#-----| -> y
6514+
6515+
# 573| y
6516+
#-----| -> sink(arg:)
6517+
6518+
# 574| sink(arg:)
6519+
#-----| -> x
6520+
6521+
# 574| call to sink(arg:)
6522+
#-----| -> sink(arg:)
6523+
6524+
# 574| OpaqueValueExpr
6525+
#-----| -> call to source()
6526+
6527+
# 574| x
6528+
#-----| -> .source()
6529+
6530+
# 574| .source()
6531+
#-----| -> OpaqueValueExpr
6532+
6533+
# 574| OpenExistentialExpr
6534+
#-----| -> call to sink(arg:)
6535+
6536+
# 574| call to source()
6537+
#-----| -> OpenExistentialExpr
6538+
6539+
# 575| sink(arg:)
6540+
#-----| -> .source()
6541+
6542+
# 575| call to sink(arg:)
6543+
#-----| -> sink(arg:)
6544+
6545+
# 575| y
6546+
#-----| -> call to source()
6547+
6548+
# 575| .source()
6549+
#-----| -> y
6550+
6551+
# 575| call to source()
6552+
#-----| -> call to sink(arg:)
6553+
6554+
# 576| sink(arg:)
6555+
#-----| -> getMyProtocol()
6556+
6557+
# 576| call to sink(arg:)
6558+
#-----| -> sink(arg:)
6559+
6560+
# 576| getMyProtocol()
6561+
#-----| -> call to getMyProtocol()
6562+
6563+
# 576| OpaqueValueExpr
6564+
#-----| -> call to source()
6565+
6566+
# 576| call to getMyProtocol()
6567+
#-----| -> .source()
6568+
6569+
# 576| .source()
6570+
#-----| -> OpaqueValueExpr
6571+
6572+
# 576| OpenExistentialExpr
6573+
#-----| -> call to sink(arg:)
6574+
6575+
# 576| call to source()
6576+
#-----| -> OpenExistentialExpr
6577+
6578+
# 577| sink(arg:)
6579+
#-----| -> .source()
6580+
6581+
# 577| call to sink(arg:)
6582+
#-----| -> exit testOpenExistentialExpr(x:y:) (normal)
6583+
6584+
# 577| getMyProtocolImpl()
6585+
#-----| -> call to getMyProtocolImpl()
6586+
6587+
# 577| call to getMyProtocolImpl()
6588+
#-----| -> call to source()
6589+
6590+
# 577| .source()
6591+
#-----| -> getMyProtocolImpl()
6592+
6593+
# 577| call to source()
6594+
#-----| -> call to sink(arg:)

0 commit comments

Comments
 (0)