Skip to content

Commit d13d4c6

Browse files
authored
Merge pull request #9623 from MathiasVP/swift-interpretElement0
Swift: Interpret MaD strings
2 parents 1febe87 + f9c8926 commit d13d4c6

File tree

13 files changed

+176
-40
lines changed

13 files changed

+176
-40
lines changed

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

Lines changed: 77 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ private import internal.FlowSummaryImplSpecific
7878
* ensuring that they are visible to the taint tracking / data flow library.
7979
*/
8080
private module Frameworks {
81-
/* TODO */
81+
private import codeql.swift.frameworks.StandardLibrary.String
8282
}
8383

8484
/**
@@ -344,11 +344,86 @@ private predicate elementSpec(
344344
summaryModel(namespace, type, subtypes, name, signature, ext, _, _, _, _)
345345
}
346346

347+
private string paramsStringPart(AbstractFunctionDecl c, int i) {
348+
i = -1 and result = "(" and exists(c)
349+
or
350+
exists(int n, string p | c.getParam(n).getType().toString() = p |
351+
i = 2 * n and result = p
352+
or
353+
i = 2 * n - 1 and result = "," and n != 0
354+
)
355+
or
356+
i = 2 * c.getNumberOfParams() and result = ")"
357+
}
358+
359+
/**
360+
* Gets a parenthesized string containing all parameter types of this callable, separated by a comma.
361+
*
362+
* Returns the empty string if the callable has no parameters.
363+
* Parameter types are represented by their type erasure.
364+
*/
365+
cached
366+
string paramsString(AbstractFunctionDecl c) {
367+
result = concat(int i | | paramsStringPart(c, i) order by i)
368+
}
369+
370+
bindingset[func]
371+
predicate matchesSignature(AbstractFunctionDecl func, string signature) {
372+
signature = "" or
373+
paramsString(func) = signature
374+
}
375+
376+
private NominalType getDeclType(IterableDeclContext decl) {
377+
result = decl.(ClassDecl).getType()
378+
or
379+
result = decl.(StructDecl).getType()
380+
or
381+
result = getDeclType(decl.(ExtensionDecl).getExtendedTypeDecl())
382+
or
383+
result = decl.(EnumDecl).getType()
384+
or
385+
result = decl.(ProtocolDecl).getType()
386+
}
387+
388+
/**
389+
* Gets the element in module `namespace` that satisfies the following properties:
390+
* 1. If the element is a member of a class-like type, then the class-like type has name `type`
391+
* 2. If `subtypes = true` and the element is a member of a class-like type, then overrides of the element
392+
* are also returned.
393+
* 3. The element has name `name`
394+
* 4. If `signature` is non-empty, then the element has a list of parameter types described by `signature`.
395+
*
396+
* NOTE: `namespace` is currently not used (since we don't properly extract modules yet).
397+
*/
347398
pragma[nomagic]
348399
private Element interpretElement0(
349400
string namespace, string type, boolean subtypes, string name, string signature
350401
) {
351-
none() // TODO
402+
namespace = "" and // TODO: Fill out when we properly extract modules.
403+
(
404+
exists(AbstractFunctionDecl func |
405+
func.getName() = name and
406+
type = "" and
407+
matchesSignature(func, signature) and
408+
subtypes = false and
409+
not result instanceof MethodDecl and
410+
result = func
411+
)
412+
or
413+
exists(NominalType nomType, IterableDeclContext decl, MethodDecl method |
414+
method.getName() = name and
415+
method = decl.getAMember() and
416+
nomType.getName() = type and
417+
matchesSignature(method, signature) and
418+
result = method
419+
|
420+
subtypes = true and
421+
getDeclType(decl) = nomType.getADerivedType*()
422+
or
423+
subtypes = false and
424+
getDeclType(decl) = nomType
425+
)
426+
)
352427
}
353428

