Skip to content

Commit 4a8320f

Browse files
authored
Merge pull request github#13287 from geoffw0/stringfp
Swift: Fix some string length conflation false positives
2 parents e764b46 + 85a1ab0 commit 4a8320f

File tree

4 files changed

+146
-31
lines changed

4 files changed

+146
-31
lines changed

swift/ql/lib/codeql/swift/security/StringLengthConflationExtensions.qll

Lines changed: 59 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -38,27 +38,34 @@ class StringType extends TStringType {
3838
csvLabel = "nsstring-length"
3939
or
4040
this = TStringUtf8() and
41-
name = "String.utf8" and
42-
singular = "a String.utf8" and
41+
name = "String.UTF8View" and
42+
singular = "a String.UTF8View" and
4343
equivClass = this and
4444
csvLabel = "string-utf8-length"
4545
or
4646
this = TStringUtf16() and
47-
name = "String.utf16" and
48-
singular = "a String.utf16" and
47+
name = "String.UTF16View" and
48+
singular = "a String.UTF16View" and
4949
equivClass = TNsString() and
5050
csvLabel = "string-utf16-length"
5151
or
5252
this = TStringUnicodeScalars() and
53-
name = "String.unicodeScalars" and
54-
singular = "a String.unicodeScalars" and
53+
name = "String.UnicodeScalarView" and
54+
singular = "a String.UnicodeScalarView" and
5555
equivClass = this and
5656
csvLabel = "string-unicodescalars-length"
5757
}
5858

59-
/** Gets a textual representation of this string type. */
59+
/**
60+
* Gets a textual representation of this string type.
61+
*/
6062
string toString() { result = name }
6163

64+
/**
65+
* Gets the name of this string type.
66+
*/
67+
string getName() { result = name }
68+
6269
/**
6370
* Gets the equivalence class for this string type. If these are equal,
6471
* they should be treated as equivalent.
@@ -142,21 +149,16 @@ private class ExtraStringLengthConflationSource extends StringLengthConflationSo
142149
StringType stringType;
143150

144151
ExtraStringLengthConflationSource() {
145-
exists(MemberRefExpr memberRef, string typeName |
152+
// source is the result of a call to `[stringType].count`.
153+
exists(MemberRefExpr memberRef |
146154
(
147-
// result of a call to `String.utf8.count`
148-
typeName = "String.UTF8View" and
149155
stringType = TStringUtf8()
150156
or
151-
// result of a call to `String.utf16.count`
152-
typeName = "String.UTF16View" and
153157
stringType = TStringUtf16()
154158
or
155-
// result of a call to `String.unicodeScalars.count`
156-
typeName = "String.UnicodeScalarView" and
157159
stringType = TStringUnicodeScalars()
158160
) and
159-
memberRef.getBase().getType().(NominalType).getName() = typeName and
161+
memberRef.getBase().getType().(NominalType).getName() = stringType.getName() and
160162
memberRef.getMember().(VarDecl).getName() = "count" and
161163
this.asExpr() = memberRef
162164
)
@@ -180,14 +182,6 @@ private class StringLengthConflationSinks extends SinkModelCsv {
180182
override predicate row(string row) {
181183
row =
182184
[
183-
";Sequence;true;dropFirst(_:);;;Argument[0];string-length",
184-
";Sequence;true;dropLast(_:);;;Argument[0];string-length",
185-
";Sequence;true;prefix(_:);;;Argument[0];string-length",
186-
";Sequence;true;suffix(_:);;;Argument[0];string-length",
187-
";Collection;true;formIndex(_:offsetBy:);;;Argument[0..1];string-length",
188-
";Collection;true;formIndex(_:offsetBy:limitBy:);;;Argument[0..1];string-length",
189-
";Collection;true;removeFirst(_:);;;Argument[0];string-length",
190-
";RangeReplaceableCollection;true;removeLast(_:);;;Argument[0];string-length",
191185
";String;true;index(_:offsetBy:);;;Argument[0..1];string-length",
192186
";String;true;index(_:offsetBy:limitBy:);;;Argument[0..1];string-length",
193187
";String.Index;true;init(encodedOffset:);;;Argument[0];string-length",
@@ -203,3 +197,45 @@ private class StringLengthConflationSinks extends SinkModelCsv {
203197
]
204198
}
205199
}
200+
201+
/**
202+
* An extra sink that don't fit into the CSV scheme (because we care about the actual
203+
* type the method is being called on, not just the type it's declared on).
204+
*/
205+
private class ExtraStringLengthConflationSink extends StringLengthConflationSink {
206+
StringType stringType;
207+
208+
ExtraStringLengthConflationSink() {
209+
// sink is a length or offset argument of a call to `[stringType].[method]`.
210+
exists(CallExpr call |
211+
(
212+
stringType = TString()
213+
or
214+
stringType = TStringUtf8()
215+
or
216+
stringType = TStringUtf16()
217+
or
218+
stringType = TStringUnicodeScalars()
219+
) and
220+
(
221+
call.getQualifier().getType().(NominalType).getName() = stringType.getName() or
222+
call.getQualifier().getType().(InOutType).getObjectType().(NominalType).getName() =
223+
stringType.getName()
224+
) and
225+
(
226+
call.getStaticTarget().getName() =
227+
[
228+
"dropFirst(_:)", "dropLast(_:)", "prefix(_:)", "suffix(_:)", "removeFirst(_:)",
229+
"removeLast(_:)"
230+
] and
231+
this.asExpr() = call.getArgument(0).getExpr()
232+
or
233+
call.getStaticTarget().getName() =
234+
["formIndex(_:offsetBy:)", "formIndex(_:offsetBy:limitBy:)"] and
235+
this.asExpr() = call.getArgument([0, 1]).getExpr()
236+
)
237+
)
238+
}
239+
240+
override StringType getCorrectStringType() { result = stringType }
241+
}
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
---
2+
category: minorAnalysis
3+
---
4+
* Fixed some false positive results from the `swift/string-length-conflation` query, caused by imprecise sinks.

0 commit comments

Comments
 (0)