Skip to content

Commit

Permalink
Merge pull request #14113 from geoffw0/implicitflow
Browse files Browse the repository at this point in the history
Swift: Flow through OpenExistentialExpr
  • Loading branch information
MathiasVP authored Oct 30, 2023
2 parents 4e08ba6 + 1929dea commit c4521a3
Show file tree
Hide file tree
Showing 12 changed files with 424 additions and 7 deletions.
5 changes: 5 additions & 0 deletions swift/ql/lib/change-notes/2023-08-31-open-existential-expr.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
category: minorAnalysis
---

* 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.
Original file line number Diff line number Diff line change
Expand Up @@ -261,6 +261,9 @@ private module Cached {
nodeFrom.asExpr() = ie.getBranch(_)
)
or
// flow through OpenExistentialExpr (compiler generated expression wrapper)
nodeFrom.asExpr() = nodeTo.asExpr().(OpenExistentialExpr).getSubExpr()
or
// flow from Expr to Pattern
exists(Expr e, Pattern p |
nodeFrom.asExpr() = e and
Expand Down
2 changes: 0 additions & 2 deletions swift/ql/test/extractor-tests/statements/statements.swift
Original file line number Diff line number Diff line change
Expand Up @@ -91,5 +91,3 @@ if #available(macOS 155, *) {
if #unavailable(macOS 42) {
print(42)
}


