Skip to content

Commit faca4b5

Browse files
authored
Merge pull request github#11461 from hvitved/ruby/unique-hash-splat-param
Ruby: At most one hash-splat `ParameterNode` per callable
2 parents 07e4367 + b33f592 commit faca4b5

File tree

7 files changed

+40
-11
lines changed

7 files changed

+40
-11
lines changed

csharp/ql/lib/semmle/code/csharp/dataflow/internal/FlowSummaryImpl.qll

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -520,7 +520,8 @@ module Private {
520520
predicate summaryParameterNodeRange(SummarizedCallable c, ParameterPosition pos) {
521521
parameterReadState(c, _, pos)
522522
or
523-
isParameterPostUpdate(_, c, pos)
523+
// Same as `isParameterPostUpdate(_, c, pos)`, but can be used in a negative context
524+
any(SummaryNodeState state).isOutputState(c, SummaryComponentStack::argument(pos))
524525
}
525526

526527
private predicate callbackOutput(

go/ql/lib/semmle/go/dataflow/internal/FlowSummaryImpl.qll

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -520,7 +520,8 @@ module Private {
520520
predicate summaryParameterNodeRange(SummarizedCallable c, ParameterPosition pos) {
521521
parameterReadState(c, _, pos)
522522
or
523-
isParameterPostUpdate(_, c, pos)
523+
// Same as `isParameterPostUpdate(_, c, pos)`, but can be used in a negative context
524+
any(SummaryNodeState state).isOutputState(c, SummaryComponentStack::argument(pos))
524525
}
525526

526527
private predicate callbackOutput(

java/ql/lib/semmle/code/java/dataflow/internal/FlowSummaryImpl.qll

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -520,7 +520,8 @@ module Private {
520520
predicate summaryParameterNodeRange(SummarizedCallable c, ParameterPosition pos) {
521521
parameterReadState(c, _, pos)
522522
or
523-
isParameterPostUpdate(_, c, pos)
523+
// Same as `isParameterPostUpdate(_, c, pos)`, but can be used in a negative context
524+
any(SummaryNodeState state).isOutputState(c, SummaryComponentStack::argument(pos))
524525
}
525526

526527
private predicate callbackOutput(

python/ql/lib/semmle/python/dataflow/new/internal/FlowSummaryImpl.qll

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -520,7 +520,8 @@ module Private {
520520
predicate summaryParameterNodeRange(SummarizedCallable c, ParameterPosition pos) {
521521
parameterReadState(c, _, pos)
522522
or
523-
isParameterPostUpdate(_, c, pos)
523+
// Same as `isParameterPostUpdate(_, c, pos)`, but can be used in a negative context
524+
any(SummaryNodeState state).isOutputState(c, SummaryComponentStack::argument(pos))
524525
}
525526

526527
private predicate callbackOutput(

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

Lines changed: 28 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,18 @@ module LocalFlow {
183183
}
184184

185185
predicate localFlowStepCommon(Node nodeFrom, Node nodeTo) {
186+
exists(DataFlowCallable c | nodeFrom = TSynthHashSplatParameterNode(c) |
187+
exists(HashSplatParameter p |
188+
p.getCallable() = c.asCallable() and
189+
nodeTo = TNormalParameterNode(p)
190+
)
191+
or
192+
exists(ParameterPosition pos |
193+
nodeTo = TSummaryParameterNode(c.asLibraryCallable(), pos) and
194+
pos.isHashSplat()
195+
)
196+
)
197+
or
186198
localSsaFlowStep(nodeFrom, nodeTo)
187199
or
188200
nodeFrom.asExpr() = nodeTo.asExpr().(CfgNodes::ExprNodes::BlockArgumentCfgNode).getValue()
@@ -620,7 +632,9 @@ private module ParameterNodes {
620632
)
621633
or
622634
parameter = callable.getAParameter().(HashSplatParameter) and
623-
pos.isHashSplat()
635+
pos.isHashSplat() and
636+
// avoid overlap with `SynthHashSplatParameterNode`
637+
not callable.getAParameter() instanceof KeywordParameter
624638
or
625639
parameter = callable.getParameter(0).(SplatParameter) and
626640
pos.isSplatAll()
@@ -772,7 +786,16 @@ private module ParameterNodes {
772786
override Parameter getParameter() { none() }
773787

774788
override predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
775-
sc = c.asLibraryCallable() and pos = pos_
789+
sc = c.asLibraryCallable() and
790+
pos = pos_ and
791+
// avoid overlap with `SynthHashSplatParameterNode`
792+
not (
793+
pos.isHashSplat() and
794+
exists(ParameterPosition keywordPos |
795+
FlowSummaryImpl::Private::summaryParameterNodeRange(sc, keywordPos) and
796+
keywordPos.isKeyword(_)
797+
)
798+
)
776799
}
777800

778801
override CfgScope getCfgScope() { none() }
@@ -1174,11 +1197,11 @@ predicate clearsContent(Node n, ContentSet c) {
11741197
// Filter out keyword arguments that are part of the method signature from
11751198
// the hash-splat parameter
11761199
exists(
1177-
DataFlowCallable callable, ParameterPosition hashSplatPos, ParameterNodeImpl keywordParam,
1200+
DataFlowCallable callable, HashSplatParameter hashSplatParam, ParameterNodeImpl keywordParam,
11781201
ParameterPosition keywordPos, string name
11791202
|
1180-
n.(ParameterNodes::NormalParameterNode).isParameterOf(callable, hashSplatPos) and
1181-
hashSplatPos.isHashSplat() and
1203+
n = TNormalParameterNode(hashSplatParam) and
1204+
callable.asCallable() = hashSplatParam.getCallable() and
11821205
keywordParam.isParameterOf(callable, keywordPos) and
11831206
keywordPos.isKeyword(name) and
11841207
c = getKeywordContent(name)

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

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -520,7 +520,8 @@ module Private {
520520
predicate summaryParameterNodeRange(SummarizedCallable c, ParameterPosition pos) {
521521
parameterReadState(c, _, pos)
522522
or
523-
isParameterPostUpdate(_, c, pos)
523+
// Same as `isParameterPostUpdate(_, c, pos)`, but can be used in a negative context
524+
any(SummaryNodeState state).isOutputState(c, SummaryComponentStack::argument(pos))
524525
}
525526

526527
private predicate callbackOutput(

swift/ql/lib/codeql/swift/dataflow/internal/FlowSummaryImpl.qll

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -520,7 +520,8 @@ module Private {
520520
predicate summaryParameterNodeRange(SummarizedCallable c, ParameterPosition pos) {
521521
parameterReadState(c, _, pos)
522522
or
523-
isParameterPostUpdate(_, c, pos)
523+
// Same as `isParameterPostUpdate(_, c, pos)`, but can be used in a negative context
524+
any(SummaryNodeState state).isOutputState(c, SummaryComponentStack::argument(pos))
524525
}
525526

526527
private predicate callbackOutput(

0 commit comments

Comments
 (0)