Skip to content

Commit cc84464

Browse files
authored
Merge pull request github#3365 from hvitved/csharp/format-queries-path-problem
C#: Convert `string.format()` queries to path queries
2 parents 061f318 + d0c607c commit cc84464

File tree

7 files changed

+190
-83
lines changed

7 files changed

+190
-83
lines changed
Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/**
22
* @name Invalid format string
33
* @description Using a format string with an incorrect format causes a 'System.FormatException'.
4-
* @kind problem
4+
* @kind path-problem
55
* @problem.severity error
66
* @precision high
77
* @id cs/invalid-format-string
@@ -11,7 +11,8 @@
1111

1212
import csharp
1313
import semmle.code.csharp.frameworks.Format
14+
import FormatFlow
1415

15-
from FormatCall s, InvalidFormatString src
16-
where src = s.getAFormatSource()
17-
select src, "Invalid format string used in $@ formatting call.", s, "this"
16+
from FormatCall s, InvalidFormatString src, PathNode source, PathNode sink
17+
where hasFlowPath(src, source, s, sink)
18+
select src, source, sink, "Invalid format string used in $@ formatting call.", s, "this"
Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/**
22
* @name Missing format argument
33
* @description Supplying too few arguments to a format string causes a 'System.FormatException'.
4-
* @kind problem
4+
* @kind path-problem
55
* @problem.severity error
66
* @precision high
77
* @id cs/format-argument-missing
@@ -11,11 +11,14 @@
1111

1212
import csharp
1313
import semmle.code.csharp.frameworks.Format
14+
import FormatFlow
1415

15-
from FormatCall format, ValidFormatString src, int used, int supplied
16+
from
17+
FormatCall format, ValidFormatString src, int used, int supplied, PathNode source, PathNode sink
1618
where
17-
src = format.getAFormatSource() and
19+
hasFlowPath(src, source, format, sink) and
1820
used = src.getAnInsert() and
1921
supplied = format.getSuppliedArguments() and
2022
used >= supplied
21-
select format, "Argument '{" + used + "}' has not been supplied to $@ format string.", src, "this"
23+
select format, source, sink, "Argument '{" + used + "}' has not been supplied to $@ format string.",
24+
src, "this"
Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/**
22
* @name Unused format argument
33
* @description Supplying more arguments than are required for a format string may indicate an error in the format string.
4-
* @kind problem
4+
* @kind path-problem
55
* @problem.severity warning
66
* @precision high
77
* @id cs/format-argument-unused
@@ -11,11 +11,12 @@
1111

1212
import csharp
1313
import semmle.code.csharp.frameworks.Format
14+
import FormatFlow
1415

15-
from FormatCall format, int unused, ValidFormatString src
16+
from FormatCall format, int unused, ValidFormatString src, PathNode source, PathNode sink
1617
where
17-
src = format.getAFormatSource() and
18+
hasFlowPath(src, source, format, sink) and
1819
unused = format.getAnUnusedArgument(src) and
1920
not src.getValue() = ""
20-
select format, "The $@ ignores $@.", src, "format string", format.getSuppliedExpr(unused),
21-
"this supplied value"
21+
select format, source, sink, "The $@ ignores $@.", src, "format string",
22+
format.getSuppliedExpr(unused), "this supplied value"

csharp/ql/src/semmle/code/csharp/frameworks/Format.qll

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ class InvalidFormatString extends StringLiteral {
173173
}
174174

175175
/** Provides a dataflow configuration for format strings. */
176-
private module FormatFlow {
176+
module FormatFlow {
177177
private import semmle.code.csharp.dataflow.DataFlow
178178

179179
private class FormatConfiguration extends DataFlow2::Configuration {
@@ -186,12 +186,21 @@ private module FormatFlow {
186186
}
187187
}
188188

189-
predicate hasFlow(StringLiteral lit, Expr format) {
190-
exists(DataFlow::Node n1, DataFlow::Node n2, FormatConfiguration conf |
191-
n1.asExpr() = lit and n2.asExpr() = format
192-
|
193-
conf.hasFlow(n1, n2)
194-
)
189+
query predicate nodes = DataFlow2::PathGraph::nodes/3;
190+
191+
query predicate edges = DataFlow2::PathGraph::edges/2;
192+
193+
class PathNode = DataFlow2::PathNode;
194+
195+
/**
196+
* Holds if there is flow from string literal `lit` to the format string in
197+
* `call`. `litNode` and `formatNode` are the corresponding data-flow path
198+
* nodes.
199+
*/
200+
predicate hasFlowPath(StringLiteral lit, PathNode litNode, FormatCall call, PathNode formatNode) {
201+
litNode.getNode().asExpr() = lit and
202+
formatNode.getNode().asExpr() = call.getFormatExpr() and
203+
any(FormatConfiguration conf).hasFlowPath(litNode, formatNode)
195204
}
196205
}
197206

@@ -218,10 +227,12 @@ class FormatCall extends MethodCall {
218227
}
219228

220229
/**
230+
* DEPRECATED: Use `FormatFlow::hasFlowPath()` instead.
231+
*
221232
* Gets a format string. Global data flow analysis is applied to retrieve all
222233
* sources that can reach this method call.
223234
*/
224-
StringLiteral getAFormatSource() { FormatFlow::hasFlow(result, this.getFormatExpr()) }
235+
deprecated StringLiteral getAFormatSource() { FormatFlow::hasFlowPath(result, _, this, _) }
225236

226237
/**
227238
* Gets the number of supplied arguments (excluding the format string and format
@@ -245,7 +256,7 @@ class FormatCall extends MethodCall {
245256
/** Gets a supplied argument that is not used in the format string `src`. */
246257
int getAnUnusedArgument(ValidFormatString src) {
247258
result = this.getASuppliedArgument() and
248-
src = this.getAFormatSource() and
259+
FormatFlow::hasFlowPath(src, _, this, _) and
249260
not result = src.getAnInsert()
250261
}
251262
}

0 commit comments

Comments
 (0)