94 changes: 94 additions & 0 deletions swift/ql/test/library-tests/ast/PrintAst.expected
Original file line number Diff line number Diff line change
Expand Up @@ -3384,6 +3384,100 @@ cfg.swift:
# 555| getBody(): [BraceStmt] { ... }
# 555| getElement(0): [ReturnStmt] return ...
# 555| getResult(): [IntegerLiteralExpr] 1
# 558| [Comment] // ---
# 558|
# 560| [ProtocolDecl] MyProtocol
#-----| getGenericTypeParam(0): [GenericTypeParamDecl] Self
# 561| getMember(0): [NamedFunction] source()
# 561| InterfaceType = <Self where Self : MyProtocol> (Self) -> () -> Int
# 561| getSelfParam(): [ParamDecl] self
# 561| Type = Self
# 564| [ClassDecl] MyProcotolImpl
# 565| getMember(0): [NamedFunction] source()
# 565| InterfaceType = (MyProcotolImpl) -> () -> Int
# 565| getSelfParam(): [ParamDecl] self
# 565| Type = MyProcotolImpl
# 565| getBody(): [BraceStmt] { ... }
# 565| getElement(0): [ReturnStmt] return ...
# 565| getResult(): [IntegerLiteralExpr] 0
# 564| getMember(1): [Deinitializer] MyProcotolImpl.deinit()
# 564| InterfaceType = (MyProcotolImpl) -> () -> ()
# 564| getSelfParam(): [ParamDecl] self
# 564| Type = MyProcotolImpl
# 564| getBody(): [BraceStmt] { ... }
# 564| getMember(2): [Initializer] MyProcotolImpl.init()
# 564| InterfaceType = (MyProcotolImpl.Type) -> () -> MyProcotolImpl
# 564| getSelfParam(): [ParamDecl] self
# 564| Type = MyProcotolImpl
# 564| getBody(): [BraceStmt] { ... }
# 564| getElement(0): [ReturnStmt] return
# 568| [NamedFunction] getMyProtocol()
# 568| InterfaceType = () -> MyProtocol
# 568| getBody(): [BraceStmt] { ... }
# 568| getElement(0): [ReturnStmt] return ...
# 568| getResult(): [CallExpr] call to MyProcotolImpl.init()
# 568| getFunction(): [MethodLookupExpr] MyProcotolImpl.init()
# 568| getBase(): [TypeExpr] MyProcotolImpl.Type
# 568| getTypeRepr(): [TypeRepr] MyProcotolImpl
# 568| getMethodRef(): [DeclRefExpr] MyProcotolImpl.init()
# 568| getResult().getFullyConverted(): [ErasureExpr] (MyProtocol) ...
# 569| [NamedFunction] getMyProtocolImpl()
# 569| InterfaceType = () -> MyProcotolImpl
# 569| getBody(): [BraceStmt] { ... }
# 569| getElement(0): [ReturnStmt] return ...
# 569| getResult(): [CallExpr] call to MyProcotolImpl.init()
# 569| getFunction(): [MethodLookupExpr] MyProcotolImpl.init()
# 569| getBase(): [TypeExpr] MyProcotolImpl.Type
# 569| getTypeRepr(): [TypeRepr] MyProcotolImpl
# 569| getMethodRef(): [DeclRefExpr] MyProcotolImpl.init()
# 571| [NamedFunction] sink(arg:)
# 571| InterfaceType = (Int) -> ()
# 571| getParam(0): [ParamDecl] arg
# 571| Type = Int
# 571| getBody(): [BraceStmt] { ... }
# 573| [NamedFunction] testOpenExistentialExpr(x:y:)
# 573| InterfaceType = (MyProtocol, MyProcotolImpl) -> ()
# 573| getParam(0): [ParamDecl] x
# 573| Type = MyProtocol
# 573| getParam(1): [ParamDecl] y
# 573| Type = MyProcotolImpl
# 573| getBody(): [BraceStmt] { ... }
# 574| getElement(0): [CallExpr] call to sink(arg:)
# 574| getFunction(): [DeclRefExpr] sink(arg:)
# 574| getArgument(0): [Argument] arg: OpenExistentialExpr
# 574| getExpr(): [OpenExistentialExpr] OpenExistentialExpr
# 574| getSubExpr(): [CallExpr] call to source()
# 574| getFunction(): [MethodLookupExpr] .source()
# 574| getBase(): [OpaqueValueExpr] OpaqueValueExpr
# 574| getMethodRef(): [DeclRefExpr] source()
# 574| getExistential(): [DeclRefExpr] x
# 575| getElement(1): [CallExpr] call to sink(arg:)
# 575| getFunction(): [DeclRefExpr] sink(arg:)
# 575| getArgument(0): [Argument] arg: call to source()
# 575| getExpr(): [CallExpr] call to source()
# 575| getFunction(): [MethodLookupExpr] .source()
# 575| getBase(): [DeclRefExpr] y
# 575| getMethodRef(): [DeclRefExpr] source()
# 576| getElement(2): [CallExpr] call to sink(arg:)
# 576| getFunction(): [DeclRefExpr] sink(arg:)
# 576| getArgument(0): [Argument] arg: OpenExistentialExpr
# 576| getExpr(): [OpenExistentialExpr] OpenExistentialExpr
# 576| getSubExpr(): [CallExpr] call to source()
# 576| getFunction(): [MethodLookupExpr] .source()
# 576| getBase(): [OpaqueValueExpr] OpaqueValueExpr
# 576| getMethodRef(): [DeclRefExpr] source()
# 576| getExistential(): [CallExpr] call to getMyProtocol()
# 576| getFunction(): [DeclRefExpr] getMyProtocol()
# 577| getElement(3): [CallExpr] call to sink(arg:)
# 577| getFunction(): [DeclRefExpr] sink(arg:)
# 577| getArgument(0): [Argument] arg: call to source()
# 577| getExpr(): [CallExpr] call to source()
# 577| getFunction(): [MethodLookupExpr] .source()
# 577| getBase(): [CallExpr] call to getMyProtocolImpl()
# 577| getFunction(): [DeclRefExpr] getMyProtocolImpl()
# 577| getMethodRef(): [DeclRefExpr] source()
# 580| [Comment] // ---
# 580|
declarations.swift:
# 1| [StructDecl] Foo
# 2| getMember(0): [PatternBindingDecl] var ... = ...
Expand Down
24 changes: 24 additions & 0 deletions swift/ql/test/library-tests/ast/cfg.swift
Original file line number Diff line number Diff line change
Expand Up @@ -554,3 +554,27 @@ func usesAutoclosure(_ expr: @autoclosure () -> Int) -> Int {
func autoclosureTest() {
usesAutoclosure(1)
}

// ---

protocol MyProtocol {
func source() -> Int
}

class MyProcotolImpl : MyProtocol {
func source() -> Int { return 0 }
}

func getMyProtocol() -> MyProtocol { return MyProcotolImpl() }
func getMyProtocolImpl() -> MyProcotolImpl { return MyProcotolImpl() }

func sink(arg: Int) { }

func testOpenExistentialExpr(x: MyProtocol, y: MyProcotolImpl) {
sink(arg: x.source())
sink(arg: y.source())
sink(arg: getMyProtocol().source())
sink(arg: getMyProtocolImpl().source())
}

// ---
2 changes: 0 additions & 2 deletions swift/ql/test/library-tests/ast/statements.swift
Original file line number Diff line number Diff line change
Expand Up @@ -91,5 +91,3 @@ if #available(macOS 155, *) {
if #unavailable(macOS 42) {
print(42)
}


215 changes: 215 additions & 0 deletions swift/ql/test/library-tests/controlflow/graph/Cfg.expected
Original file line number Diff line number Diff line change
Expand Up @@ -6377,3 +6377,218 @@ cfg.swift:

# 555| { ... }
#-----| -> call to usesAutoclosure(_:)

# 564| MyProcotolImpl.deinit()
#-----| -> self

# 564| MyProcotolImpl.init()
#-----| -> self

# 564| enter MyProcotolImpl.deinit()
#-----| -> MyProcotolImpl.deinit()

# 564| enter MyProcotolImpl.init()
#-----| -> MyProcotolImpl.init()

# 564| exit MyProcotolImpl.deinit()

