Skip to content

Commit ca279f4

Browse files
authored
Merge pull request github#10996 from geoffw0/methods
Swift: Add MethodDecl.hasQualifiedName
2 parents 19b7e9e + 3507ea3 commit ca279f4

File tree

7 files changed

+123
-23
lines changed

7 files changed

+123
-23
lines changed

swift/ql/lib/codeql/swift/elements/decl/AbstractFunctionDecl.qll

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,4 +2,9 @@ private import codeql.swift.generated.decl.AbstractFunctionDecl
22

33
class AbstractFunctionDecl extends Generated::AbstractFunctionDecl {
44
override string toString() { result = this.getName() }
5+
6+
/**
7+
* Holds if this function is called `funcName`.
8+
*/
9+
predicate hasName(string funcName) { this.getName() = funcName }
510
}

swift/ql/lib/codeql/swift/elements/decl/MethodDecl.qll

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,4 +21,34 @@ class MethodDecl extends AbstractFunctionDecl {
2121
or
2222
this = getAMember(any(ProtocolDecl c))
2323
}
24+
25+
/**
26+
* Holds if this function is called `funcName` and its a member of a
27+
* class, struct, extension, enum or protocol call `typeName`.
28+
*/
29+
cached
30+
predicate hasQualifiedName(string typeName, string funcName) {
31+
this.getName() = funcName and
32+
(
33+
exists(NominalTypeDecl c |
34+
c.getFullName() = typeName and
35+
c.getAMember() = this
36+
)
37+
or
38+
exists(ExtensionDecl e |
39+
e.getExtendedTypeDecl().getFullName() = typeName and
40+
e.getAMember() = this
41+
)
42+
)
43+
}
44+
45+
/**
46+
* Holds if this function is called `funcName` and its a member of a
47+
* class, struct, extension, enum or protocol call `typeName` in a module
48+
* called `moduleName`.
49+
*/
50+
predicate hasQualifiedName(string moduleName, string typeName, string funcName) {
51+
this.hasQualifiedName(typeName, funcName) and
52+
this.getModule().getFullName() = moduleName
53+
}
2454
}

