Skip to content

Commit d326b3a

Browse files
author
Robert Marsh
authored
Swift: global dataflow WIP
1 parent bba3564 commit d326b3a

4 files changed

Lines changed: 77 additions & 29 deletions

File tree

swift/ql/lib/codeql/swift/dataflow/Ssa.qll

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -64,6 +64,12 @@ module Ssa {
6464
a = bb.getNode(i).getNode().asAstNode() and
6565
value.getNode().asAstNode() = a.getSource()
6666
)
67+
or
68+
exists(VarDecl var, BasicBlock bb, int blockIndex, PatternBindingDecl pbd |
69+
this.definesAt(var, bb, blockIndex) and
70+
pbd.getAPattern() = bb.getNode(blockIndex).getNode() and
71+
value.getNode() = var.getParentInitializer()
72+
)
6773
}
6874
}
6975
}

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

Lines changed: 22 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
private import swift
22
private import DataFlowPrivate
3+
private import DataFlowPublic
34

45
newtype TReturnKind = TNormalReturnKind()
56

@@ -42,47 +43,35 @@ class DataFlowCallable extends TDataFlowCallable {
4243
* A call. This includes calls from source code, as well as call(back)s
4344
* inside library callables with a flow summary.
4445
*/
45-
class DataFlowCall extends TDataFlowCall {
46+
class DataFlowCall extends ExprNode {
47+
DataFlowCall() {
48+
this.asExpr() instanceof CallExpr
49+
}
50+
4651
/** Gets the enclosing callable. */
4752
DataFlowCallable getEnclosingCallable() { none() }
48-
49-
/** Gets a textual representation of this call. */
50-
string toString() { none() }
51-
52-
/** Gets the location of this call. */
53-
Location getLocation() { none() }
54-
55-
/**
56-
* Holds if this element is at the specified location.
57-
* The location spans column `startcolumn` of line `startline` to
58-
* column `endcolumn` of line `endline` in file `filepath`.
59-
* For more information, see
60-
* [Locations](https://codeql.github.com/docs/writing-codeql-queries/providing-locations-in-codeql-queries).
61-
*/
62-
predicate hasLocationInfo(
63-
string filepath, int startline, int startcolumn, int endline, int endcolumn
64-
) {
65-
this.getLocation().hasLocationInfo(filepath, startline, startcolumn, endline, endcolumn)
66-
}
6753
}
6854

6955
cached
7056
private module Cached {
7157
cached
72-
newtype TDataFlowCallable = TODO_TDataFlowCallable()
73-
74-
cached
75-
newtype TDataFlowCall = TODO_TDataFlowCall()
58+
newtype TDataFlowCallable = TDataFlowFunc(FuncDecl func)
7659

7760
/** Gets a viable run-time target for the call `call`. */
7861
cached
79-
DataFlowCallable viableCallable(DataFlowCall call) { none() }
62+
DataFlowCallable viableCallable(DataFlowCall call) {
63+
result = TDataFlowFunc(call.asExpr().(CallExpr).getStaticTarget())
64+
}
8065

8166
cached
82-
newtype TArgumentPosition = TODO_TArgumentPosition()
67+
newtype TArgumentPosition =
68+
TThisArgument() or
69+
TPositionalArgument(int n) { n in [0 .. 100] } // we rely on default exprs generated in the caller for ordering. TODO: compute range properly. TODO: varargs?
8370

8471
cached
85-
newtype TParameterPosition = TODO_TParameterPosition()
72+
newtype TParameterPosition =
73+
TThisParameter() or
74+
TPositionalParameter(int n) { n in [0 .. 100] } // TODO: compute range properly
8675
}
8776

8877
import Cached
@@ -111,6 +100,12 @@ class ArgumentPosition extends TArgumentPosition {
111100
string toString() { none() }
112101
}
113102

103+
class PositionalArgumentPosition extends ArgumentPosition, TPositionalArgument {
104+
int getIndex() {
105+
this = TPositionalArgument(result)
106+
}
107+
}
108+
114109
/** Holds if arguments at position `apos` match parameters at position `ppos`. */
115110
pragma[inline]
116111
predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) { none() }

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

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,12 +31,18 @@ private class ExprNodeImpl extends ExprNode, NodeImpl {
3131
override Location getLocationImpl() { result = expr.getLocation() }
3232

3333
override string toStringImpl() { result = expr.toString() }
34+
35+
override DataFlowCallable getEnclosingCallable() { result = TDataFlowFunc(expr.getScope()) }
3436
}
3537

3638
private class SsaDefinitionNodeImpl extends SsaDefinitionNode, NodeImpl {
3739
override Location getLocationImpl() { result = def.getLocation() }
3840

3941
override string toStringImpl() { result = def.toString() }
42+
43+
override DataFlowCallable getEnclosingCallable() {
44+
result = TDataFlowFunc(def.getBasicBlock().getScope())
45+
}
4046
}
4147

4248
/** A collection of cached types and predicates to be evaluated in the same stage. */
@@ -103,7 +109,11 @@ private module ParameterNodes {
103109
override string toStringImpl() { result = param.toString() }
104110

105111
override predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
106-
none() // TODO
112+
exists(FuncDecl f, int index |
113+
c = TDataFlowFunc(f) and
114+
f.getParam(index) = param and
115+
pos = TPositionalParameter(index)
116+
)
107117
}
108118
}
109119
}
@@ -119,7 +129,16 @@ abstract class ArgumentNode extends Node {
119129
final DataFlowCall getCall() { this.argumentOf(result, _) }
120130
}
121131

122-
private module ArgumentNodes { }
132+
private module ArgumentNodes {
133+
class NormalArgumentNode extends ExprNode, ArgumentNode {
134+
NormalArgumentNode() { exists(CallExpr call | call.getAnArgument().getExpr() = this.asExpr()) }
135+
136+
override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) {
137+
call.asExpr().(CallExpr).getArgument(pos.(PositionalArgumentPosition).getIndex()).getExpr() =
138+
this.asExpr()
139+
}
140+
}
141+
}
123142

124143
import ArgumentNodes
125144

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import swift
2+
import codeql.swift.dataflow.DataFlow
3+
import DataFlow::PathGraph
4+
5+
class TestConfiguration extends DataFlow::Configuration {
6+
TestConfiguration() { this = "TestConfiguration" }
7+
8+
override predicate isSource(DataFlow::Node src) {
9+
src.asExpr().(CallExpr).getStaticTarget().getName() = "source"
10+
}
11+
12+
override predicate isSink(DataFlow::Node sink) {
13+
exists(CallExpr sinkCall |
14+
sinkCall.getStaticTarget().getName() = "sink" and
15+
sinkCall.getAnArgument() = sink.asExpr()
16+
)
17+
}
18+
19+
override int explorationLimit() { result = 100 }
20+
}
21+
22+
from DataFlow::PartialPathNode src, DataFlow::PartialPathNode sink, TestConfiguration test
23+
where
24+
//test.isSource(src) and
25+
// test.isSink(sink) and
26+
//DataFlow::localFlow(src, sink)
27+
test.hasPartialFlow(src, sink, _)
28+
select src, sink

0 commit comments

Comments
 (0)