354429
/** Gets the source/sink/summary element corresponding to the supplied parameters. */

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -181,6 +181,12 @@ class ParameterPosition extends TParameterPosition {
181181

182182
class PositionalParameterPosition extends ParameterPosition, TPositionalParameter {
183183
int getIndex() { this = TPositionalParameter(result) }
184+
185+
override string toString() { result = this.getIndex().toString() }
186+
}
187+
188+
class ThisParameterPosition extends ParameterPosition, TThisParameter {
189+
override string toString() { result = "this" }
184190
}
185191

186192
/** An argument position. */
@@ -191,6 +197,12 @@ class ArgumentPosition extends TArgumentPosition {
191197

192198
class PositionalArgumentPosition extends ArgumentPosition, TPositionalArgument {
193199
int getIndex() { this = TPositionalArgument(result) }
200+
201+
override string toString() { result = this.getIndex().toString() }
202+
}
203+
204+
class ThisArgumentPosition extends ArgumentPosition, TThisArgument {
205+
override string toString() { result = "this" }
194206
}
195207

196208
/** Holds if arguments at position `apos` match parameters at position `ppos`. */

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

Lines changed: 20 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ class SummarizedCallableBase = AbstractFunctionDecl;
1717
DataFlowCallable inject(SummarizedCallable c) { result = TDataFlowFunc(c) }
1818

1919
/** Gets the parameter position of the instance parameter. */
20-
ArgumentPosition instanceParameterPosition() { none() } // disables implicit summary flow to `this` for callbacks
20+
ArgumentPosition instanceParameterPosition() { result instanceof ThisArgumentPosition }
2121

2222
/** Gets the synthesized summary data-flow node for the given values. */
2323
Node summaryNode(SummarizedCallable c, SummaryNodeState state) { result = TSummaryNode(c, state) }
@@ -31,23 +31,23 @@ DataFlowType getContentType(Content c) { any() }
3131
/** Gets the return type of kind `rk` for callable `c`. */
3232
bindingset[c]
3333
DataFlowType getReturnType(SummarizedCallable c, ReturnKind rk) {
34-
any() // TODO
34+
any() // TODO once we have type pruning
3535
}
3636

3737
/**
3838
* Gets the type of the parameter matching arguments at position `pos` in a
3939
* synthesized call that targets a callback of type `t`.
4040
*/
4141
DataFlowType getCallbackParameterType(DataFlowType t, ArgumentPosition pos) {
42-
none() // TODO
42+
any() // TODO once we have type pruning
4343
}
4444

4545
/**
4646
* Gets the return type of kind `rk` in a synthesized call that targets a
4747
* callback of type `t`.
4848
*/
4949
DataFlowType getCallbackReturnType(DataFlowType t, ReturnKind rk) {
50-
none() // TODO
50+
any() // TODO once we have type pruning
5151
}
5252

5353
/**
@@ -97,12 +97,12 @@ predicate sinkElement(Element e, string input, string kind, boolean generated) {
9797
/** Gets the summary component for specification component `c`, if any. */
9898
bindingset[c]
9999
SummaryComponent interpretComponentSpecific(AccessPathToken c) {
100-
none() // TODO
100+
none() // TODO once we have field flow
101101
}
102102

103103
/** Gets the textual representation of the content in the format used for flow summaries. */
104104
private string getContentSpecificCsv(Content c) {
105-
none() // TODO
105+
none() // TODO once we have field flow
106106
}
107107

108108
/** Gets the textual representation of a summary component in the format used for flow summaries. */
@@ -117,14 +117,10 @@ string getComponentSpecificCsv(SummaryComponent sc) {
117117
}
118118

119119
/** Gets the textual representation of a parameter position in the format used for flow summaries. */
120-
string getParameterPositionCsv(ParameterPosition pos) {
121-
none() // TODO
122-
}
120+
string getParameterPositionCsv(ParameterPosition pos) { result = pos.toString() }
123121

124122
/** Gets the textual representation of an argument position in the format used for flow summaries. */
125-
string getArgumentPositionCsv(ArgumentPosition pos) {
126-
none() // TODO
127-
}
123+
string getArgumentPositionCsv(ArgumentPosition pos) { result = pos.toString() }
128124

129125
/** Holds if input specification component `c` needs a reference. */
130126
predicate inputNeedsReferenceSpecific(string c) { none() }
@@ -187,11 +183,21 @@ predicate interpretInputSpecific(string c, InterpretNode mid, InterpretNode n) {
187183
/** Gets the argument position obtained by parsing `X` in `Parameter[X]`. */
188184
bindingset[s]
189185
ArgumentPosition parseParamBody(string s) {
190-
none() // TODO
186+
exists(int index | index = AccessPath::parseInt(s) |
187+
result.(PositionalArgumentPosition).getIndex() = index
188+
or
189+
index = -1 and
190+
result instanceof ThisArgumentPosition
191+
)
191192
}
192193

193194
/** Gets the parameter position obtained by parsing `X` in `Argument[X]`. */
194195
bindingset[s]
195196
ParameterPosition parseArgBody(string s) {
196-
none() // TODO
197+
exists(int index | index = AccessPath::parseInt(s) |
198+
result.(PositionalParameterPosition).getIndex() = index
199+
or
200+
index = -1 and
201+
result instanceof ThisParameterPosition
202+
)
197203
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
private import swift
2+
3+
private Decl getAMember(IterableDeclContext ctx) {
4+
ctx.getAMember() = result
5+
or
6+
exists(VarDecl var |
7+
ctx.getAMember() = var and
8+
var.getAnAccessorDecl() = result
9+
)
10+
}
11+
12+
class MethodDecl extends AbstractFunctionDecl {
13+
MethodDecl() {
14+
this = getAMember(any(ClassDecl c))
15+
or
16+
this = getAMember(any(StructDecl c))
17+
or
18+
this = getAMember(any(ExtensionDecl c))
19+
or
20+
this = getAMember(any(EnumDecl c))
21+
or
22+
this = getAMember(any(ProtocolDecl c))
23+
}
24+
}

swift/ql/lib/codeql/swift/elements/expr/ApplyExpr.qll

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
private import codeql.swift.generated.expr.ApplyExpr
2-
private import codeql.swift.elements.decl.FuncDecl
2+
private import codeql.swift.elements.decl.AbstractFunctionDecl
33
private import codeql.swift.elements.expr.DeclRefExpr
44

55
class ApplyExpr extends ApplyExprBase {
6-
FuncDecl getStaticTarget() { result = this.getFunction().(DeclRefExpr).getDecl() }
6+
AbstractFunctionDecl getStaticTarget() { result = this.getFunction().(DeclRefExpr).getDecl() }
77

88
override string toString() {
99
result = "call to " + this.getStaticTarget().toString()
Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
21
private import codeql.swift.generated.type.AnyGenericType
2+
private import codeql.swift.elements.decl.GenericTypeDecl
33

4-
class AnyGenericType extends AnyGenericTypeBase { }
4+
class AnyGenericType extends AnyGenericTypeBase {
5+
string getName() { result = this.getDeclaration().(GenericTypeDecl).getName() }
6+
}
Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,8 @@
1-
// generated by codegen/codegen.py, remove this comment if you wish to edit this file
21
private import codeql.swift.generated.type.NominalType
2+
private import codeql.swift.elements.decl.NominalTypeDecl
33

4-
class NominalType extends NominalTypeBase { }
4+
class NominalType extends NominalTypeBase {
5+
NominalType getABaseType() { result = this.getDeclaration().(NominalTypeDecl).getABaseType() }
6+
7+
NominalType getADerivedType() { result.getABaseType() = this }
8+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
import swift
2+
private import codeql.swift.dataflow.ExternalFlow
3+
4+
private class StringSource extends SourceModelCsv {
5+
override predicate row(string row) {
6+
row =
7+
[
8+
// String(contentsOf:) is a remote flow source
9+
";String;true;init(contentsOf:);(URL);;ReturnValue;remote"
10+
]
11+
}
12+
}

swift/ql/lib/swift.qll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,3 +2,4 @@
22

33
import codeql.swift.elements
44
import codeql.swift.elements.expr.LogicalOperation
5+
import codeql.swift.elements.decl.MethodDecl

swift/ql/test/extractor-tests/expressions/all.expected

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,7 @@
4444
| expressions.swift:21:6:21:16 | call to failure(_:) |
4545
| expressions.swift:21:14:21:14 | 11 |
4646
| expressions.swift:27:13:27:13 | Klass.Type |
47-
| expressions.swift:27:13:27:13 | call to ... |
47+
| expressions.swift:27:13:27:13 | call to init |
4848
| expressions.swift:27:13:27:13 | init |
4949
| expressions.swift:27:13:27:19 | call to ... |
5050
| expressions.swift:29:9:29:19 | [...] |
@@ -163,7 +163,7 @@
163163
| expressions.swift:79:11:79:11 | init |
164164
| expressions.swift:79:19:79:19 | 22 |
165165
| expressions.swift:83:15:83:15 | Derived.Type |
166-
| expressions.swift:83:15:83:15 | call to ... |
166+
| expressions.swift:83:15:83:15 | call to init |
167167
| expressions.swift:83:15:83:15 | init |
168168
| expressions.swift:83:15:83:23 | call to ... |
169169
| expressions.swift:84:1:84:1 | _ |
@@ -184,7 +184,7 @@
184184
| expressions.swift:92:14:92:55 | call to ... |
185185
| expressions.swift:92:24:92:24 | passRetained(_:) |
186186
| expressions.swift:92:37:92:37 | ToPtr.Type |
187-
| expressions.swift:92:37:92:37 | call to ... |
187+
| expressions.swift:92:37:92:37 | call to init |
188188
| expressions.swift:92:37:92:37 | init |
189189
| expressions.swift:92:37:92:43 | call to ... |
190190
| expressions.swift:92:46:92:46 | toOpaque() |

0 commit comments

Comments
 (0)