Skip to content

Commit 42cc644

Browse files
committed
Swift: add DataFlow::Content for arrays
1 parent d57276c commit 42cc644

File tree

6 files changed

+81
-2
lines changed

6 files changed

+81
-2
lines changed

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

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ private import codeql.swift.controlflow.BasicBlocks
88
private import codeql.swift.dataflow.FlowSummary as FlowSummary
99
private import codeql.swift.dataflow.internal.FlowSummaryImpl as FlowSummaryImpl
1010
private import codeql.swift.frameworks.StandardLibrary.PointerTypes
11+
private import codeql.swift.frameworks.StandardLibrary.ArrayType
1112

1213
/** Gets the callable in which this node occurs. */
1314
DataFlowCallable nodeGetEnclosingCallable(NodeImpl n) { result = n.getEnclosingCallable() }
@@ -245,7 +246,8 @@ private module Cached {
245246
newtype TContent =
246247
TFieldContent(FieldDecl f) or
247248
TTupleContent(int index) { exists(any(TupleExpr te).getElement(index)) } or
248-
TEnumContent(ParamDecl f) { exists(EnumElementDecl d | d.getAParam() = f) }
249+
TEnumContent(ParamDecl f) { exists(EnumElementDecl d | d.getAParam() = f) } or
250+
TArrayContent()
249251
}
250252

