Skip to content

Commit 38acdaa

Browse files
authored
Merge pull request github#11111 from geoffw0/tuples
Swift: Content flow through tuples
2 parents edaf64c + af9ad7b commit 38acdaa

File tree

5 files changed

+165
-3
lines changed

5 files changed

+165
-3
lines changed

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

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ private module Cached {
8686
hasExprNode(n,
8787
[
8888
any(Argument arg | modifiable(arg)).getExpr(), any(MemberRefExpr ref).getBase(),
89-
any(ApplyExpr apply).getQualifier()
89+
any(ApplyExpr apply).getQualifier(), any(TupleElementExpr te).getSubExpr()
9090
])
9191
}
9292

@@ -177,7 +177,9 @@ private module Cached {
177177
newtype TContentSet = TSingletonContent(Content c)
178178

179179
cached
180-
newtype TContent = TFieldContent(FieldDecl f)
180+
newtype TContent =
181+
TFieldContent(FieldDecl f) or
182+
TTupleContent(int index) { exists(any(TupleExpr te).getElement(index)) }
181183
}
182184

183185
/**
@@ -498,25 +500,49 @@ predicate jumpStep(Node pred, Node succ) {
498500
}
499501

500502
predicate storeStep(Node node1, ContentSet c, Node node2) {
503+
// assignment to a member variable `obj.member = value`
501504
exists(MemberRefExpr ref, AssignExpr assign |
502505
ref = assign.getDest() and
503506
node1.asExpr() = assign.getSource() and
504507
node2.(PostUpdateNode).getPreUpdateNode().asExpr() = ref.getBase() and
505508
c.isSingleton(any(Content::FieldContent ct | ct.getField() = ref.getMember()))
506509
)
507510
or
511+
// creation of a tuple `(v1, v2)`
512+
exists(TupleExpr tuple, int pos |
513+
node1.asExpr() = tuple.getElement(pos) and
514+
node2.asExpr() = tuple and
515+
c.isSingleton(any(Content::TupleContent tc | tc.getIndex() = pos))
516+
)
517+
or
518+
// assignment to a tuple member `tuple.index = value`
519+
exists(TupleElementExpr tuple, AssignExpr assign |
520+
tuple = assign.getDest() and
521+
node1.asExpr() = assign.getSource() and
522+
node2.(PostUpdateNode).getPreUpdateNode().asExpr() = tuple.getSubExpr() and
523+
c.isSingleton(any(Content::TupleContent tc | tc.getIndex() = tuple.getIndex()))
524+
)
525+
or
508526
FlowSummaryImpl::Private::Steps::summaryStoreStep(node1, c, node2)
509527
}
510528

511529
predicate isLValue(Expr e) { any(AssignExpr assign).getDest() = e }
512530

513531
predicate readStep(Node node1, ContentSet c, Node node2) {
532+
// read of a member variable `obj.member`
514533
exists(MemberRefExpr ref |
515534
not isLValue(ref) and
516535
node1.asExpr() = ref.getBase() and
517536
node2.asExpr() = ref and
518537
c.isSingleton(any(Content::FieldContent ct | ct.getField() = ref.getMember()))
519538
)
539+
or
540+
// read of a tuple member `tuple.index`
541+
exists(TupleElementExpr tuple |
542+
node1.asExpr() = tuple.getSubExpr() and
543+
node2.asExpr() = tuple and
544+
c.isSingleton(any(Content::TupleContent tc | tc.getIndex() = tuple.getIndex()))
545+
)
520546
}
521547

522548
/**

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -159,6 +159,18 @@ module Content {
159159

160160
override string toString() { result = f.toString() }
161161
}
162+
163+
/** An element of a tuple at a specific index. */
164+
class TupleContent extends Content, TTupleContent {
165+
private int index;
166+
167+
TupleContent() { this = TTupleContent(index) }
168+
169+
/** Gets the index for this tuple element. */
170+
int getIndex() { result = index }
171+
172+
override string toString() { result = "Tuple element at index " + index.toString() }
173+
}
162174
}
163175

