Skip to content

Commit d92e90f

Browse files
committed
unified: Handle qualified type names
1 parent af35b8f commit d92e90f

3 files changed

Lines changed: 42 additions & 24 deletions

File tree

‎unified/ql/lib/codeql/unified/internal/mad/LegacyMaD.qll‎

Lines changed: 30 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,19 @@ private predicate parsedRawMethodName(string rawName, string name, string argLab
3838
)
3939
}
4040

41-
private string getNameFromExpr(Expr e) {
41+
private string getSimpleNameFromExpr(Expr e) {
4242
result = e.(Identifier).getValue()
4343
or
4444
result = e.(MemberAccessExpr).getMemberName()
4545
}
4646

47-
private string getCalleeName(CallExpr call) { result = getNameFromExpr(call.getCallee()) }
47+
private string getQualifiedNameFromExpr(Expr e) {
48+
result = e.(Identifier).getValue()
49+
or
50+
exists(MemberAccessExpr access | e = access |
51+
result = getQualifiedNameFromExpr(access.getBase()) + "." + access.getMemberName()
52+
)
53+
}
4854

4955
private string getArgLabelsFromCall(CallExpr call) {
5056
result =
@@ -64,8 +70,14 @@ private string getArgLabelsFromCall(CallExpr call) {
6470
}
6571

6672
pragma[nomagic]
67-
private predicate callSelector(CallExpr call, string name, string argLabels) {
68-
name = getCalleeName(call) and
73+
private predicate methodCallSelector(CallExpr call, string name, string argLabels) {
74+
name = getSimpleNameFromExpr(call.getCallee()) and
75+
argLabels = getArgLabelsFromCall(call)
76+
}
77+
78+
pragma[nomagic]
79+
private predicate constructorCallSelector(CallExpr call, string name, string argLabels) {
80+
name = getQualifiedNameFromExpr(call.getCallee()) and
6981
argLabels = getArgLabelsFromCall(call)
7082
}
7183

@@ -74,7 +86,7 @@ private import codeql.unified.internal.NameBinding as NameBinding
7486
private predicate isSubclassOfType(ClassLikeDeclaration cls, string typeName) {
7587
typeName = any(Selector s).getTypeString() and
7688
(
77-
getNameFromExpr(cls.getABaseType().getType()) = typeName
89+
getQualifiedNameFromExpr(cls.getABaseType().getType()) = typeName
7890
or
7991
isSubclassOfType(cls.getABaseClass(), typeName)
8092
)
@@ -146,26 +158,26 @@ private class Selector extends TSelector {
146158
")" + this.getArgTypes()
147159
}
148160

149-
/** Holds if `name,argLabels` should be used to join with `callSelector`. */
150-
private predicate effectiveCallSelector(string name, string argLabels) {
161+
/** Holds if `name,argLabels` should be used to join with `methodCallSelector`. */
162+
pragma[nomagic]
163+
private predicate matchesMethodCallSelector(string name, string argLabels) {
151164
this = MkSelector(_, _, name, argLabels, _) and
152165
name != "init"
153-
or
154-
// For "init" models there are two issues at play:
155-
// - Constructor calls do not mention "init", they just mention the type name, e.g. `String(...)` not `String.init(...)`.
156-
// - The name "init" is too common to match on anyway. It is more precise to match on the type name in this case.
157-
//
158-
// So to wire up "init" calls correctly, we just use the type name as the method name.
159-
//
160-
// TODO: does not work for compound access like `String.Index(...)` where the type is `String.Index` but the
161-
// call selector only uses `Index`.
166+
}
167+
168+
/** Holds if `name,argLabels` should be used to join with `constructorCallSelector`. */
169+
pragma[nomagic]
170+
private predicate matchesConstructorCallSelector(string name, string argLabels) {
162171
this = MkSelector(name, _, "init", argLabels, _)
163172
}
164173

165174
predicate matchesCall(CallExpr call) {
166175
exists(string name, string argLabels |
167-
this.effectiveCallSelector(name, argLabels) and
168-
callSelector(call, name, argLabels)
176+
this.matchesMethodCallSelector(name, argLabels) and
177+
methodCallSelector(call, name, argLabels)
178+
or
179+
this.matchesConstructorCallSelector(name, argLabels) and
180+
constructorCallSelector(call, name, argLabels)
169181
)
170182
}
171183

‎unified/ql/test/library-tests/mad/test.expected‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,12 @@ isSink
66
| test.swift:20:5:20:16 | [receiver arg] ... .md5(...) | weak-hash-input-MD5 |
77
| test.swift:22:20:22:25 | string | regex-use |
88
| test.swift:23:20:23:25 | string | regex-use |
9+
| test.swift:70:37:70:49 | encodedOffset | string-length |
10+
| test.swift:74:24:74:36 | encryptionKey | encryption-key |
11+
| test.swift:75:18:75:24 | fileURL | path-injection |
12+
| test.swift:86:24:86:36 | encryptionKey | encryption-key |
13+
| test.swift:87:18:87:24 | fileURL | path-injection |
14+
| test.swift:93:23:93:34 | seedFilePath | path-injection |
915
isSource
1016
| test.swift:4:5:4:27 | String(...) | remote |
1117
| test.swift:5:5:5:44 | String(...) | remote |

‎unified/ql/test/library-tests/mad/test.swift‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,12 @@ func testQualifiedConstructors(
6767
fileURL: String,
6868
seedFilePath: String
6969
) {
70-
_ = String.Index(encodedOffset: encodedOffset) // $ MISSING: isSink=string-length
70+
_ = String.Index(encodedOffset: encodedOffset) // $ isSink=string-length
7171

7272
_ = Realm.Configuration(
7373
deleteRealmIfMigrationNeeded: false,
74-
encryptionKey: encryptionKey, // $ MISSING: isSink=encryption-key
75-
fileURL: fileURL, // $ MISSING: isSink=path-injection
74+
encryptionKey: encryptionKey, // $ isSink=encryption-key
75+
fileURL: fileURL, // $ isSink=path-injection
7676
inMemoryIdentifier: nil,
7777
migrationBlock: nil,
7878
objectTypes: nil,
@@ -83,14 +83,14 @@ func testQualifiedConstructors(
8383

8484
_ = Realm.Configuration(
8585
deleteRealmIfMigrationNeeded: false,
86-
encryptionKey: encryptionKey, // $ MISSING: isSink=encryption-key
87-
fileURL: fileURL, // $ MISSING: isSink=path-injection
86+
encryptionKey: encryptionKey, // $ isSink=encryption-key
87+
fileURL: fileURL, // $ isSink=path-injection
8888
inMemoryIdentifier: nil,
8989
migrationBlock: nil,
9090
objectTypes: nil,
9191
readOnly: false,
9292
schemaVersion: 0,
93-
seedFilePath: seedFilePath, // $ MISSING: isSink=path-injection
93+
seedFilePath: seedFilePath, // $ isSink=path-injection
9494
shouldCompactOnLaunch: nil,
9595
syncConfiguration: nil)
9696
}

0 commit comments

Comments
 (0)