251253
/**
@@ -689,6 +691,19 @@ predicate storeStep(Node node1, ContentSet c, Node node2) {
689691
node2 = node1 and // TODO: again, we should ideally have a separate Node case here, and not reuse the CallExpr
690692
c instanceof OptionalSomeContentSet and
691693
init.isFailable()
694+
) or
695+
// creation of an array `[v1,v2]`
696+
exists(ArrayExpr arr |
697+
node1.asExpr() = arr.getAnElement() and
698+
node2.asExpr() = arr and
699+
c.isSingleton(any(Content::ArrayContent ac))
700+
) or
701+
// array assignment `a[n] = x`
702+
exists(AssignExpr assign, SubscriptExpr subscript |
703+
node1.asExpr() = assign.getSource() and
704+
node2.(PostUpdateNode).getPreUpdateNode().asExpr() = subscript.getBase() and
705+
subscript = assign.getDest() and
706+
subscript.getBase().getType().(InOutType).getObjectType() instanceof ArrayType
692707
)
693708
or
694709
FlowSummaryImpl::Private::Steps::summaryStoreStep(node1.(FlowSummaryNode).getSummaryNode(), c,
@@ -754,6 +769,14 @@ predicate readStep(Node node1, ContentSet c, Node node2) {
754769
not exists(component.getNextComponent()) and
755770
node2.(KeyPathReturnNodeImpl).getKeyPathExpr() = component.getKeyPathExpr()
756771
)
772+
or
773+
// read of an array member via subscript operator
774+
exists(SubscriptExpr subscript |
775+
subscript.getBase() = node1.asExpr() and
776+
subscript = node2.asExpr() and
777+
subscript.getBase().getType().(InOutType).getObjectType() instanceof ArrayType and
778+
c.isSingleton(any(Content::ArrayContent ac))
779+
)
757780
}
758781

759782
/**

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,6 +206,10 @@ module Content {
206206
exists(EnumElementDecl d, int pos | d.getParam(pos) = p | result = d.toString() + ":" + pos)
207207
}
208208
}
209+
210+
class ArrayContent extends Content, TArrayContent {
211+
override string toString() { result = "Array element"}
212+
}
209213
}
210214

211215
/**
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import swift
2+
3+
class ArrayType extends BoundGenericType {
4+
ArrayType() {
5+
this.getName().matches("Array<%")
6+
}
7+
}

swift/ql/test/library-tests/dataflow/dataflow/DataFlow.expected

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,12 @@ edges
274274
| test.swift:628:9:628:16 | call to source() | test.swift:631:15:631:15 | x |
275275
| test.swift:630:10:630:11 | &... | test.swift:630:14:630:15 | [post] &... |
276276
| test.swift:630:14:630:15 | [post] &... | test.swift:632:15:632:15 | y |
277+
| test.swift:638:5:638:5 | [post] &... [Array element] | test.swift:639:15:639:15 | &... [Array element] |
278+
| test.swift:638:15:638:22 | call to source() | test.swift:638:5:638:5 | [post] &... [Array element] |
279+
| test.swift:639:15:639:15 | &... [Array element] | test.swift:639:15:639:21 | ...[...] |
280+
| test.swift:641:16:641:25 | [...] [Array element] | test.swift:642:15:642:15 | &... [Array element] |
281+
| test.swift:641:17:641:24 | call to source() | test.swift:641:16:641:25 | [...] [Array element] |
282+
| test.swift:642:15:642:15 | &... [Array element] | test.swift:642:15:642:21 | ...[...] |
277283
nodes
278284
| file://:0:0:0:0 | .a [x] | semmle.label | .a [x] |
279285
| file://:0:0:0:0 | .str | semmle.label | .str |
@@ -574,6 +580,14 @@ nodes
574580
| test.swift:630:14:630:15 | [post] &... | semmle.label | [post] &... |
575581
| test.swift:631:15:631:15 | x | semmle.label | x |
576582
| test.swift:632:15:632:15 | y | semmle.label | y |
583+
| test.swift:638:5:638:5 | [post] &... [Array element] | semmle.label | [post] &... [Array element] |
584+
| test.swift:638:15:638:22 | call to source() | semmle.label | call to source() |
585+
| test.swift:639:15:639:15 | &... [Array element] | semmle.label | &... [Array element] |
586+
| test.swift:639:15:639:21 | ...[...] | semmle.label | ...[...] |
587+
| test.swift:641:16:641:25 | [...] [Array element] | semmle.label | [...] [Array element] |
588+
| test.swift:641:17:641:24 | call to source() | semmle.label | call to source() |
589+
| test.swift:642:15:642:15 | &... [Array element] | semmle.label | &... [Array element] |
590+
| test.swift:642:15:642:21 | ...[...] | semmle.label | ...[...] |
577591
subpaths
578592
| test.swift:75:21:75:22 | &... | test.swift:65:16:65:28 | arg1 | test.swift:65:1:70:1 | arg2[return] | test.swift:75:31:75:32 | [post] &... |
579593
| 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 ... |
@@ -688,3 +702,5 @@ subpaths
688702
| test.swift:626:15:626:15 | y | test.swift:618:13:618:20 | call to source() | test.swift:626:15:626:15 | y | result |
689703
| test.swift:631:15:631:15 | x | test.swift:628:9:628:16 | call to source() | test.swift:631:15:631:15 | x | result |
690704
| test.swift:632:15:632:15 | y | test.swift:628:9:628:16 | call to source() | test.swift:632:15:632:15 | y | result |
705+
| test.swift:639:15:639:21 | ...[...] | test.swift:638:15:638:22 | call to source() | test.swift:639:15:639:21 | ...[...] | result |
706+
| test.swift:642:15:642:21 | ...[...] | test.swift:641:17:641:24 | call to source() | test.swift:642:15:642:21 | ...[...] | result |

swift/ql/test/library-tests/dataflow/dataflow/LocalFlow.expected

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -685,3 +685,17 @@
685685
| test.swift:630:14:630:15 | &... | test.swift:632:15:632:15 | y |
686686
| test.swift:630:14:630:15 | [post] &... | test.swift:632:15:632:15 | y |
687687
| test.swift:630:15:630:15 | y | test.swift:630:14:630:15 | &... |
688+
| test.swift:636:9:636:9 | SSA def(arr1) | test.swift:637:15:637:15 | arr1 |
689+
| test.swift:636:9:636:9 | arr1 | test.swift:636:9:636:9 | SSA def(arr1) |
690+
| test.swift:636:16:636:22 | [...] | test.swift:636:9:636:9 | arr1 |
691+
| test.swift:637:15:637:15 | &... | test.swift:638:5:638:5 | arr1 |
692+
| test.swift:637:15:637:15 | [post] &... | test.swift:638:5:638:5 | arr1 |
693+
| test.swift:637:15:637:15 | arr1 | test.swift:637:15:637:15 | &... |
694+
| test.swift:638:5:638:5 | &... | test.swift:639:15:639:15 | arr1 |
695+
| test.swift:638:5:638:5 | [post] &... | test.swift:639:15:639:15 | arr1 |
696+
| test.swift:638:5:638:5 | arr1 | test.swift:638:5:638:5 | &... |
697+
| test.swift:639:15:639:15 | arr1 | test.swift:639:15:639:15 | &... |
698+
| test.swift:641:9:641:9 | SSA def(arr2) | test.swift:642:15:642:15 | arr2 |
699+
| test.swift:641:9:641:9 | arr2 | test.swift:641:9:641:9 | SSA def(arr2) |
700+
| test.swift:641:16:641:25 | [...] | test.swift:641:9:641:9 | arr2 |
701+
| test.swift:642:15:642:15 | arr2 | test.swift:642:15:642:15 | &... |

swift/ql/test/library-tests/dataflow/dataflow/test.swift

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
func source() -> Int { return 0; }
2-
func sink(arg: Int) {}
2+
func sink<T>(arg: T) {}
33

44
func intraprocedural_with_local_flow() -> Void {
55
var t2: Int
@@ -631,3 +631,18 @@ func testSwap() {
631631
sink(arg: x) // $ SPURIOUS: flow=628
632632
sink(arg: y) // $ flow=628
633633
}
634+
635+
func testArray() {
636+
var arr1 = [1,2,3]
637+
sink(arg: arr1[0])
638+
arr1[1] = source()
639+
sink(arg: arr1[0]) // $ flow=638
640+
sink(arg: arr1)
641+
642+
var arr2 = [source()]
643+
sink(arg: arr2[0]) // $ flow=642
644+
645+
var matrix = [[source()]]
646+
sink(arg: matrix[0])
647+
sink(arg: matrix[0][0]) // $ flow=645
648+
}

0 commit comments

Comments
 (0)