164176
/**

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

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,22 @@ edges
107107
| test.swift:266:15:266:16 | ...? : | file://:0:0:0:0 | [summary param] this in signum() : |
108108
| test.swift:266:15:266:16 | ...? : | test.swift:266:15:266:25 | call to signum() : |
109109
| test.swift:266:15:266:25 | call to signum() : | test.swift:266:15:266:25 | OptionalEvaluationExpr |
110+
| test.swift:277:14:277:26 | (...) [Tuple element at index 1] : | test.swift:281:15:281:15 | t1 [Tuple element at index 1] : |
111+
| test.swift:277:18:277:25 | call to source() : | test.swift:277:14:277:26 | (...) [Tuple element at index 1] : |
112+
| test.swift:281:15:281:15 | t1 [Tuple element at index 1] : | test.swift:281:15:281:18 | .1 |
113+
| test.swift:289:5:289:5 | [post] t1 [Tuple element at index 0] : | test.swift:292:15:292:15 | t1 [Tuple element at index 0] : |
114+
| test.swift:289:12:289:19 | call to source() : | test.swift:289:5:289:5 | [post] t1 [Tuple element at index 0] : |
115+
| test.swift:292:15:292:15 | t1 [Tuple element at index 0] : | test.swift:292:15:292:18 | .0 |
116+
| test.swift:297:14:297:45 | (...) [Tuple element at index 0] : | test.swift:302:15:302:15 | t1 [Tuple element at index 0] : |
117+
| test.swift:297:14:297:45 | (...) [Tuple element at index 0] : | test.swift:306:15:306:15 | t2 [Tuple element at index 0] : |
118+
| test.swift:297:14:297:45 | (...) [Tuple element at index 1] : | test.swift:303:15:303:15 | t1 [Tuple element at index 1] : |
119+
| test.swift:297:14:297:45 | (...) [Tuple element at index 1] : | test.swift:307:15:307:15 | t2 [Tuple element at index 1] : |
120+
| test.swift:297:18:297:25 | call to source() : | test.swift:297:14:297:45 | (...) [Tuple element at index 0] : |
121+
| test.swift:297:31:297:38 | call to source() : | test.swift:297:14:297:45 | (...) [Tuple element at index 1] : |
122+
| test.swift:302:15:302:15 | t1 [Tuple element at index 0] : | test.swift:302:15:302:18 | .0 |
123+
| test.swift:303:15:303:15 | t1 [Tuple element at index 1] : | test.swift:303:15:303:18 | .1 |
124+
| test.swift:306:15:306:15 | t2 [Tuple element at index 0] : | test.swift:306:15:306:18 | .0 |
125+
| test.swift:307:15:307:15 | t2 [Tuple element at index 1] : | test.swift:307:15:307:18 | .1 |
110126
nodes
111127
| file://:0:0:0:0 | .a [x] : | semmle.label | .a [x] : |
112128
| file://:0:0:0:0 | .x : | semmle.label | .x : |
@@ -227,6 +243,26 @@ nodes
227243
| test.swift:266:15:266:16 | ...? : | semmle.label | ...? : |
228244
| test.swift:266:15:266:25 | OptionalEvaluationExpr | semmle.label | OptionalEvaluationExpr |
229245
| test.swift:266:15:266:25 | call to signum() : | semmle.label | call to signum() : |
246+
| test.swift:277:14:277:26 | (...) [Tuple element at index 1] : | semmle.label | (...) [Tuple element at index 1] : |
247+
| test.swift:277:18:277:25 | call to source() : | semmle.label | call to source() : |
248+
| test.swift:281:15:281:15 | t1 [Tuple element at index 1] : | semmle.label | t1 [Tuple element at index 1] : |
249+
| test.swift:281:15:281:18 | .1 | semmle.label | .1 |
250+
| test.swift:289:5:289:5 | [post] t1 [Tuple element at index 0] : | semmle.label | [post] t1 [Tuple element at index 0] : |
251+
| test.swift:289:12:289:19 | call to source() : | semmle.label | call to source() : |
252+
| test.swift:292:15:292:15 | t1 [Tuple element at index 0] : | semmle.label | t1 [Tuple element at index 0] : |
253+
| test.swift:292:15:292:18 | .0 | semmle.label | .0 |
254+
| test.swift:297:14:297:45 | (...) [Tuple element at index 0] : | semmle.label | (...) [Tuple element at index 0] : |
255+
| test.swift:297:14:297:45 | (...) [Tuple element at index 1] : | semmle.label | (...) [Tuple element at index 1] : |
256+
| test.swift:297:18:297:25 | call to source() : | semmle.label | call to source() : |
257+
| test.swift:297:31:297:38 | call to source() : | semmle.label | call to source() : |
258+
| test.swift:302:15:302:15 | t1 [Tuple element at index 0] : | semmle.label | t1 [Tuple element at index 0] : |
259+
| test.swift:302:15:302:18 | .0 | semmle.label | .0 |
260+
| test.swift:303:15:303:15 | t1 [Tuple element at index 1] : | semmle.label | t1 [Tuple element at index 1] : |
261+
| test.swift:303:15:303:18 | .1 | semmle.label | .1 |
262+
| test.swift:306:15:306:15 | t2 [Tuple element at index 0] : | semmle.label | t2 [Tuple element at index 0] : |
263+
| test.swift:306:15:306:18 | .0 | semmle.label | .0 |
264+
| test.swift:307:15:307:15 | t2 [Tuple element at index 1] : | semmle.label | t2 [Tuple element at index 1] : |
265+
| test.swift:307:15:307:18 | .1 | semmle.label | .1 |
230266
subpaths
231267
| 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] &... : |
232268
| 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 ... : |
@@ -287,3 +323,9 @@ subpaths
287323
| test.swift:264:15:264:16 | ...! | test.swift:259:12:259:19 | call to source() : | test.swift:264:15:264:16 | ...! | result |
288324
| test.swift:265:15:265:31 | call to signum() | test.swift:265:15:265:22 | call to source() : | test.swift:265:15:265:31 | call to signum() | result |
289325
| test.swift:266:15:266:25 | OptionalEvaluationExpr | test.swift:259:12:259:19 | call to source() : | test.swift:266:15:266:25 | OptionalEvaluationExpr | result |
326+
| test.swift:281:15:281:18 | .1 | test.swift:277:18:277:25 | call to source() : | test.swift:281:15:281:18 | .1 | result |
327+
| test.swift:292:15:292:18 | .0 | test.swift:289:12:289:19 | call to source() : | test.swift:292:15:292:18 | .0 | result |
328+
| test.swift:302:15:302:18 | .0 | test.swift:297:18:297:25 | call to source() : | test.swift:302:15:302:18 | .0 | result |
329+
| test.swift:303:15:303:18 | .1 | test.swift:297:31:297:38 | call to source() : | test.swift:303:15:303:18 | .1 | result |
330+
| test.swift:306:15:306:18 | .0 | test.swift:297:18:297:25 | call to source() : | test.swift:306:15:306:18 | .0 | result |
331+
| test.swift:307:15:307:18 | .1 | test.swift:297:31:297:38 | call to source() : | test.swift:307:15:307:18 | .1 | result |

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

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -192,3 +192,44 @@
192192
| test.swift:266:15:266:15 | x | test.swift:267:15:267:15 | x |
193193
| test.swift:266:15:266:25 | call to signum() | test.swift:266:15:266:25 | OptionalEvaluationExpr |
194194
| test.swift:267:15:267:15 | x | test.swift:268:16:268:16 | x |
195+
| test.swift:277:9:277:9 | WriteDef | test.swift:279:15:279:15 | t1 |
196+
| test.swift:277:14:277:26 | (...) | test.swift:277:9:277:9 | WriteDef |
197+
| test.swift:279:15:279:15 | t1 | test.swift:280:15:280:15 | t1 |
198+
| test.swift:280:15:280:15 | [post] t1 | test.swift:281:15:281:15 | t1 |
199+
| test.swift:280:15:280:15 | t1 | test.swift:281:15:281:15 | t1 |
200+
| test.swift:281:15:281:15 | [post] t1 | test.swift:283:5:283:5 | t1 |
201+
| test.swift:281:15:281:15 | t1 | test.swift:283:5:283:5 | t1 |
202+
| test.swift:283:5:283:5 | [post] t1 | test.swift:285:15:285:15 | t1 |
203+
| test.swift:283:5:283:5 | t1 | test.swift:285:15:285:15 | t1 |
204+
| test.swift:285:15:285:15 | t1 | test.swift:286:15:286:15 | t1 |
205+
| test.swift:286:15:286:15 | [post] t1 | test.swift:287:15:287:15 | t1 |
206+
| test.swift:286:15:286:15 | t1 | test.swift:287:15:287:15 | t1 |
207+
| test.swift:287:15:287:15 | [post] t1 | test.swift:289:5:289:5 | t1 |
208+
| test.swift:287:15:287:15 | t1 | test.swift:289:5:289:5 | t1 |
209+
| test.swift:289:5:289:5 | [post] t1 | test.swift:291:15:291:15 | t1 |
210+
| test.swift:289:5:289:5 | t1 | test.swift:291:15:291:15 | t1 |
211+
| test.swift:291:15:291:15 | t1 | test.swift:292:15:292:15 | t1 |
212+
| test.swift:292:15:292:15 | [post] t1 | test.swift:293:15:293:15 | t1 |
213+
| test.swift:292:15:292:15 | t1 | test.swift:293:15:293:15 | t1 |
214+
| test.swift:297:9:297:9 | WriteDef | test.swift:298:14:298:14 | t1 |
215+
| test.swift:297:14:297:45 | (...) | test.swift:297:9:297:9 | WriteDef |
216+
| test.swift:298:9:298:9 | WriteDef | test.swift:305:15:305:15 | t2 |
217+
| test.swift:298:14:298:14 | t1 | test.swift:298:9:298:9 | WriteDef |
218+
| test.swift:298:14:298:14 | t1 | test.swift:299:21:299:21 | t1 |
219+
| test.swift:299:9:299:17 | WriteDef | test.swift:309:15:309:15 | a |
220+
| test.swift:299:9:299:17 | WriteDef | test.swift:310:15:310:15 | b |
221+
| test.swift:299:9:299:17 | WriteDef | test.swift:311:15:311:15 | c |
222+
| test.swift:299:21:299:21 | t1 | test.swift:299:9:299:17 | WriteDef |
223+
| test.swift:299:21:299:21 | t1 | test.swift:299:9:299:17 | WriteDef |
224+
| test.swift:299:21:299:21 | t1 | test.swift:299:9:299:17 | WriteDef |
225+
| test.swift:299:21:299:21 | t1 | test.swift:301:15:301:15 | t1 |
226+
| test.swift:301:15:301:15 | t1 | test.swift:302:15:302:15 | t1 |
227+
| test.swift:302:15:302:15 | [post] t1 | test.swift:303:15:303:15 | t1 |
228+
| test.swift:302:15:302:15 | t1 | test.swift:303:15:303:15 | t1 |
229+
| test.swift:303:15:303:15 | [post] t1 | test.swift:304:15:304:15 | t1 |
230+
| test.swift:303:15:303:15 | t1 | test.swift:304:15:304:15 | t1 |
231+
| test.swift:305:15:305:15 | t2 | test.swift:306:15:306:15 | t2 |
232+
| test.swift:306:15:306:15 | [post] t2 | test.swift:307:15:307:15 | t2 |
233+
| test.swift:306:15:306:15 | t2 | test.swift:307:15:307:15 | t2 |
234+
| test.swift:307:15:307:15 | [post] t2 | test.swift:308:15:308:15 | t2 |
235+
| test.swift:307:15:307:15 | t2 | test.swift:308:15:308:15 | t2 |

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

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -124,7 +124,7 @@ func forwarder() {
124124
return i
125125
})
126126
sink(arg: z) // $ flow=122
127-
127+
128128
var clean: Int = forward(arg: source(), lambda: {
129129
(i: Int) -> Int in
130130
return 0
@@ -269,3 +269,44 @@ func test_optionals() {
269269
sink(arg: y) // $ MISSING: flow=259
270270
}
271271
}
272+
273+
func sink(arg: (Int, Int)) {}
274+
func sink(arg: (Int, Int, Int)) {}
275+
276+
func testTuples() {
277+
var t1 = (1, source())
278+
279+
sink(arg: t1)
280+
sink(arg: t1.0)
281+
sink(arg: t1.1) // $ flow=277
282+
283+
t1.1 = 2
284+
285+
sink(arg: t1)
286+
sink(arg: t1.0)
287+
sink(arg: t1.1)
288+
289+
t1.0 = source()
290+
291+
sink(arg: t1)
292+
sink(arg: t1.0) // $ flow=289
293+
sink(arg: t1.1)
294+
}
295+
296+
func testTuples2() {
297+
let t1 = (x: source(), y: source(), z: 0)
298+
let t2 = t1
299+
let (a, b, c) = t1
300+
301+
sink(arg: t1)
302+
sink(arg: t1.x) // $ flow=297
303+
sink(arg: t1.y) // $ flow=297
304+
sink(arg: t1.z)
305+
sink(arg: t2)
306+
sink(arg: t2.x) // $ flow=297
307+
sink(arg: t2.y) // $ flow=297
308+
sink(arg: t2.z)
309+
sink(arg: a) // $ MISSING: flow=297
310+
sink(arg: b) // $ MISSING: flow=297
311+
sink(arg: c)
312+
}

0 commit comments

Comments
 (0)