Skip to content

Commit 0264219

Browse files
committed
Ruby: Prevent positional matching when preceded by a splat
1 parent 3ca4888 commit 0264219

File tree

4 files changed

+22
-236
lines changed

4 files changed

+22
-236
lines changed

ruby/ql/lib/codeql/ruby/dataflow/internal/DataFlowPrivate.qll

Lines changed: 16 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,9 @@ private class Argument extends CfgNodes::ExprCfgNode {
195195
not this.getExpr().(Pair).getKey().getConstantValue().isSymbol(_) and
196196
not this.getExpr() instanceof HashSplatExpr and
197197
not this.getExpr() instanceof SplatExpr and
198-
arg.isPositional(i)
198+
arg.isPositional(i) and
199+
// There are no splat arguments before the positional argument
200+
not splatArgumentAt(call, any(int j | j < i))
199201
)
200202
or
201203
exists(CfgNodes::ExprNodes::PairCfgNode p |
@@ -217,7 +219,9 @@ private class Argument extends CfgNodes::ExprCfgNode {
217219
exists(int pos |
218220
this = call.getArgument(pos) and
219221
this.getExpr() instanceof SplatExpr and
220-
arg.isSplat(pos)
222+
arg.isSplat(pos) and
223+
// There are no earlier splat arguments
224+
not splatArgumentAt(call, any(int j | j < pos))
221225
)
222226
or
223227
this = call.getAnArgument() and
@@ -432,7 +436,7 @@ private predicate splatParameterAt(Callable c, int pos) {
432436
}
433437

434438
private predicate splatArgumentAt(CfgNodes::ExprNodes::CallCfgNode c, int pos) {
435-
exists(Argument arg, ArgumentPosition apos | arg.isArgumentOf(c, apos) and apos.isSplat(pos))
439+
c.getArgument(pos).getExpr() instanceof SplatExpr
436440
}
437441

438442
/** A collection of cached types and predicates to be evaluated in the same stage. */
@@ -920,7 +924,12 @@ private module ParameterNodes {
920924

921925
override predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
922926
exists(Callable callable | callable = c.asCfgScope() |
923-
exists(int i | pos.isPositional(i) and callable.getParameter(i) = parameter |
927+
exists(int i |
928+
pos.isPositional(i) and
929+
callable.getParameter(i) = parameter and
930+
// There are no splat parameters before the positional parameter
931+
not splatParameterAt(callable, any(int m | m < i))
932+
|
924933
parameter instanceof SimpleParameter
925934
or
926935
parameter instanceof OptionalParameter
@@ -939,7 +948,9 @@ private module ParameterNodes {
939948
parameter = callable.getParameter(n).(SplatParameter) and
940949
pos.isSplat(n) and
941950
// There are no positional parameters after the splat
942-
not exists(SimpleParameter p, int m | m > n | p = callable.getParameter(m))
951+
not exists(SimpleParameter p, int m | m > n | p = callable.getParameter(m)) and
952+
// There are no earlier splat parameters
953+
not splatParameterAt(callable, any(int m | m < n))
943954
)
944955
or
945956
parameter = callable.getAParameter().(BlockParameter) and

0 commit comments

Comments
 (0)