Skip to content

Commit 38fe9b7

Browse files
committed
Ruby: Use new parameter position for synthetic hash-splat instead
We wanted to ensure that a callable did not have multiple parameters with same parameter position. Originally we fixed this with e0bd210. This commit reverts that and solves it by introducing a new parameter position instead.
1 parent bdda0f5 commit 38fe9b7

File tree

2 files changed

+16
-26
lines changed

2 files changed

+16
-26
lines changed

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

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,13 @@ private module Cached {
441441
FlowSummaryImplSpecific::ParsePositions::isParsedKeywordArgumentPosition(_, name)
442442
} or
443443
THashSplatParameterPosition() or
444+
// To get flow from a hash-splat argument to a keyword parameter, we add a read-step
445+
// from a synthetic hash-splat parameter. We need this separate synthetic ParameterNode,
446+
// since we clear content of the normal hash-splat parameter for the names that
447+
// correspond to normal keyword parameters. Since we cannot re-use the same parameter
448+
// position for multiple parameter nodes in the same callable, we introduce this
449+
// synthetic parameter position.
450+
TSynthHashSplatParameterPosition() or
444451
TSplatAllParameterPosition() or
445452
TAnyParameterPosition() or
446453
TAnyKeywordParameterPosition()
@@ -1238,6 +1245,8 @@ class ParameterPosition extends TParameterPosition {
12381245
/** Holds if this position represents a hash-splat parameter. */
12391246
predicate isHashSplat() { this = THashSplatParameterPosition() }
12401247

1248+
predicate isSynthHashSplat() { this = TSynthHashSplatParameterPosition() }
1249+
12411250
predicate isSplatAll() { this = TSplatAllParameterPosition() }
12421251

12431252
/**
@@ -1263,6 +1272,8 @@ class ParameterPosition extends TParameterPosition {
12631272
or
12641273
this.isHashSplat() and result = "**"
12651274
or
1275+
this.isSynthHashSplat() and result = "synthetic **"
1276+
or
12661277
this.isSplatAll() and result = "*"
12671278
or
12681279
this.isAny() and result = "any"
@@ -1345,6 +1356,8 @@ predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) {
13451356
or
13461357
ppos.isHashSplat() and apos.isHashSplat()
13471358
or
1359+
ppos.isSynthHashSplat() and apos.isHashSplat()
1360+
or
13481361
ppos.isSplatAll() and apos.isSplatAll()
13491362
or
13501363
ppos.isAny() and argumentPositionIsNotSelf(apos)

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

Lines changed: 3 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -189,18 +189,6 @@ module LocalFlow {
189189
}
190190

191191
predicate localFlowStepCommon(Node nodeFrom, Node nodeTo) {
192-
exists(DataFlowCallable c | nodeFrom = TSynthHashSplatParameterNode(c) |
193-
exists(HashSplatParameter p |
194-
p.getCallable() = c.asCallable() and
195-
nodeTo = TNormalParameterNode(p)
196-
)
197-
or
198-
exists(ParameterPosition pos |
199-
nodeTo = TSummaryParameterNode(c.asLibraryCallable(), pos) and
200-
pos.isHashSplat()
201-
)
202-
)
203-
or
204192
localSsaFlowStep(nodeFrom, nodeTo)
205193
or
206194
nodeFrom.asExpr() = nodeTo.asExpr().(CfgNodes::ExprNodes::BlockArgumentCfgNode).getValue()
@@ -648,9 +636,7 @@ private module ParameterNodes {
648636
)
649637
or
650638
parameter = callable.getAParameter().(HashSplatParameter) and
651-
pos.isHashSplat() and
652-
// avoid overlap with `SynthHashSplatParameterNode`
653-
not callable.getAParameter() instanceof KeywordParameter
639+
pos.isHashSplat()
654640
or
655641
parameter = callable.getParameter(0).(SplatParameter) and
656642
pos.isSplatAll()
@@ -780,7 +766,7 @@ private module ParameterNodes {
780766
final override Parameter getParameter() { none() }
781767

782768
final override predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
783-
c = callable and pos.isHashSplat()
769+
c = callable and pos.isSynthHashSplat()
784770
}
785771

786772
final override CfgScope getCfgScope() { result = callable.asCallable() }
@@ -802,16 +788,7 @@ private module ParameterNodes {
802788
override Parameter getParameter() { none() }
803789

804790
override predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
805-
sc = c.asLibraryCallable() and
806-
pos = pos_ and
807-
// avoid overlap with `SynthHashSplatParameterNode`
808-
not (
809-
pos.isHashSplat() and
810-
exists(ParameterPosition keywordPos |
811-
FlowSummaryImpl::Private::summaryParameterNodeRange(sc, keywordPos) and
812-
keywordPos.isKeyword(_)
813-
)
814-
)
791+
sc = c.asLibraryCallable() and pos = pos_
815792
}
816793

817794
override CfgScope getCfgScope() { none() }

0 commit comments

Comments
 (0)