Skip to content

Commit 6e289a9

Browse files
committed
Ruby: Improvements to StringSubstitutionCall
- Handle block arguments - Recognise patterns passed via constants
1 parent 17dfb4e commit 6e289a9

File tree

1 file changed

+15
-5
lines changed

1 file changed

+15
-5
lines changed

ruby/ql/lib/codeql/ruby/frameworks/core/String.qll

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ class StringSubstitutionCall extends DataFlow::CallNode {
2020
this.getMethodName() = ["sub", "sub!", "gsub", "gsub!"] and
2121
exists(this.getReceiver()) and
2222
this.getNumberOfArguments() = 2
23+
or
24+
this.getNumberOfArguments() = 1 and exists(this.getBlock())
2325
}
2426

2527
/**
@@ -45,9 +47,10 @@ class StringSubstitutionCall extends DataFlow::CallNode {
4547
* call, if any.
4648
*/
4749
RE::RegExpPatternSource getPatternRegExp() {
48-
// TODO: using local flow means we miss regexps defined as constants outside
49-
// of the function scope.
5050
result.(DataFlow::LocalSourceNode).flowsTo(this.getPatternArgument())
51+
or
52+
result.asExpr().getExpr() =
53+
this.getPatternArgument().asExpr().getExpr().(ConstantReadAccess).getValue()
5154
}
5255

5356
/**
@@ -59,11 +62,19 @@ class StringSubstitutionCall extends DataFlow::CallNode {
5962
}
6063

6164
/**
62-
* Gets the string value passed as the second (replacement) argument in this
63-
* call, if any.
65+
* Gets the string value used to replace instances of the pattern, if any.
66+
* This includes values passed explicitly as the second argument and values
67+
* returned from the block, if one is given.
6468
*/
6569
string getReplacementString() {
6670
result = this.getReplacementArgument().asExpr().getConstantValue().getString()
71+
or
72+
exists(DataFlow::Node blockReturnNode, DataFlow::LocalSourceNode stringNode |
73+
exprNodeReturnedFrom(blockReturnNode, this.getBlock().asExpr().getExpr())
74+
|
75+
stringNode.flowsTo(blockReturnNode) and
76+
result = stringNode.asExpr().getConstantValue().getString()
77+
)
6778
}
6879

6980
/** Gets a string that is being replaced by this call. */
@@ -77,7 +88,6 @@ class StringSubstitutionCall extends DataFlow::CallNode {
7788
predicate replaces(string old, string new) {
7889
old = this.getAReplacedString() and
7990
new = this.getReplacementString()
80-
// TODO: handle block-variant of the call
8191
}
8292
}
8393

0 commit comments

Comments
 (0)