# 564| exit MyProcotolImpl.deinit() (normal)
#-----| -> exit MyProcotolImpl.deinit()

# 564| exit MyProcotolImpl.init()

# 564| exit MyProcotolImpl.init() (normal)
#-----| -> exit MyProcotolImpl.init()

# 564| return
#-----| return -> exit MyProcotolImpl.init() (normal)

# 564| self
#-----| -> { ... }

# 564| self
#-----| -> return

# 564| { ... }
#-----| -> exit MyProcotolImpl.deinit() (normal)

# 565| enter source()
#-----| -> source()

# 565| exit source()

# 565| exit source() (normal)
#-----| -> exit source()

# 565| source()
#-----| -> self

# 565| self
#-----| -> 0

# 565| return ...
#-----| return -> exit source() (normal)

# 565| 0
#-----| -> return ...

# 568| enter getMyProtocol()
#-----| -> getMyProtocol()

# 568| exit getMyProtocol()

# 568| exit getMyProtocol() (normal)
#-----| -> exit getMyProtocol()

# 568| getMyProtocol()
#-----| -> MyProcotolImpl.init()

# 568| return ...
#-----| return -> exit getMyProtocol() (normal)

# 568| MyProcotolImpl.Type
#-----| -> call to MyProcotolImpl.init()

# 568| MyProcotolImpl.init()
#-----| -> MyProcotolImpl.Type

# 568| (MyProtocol) ...
#-----| -> return ...

# 568| call to MyProcotolImpl.init()
#-----| -> (MyProtocol) ...

# 569| enter getMyProtocolImpl()
#-----| -> getMyProtocolImpl()

# 569| exit getMyProtocolImpl()

# 569| exit getMyProtocolImpl() (normal)
#-----| -> exit getMyProtocolImpl()

# 569| getMyProtocolImpl()
#-----| -> MyProcotolImpl.init()

# 569| return ...
#-----| return -> exit getMyProtocolImpl() (normal)

# 569| MyProcotolImpl.Type
#-----| -> call to MyProcotolImpl.init()

# 569| MyProcotolImpl.init()
#-----| -> MyProcotolImpl.Type

# 569| call to MyProcotolImpl.init()
#-----| -> return ...

# 571| enter sink(arg:)
#-----| -> sink(arg:)

# 571| exit sink(arg:)

# 571| exit sink(arg:) (normal)
#-----| -> exit sink(arg:)

# 571| sink(arg:)
#-----| -> arg

# 571| arg
#-----| -> { ... }

# 571| { ... }
#-----| -> exit sink(arg:) (normal)

# 573| enter testOpenExistentialExpr(x:y:)
#-----| -> testOpenExistentialExpr(x:y:)

# 573| exit testOpenExistentialExpr(x:y:)

# 573| exit testOpenExistentialExpr(x:y:) (normal)
#-----| -> exit testOpenExistentialExpr(x:y:)

# 573| testOpenExistentialExpr(x:y:)
#-----| -> x

# 573| x
#-----| -> y

# 573| y
#-----| -> sink(arg:)

# 574| sink(arg:)
#-----| -> x

# 574| call to sink(arg:)
#-----| -> sink(arg:)

# 574| OpaqueValueExpr
#-----| -> call to source()

# 574| x
#-----| -> .source()

# 574| .source()
#-----| -> OpaqueValueExpr

# 574| OpenExistentialExpr
#-----| -> call to sink(arg:)

# 574| call to source()
#-----| -> OpenExistentialExpr

# 575| sink(arg:)
#-----| -> .source()

# 575| call to sink(arg:)
#-----| -> sink(arg:)

# 575| y
#-----| -> call to source()

# 575| .source()
#-----| -> y

# 575| call to source()
#-----| -> call to sink(arg:)

# 576| sink(arg:)
#-----| -> getMyProtocol()

# 576| call to sink(arg:)
#-----| -> sink(arg:)

# 576| getMyProtocol()
#-----| -> call to getMyProtocol()

# 576| OpaqueValueExpr
#-----| -> call to source()

# 576| call to getMyProtocol()
#-----| -> .source()

# 576| .source()
#-----| -> OpaqueValueExpr

# 576| OpenExistentialExpr
#-----| -> call to sink(arg:)

# 576| call to source()
#-----| -> OpenExistentialExpr

# 577| sink(arg:)
#-----| -> .source()

# 577| call to sink(arg:)
#-----| -> exit testOpenExistentialExpr(x:y:) (normal)

# 577| getMyProtocolImpl()
#-----| -> call to getMyProtocolImpl()

# 577| call to getMyProtocolImpl()
#-----| -> call to source()

# 577| .source()
#-----| -> getMyProtocolImpl()

# 577| call to source()
#-----| -> call to sink(arg:)
Loading

0 comments on commit c4521a3

Please sign in to comment.