swift/ql/lib/codeql/swift/elements/decl/TypeDecl.qll

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ class TypeDecl extends Generated::TypeDecl {
2525
* The name and full name of `A` is `A`. The name of `B` is `B`, but the
2626
* full name of `B` is `A.B`.
2727
*/
28+
cached
2829
string getFullName() {
2930
not this.getEnclosingDecl() instanceof TypeDecl and
3031
result = this.getName()

swift/ql/src/queries/Security/CWE-079/UnsafeWebViewFetch.ql

Lines changed: 19 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -27,33 +27,29 @@ class Sink extends DataFlow::Node {
2727

2828
Sink() {
2929
exists(
30-
AbstractFunctionDecl funcDecl, CallExpr call, string funcName, string paramName, int arg,
31-
int baseUrlArg
30+
MethodDecl funcDecl, CallExpr call, string className, string funcName, string paramName,
31+
int arg, int baseUrlArg
3232
|
3333
// arguments to method calls...
34-
exists(string className, ClassOrStructDecl c |
35-
(
36-
// `loadHTMLString`
37-
className = ["UIWebView", "WKWebView"] and
38-
funcName = "loadHTMLString(_:baseURL:)" and
39-
paramName = "string"
40-
or
41-
// `UIWebView.load`
42-
className = "UIWebView" and
43-
funcName = "load(_:mimeType:textEncodingName:baseURL:)" and
44-
paramName = "data"
45-
or
46-
// `WKWebView.load`
47-
className = "WKWebView" and
48-
funcName = "load(_:mimeType:characterEncodingName:baseURL:)" and
49-
paramName = "data"
50-
) and
51-
c.getName() = className and
52-
c.getAMember() = funcDecl and
53-
call.getStaticTarget() = funcDecl
34+
(
35+
// `loadHTMLString`
36+
className = ["UIWebView", "WKWebView"] and
37+
funcName = "loadHTMLString(_:baseURL:)" and
38+
paramName = "string"
39+
or
40+
// `UIWebView.load`
41+
className = "UIWebView" and
42+
funcName = "load(_:mimeType:textEncodingName:baseURL:)" and
43+
paramName = "data"
44+
or
45+
// `WKWebView.load`
46+
className = "WKWebView" and
47+
funcName = "load(_:mimeType:characterEncodingName:baseURL:)" and
48+
paramName = "data"
5449
) and
50+
call.getStaticTarget() = funcDecl and
5551
// match up `funcName`, `paramName`, `arg`, `node`.
56-
funcDecl.getName() = funcName and
52+
funcDecl.hasQualifiedName(className, funcName) and
5753
funcDecl.getParam(pragma[only_bind_into](arg)).getName() = paramName and
5854
call.getArgument(pragma[only_bind_into](arg)).getExpr() = this.asExpr() and
5955
// match up `baseURLArg`
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
| abstractfunctiondecl.swift:2:1:2:15 | func1() | getName:func1(), hasName:func1() |
2+
| abstractfunctiondecl.swift:5:2:5:16 | func2() | MethodDecl, getName:func2(), hasName:func2(), hasQualifiedName(2):Class1.func2(), hasQualifiedName(3):abstractfunctiondecl.Class1.func2() |
3+
| abstractfunctiondecl.swift:8:3:8:17 | func3() | MethodDecl, getName:func3(), hasName:func3(), hasQualifiedName(2):Class1.Class2.func3(), hasQualifiedName(3):abstractfunctiondecl.Class1.Class2.func3() |
4+
| abstractfunctiondecl.swift:13:2:13:13 | func4() | MethodDecl, getName:func4(), hasName:func4(), hasQualifiedName(2):Protocol1.func4(), hasQualifiedName(3):abstractfunctiondecl.Protocol1.func4() |
5+
| abstractfunctiondecl.swift:17:2:17:16 | func4() | MethodDecl, getName:func4(), hasName:func4(), hasQualifiedName(2):Class3.func4(), hasQualifiedName(3):abstractfunctiondecl.Class3.func4() |
6+
| abstractfunctiondecl.swift:21:2:21:16 | func5() | MethodDecl, getName:func5(), hasName:func5(), hasQualifiedName(2):Class3.func5(), hasQualifiedName(3):abstractfunctiondecl.Class3.func5() |
7+
| abstractfunctiondecl.swift:25:2:25:16 | func6() | MethodDecl, getName:func6(), hasName:func6(), hasQualifiedName(2):Struct1.func6(), hasQualifiedName(3):abstractfunctiondecl.Struct1.func6() |
8+
| abstractfunctiondecl.swift:31:2:31:16 | func7() | MethodDecl, getName:func7(), hasName:func7(), hasQualifiedName(2):Enum1.func7(), hasQualifiedName(3):abstractfunctiondecl.Enum1.func7() |
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
import swift
2+
3+
string describe(AbstractFunctionDecl f) {
4+
result = "getName:" + f.getName()
5+
or
6+
exists(string a |
7+
f.hasName(a) and
8+
result = "hasName:" + a
9+
)
10+
or
11+
result = "MethodDecl" and f instanceof MethodDecl
12+
or
13+
exists(string a, string b |
14+
f.(MethodDecl).hasQualifiedName(a, b) and
15+
result = "hasQualifiedName(2):" + a + "." + b
16+
)
17+
or
18+
exists(string a, string b, string c |
19+
f.(MethodDecl).hasQualifiedName(a, b, c) and
20+
result = "hasQualifiedName(3):" + a + "." + b + "." + c
21+
)
22+
}
23+
24+
from AbstractFunctionDecl f
25+
where
26+
not f.getFile() instanceof UnknownFile and
27+
not f.getName().matches("%init%")
28+
select f, concat(describe(f), ", ")
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
2+
func func1() {}
3+
4+
class Class1 {
5+
func func2() {}
6+
7+
class Class2 {
8+
func func3() {}
9+
}
10+
}
11+
12+
protocol Protocol1 {
13+
func func4()
14+
}
15+
16+
class Class3: Class1, Protocol1 {
17+
func func4() {}
18+
}
19+
20+
extension Class3 {
21+
func func5() {}
22+
}
23+
24+
struct Struct1 {
25+
func func6() {}
26+
}
27+
28+
enum Enum1 {
29+
case case1
30+
case case2
31+
func func7() {}
32+
}

0 commit comments

Comments
 (0)