Skip to content

Commit 27f786b

Browse files
authored
Merge pull request #7442 from hvitved/ruby/dataflow/keyword-params
Ruby: Data flow for keyword arguments/parameters
2 parents 43b5d50 + 4133eb1 commit 27f786b

File tree

14 files changed

+374
-120
lines changed

14 files changed

+374
-120
lines changed

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

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -736,10 +736,17 @@ module Private {
736736
}
737737

738738
pragma[nomagic]
739-
private ParamNode summaryArgParam(ArgNode arg, ReturnKindExt rk, OutNodeExt out) {
740-
exists(DataFlowCall call, ParameterPosition ppos, SummarizedCallable sc |
739+
private ParamNode summaryArgParam0(DataFlowCall call, ArgNode arg) {
740+
exists(ParameterPosition ppos, SummarizedCallable sc |
741741
argumentPositionMatch(call, arg, ppos) and
742-
viableParam(call, sc, ppos, result) and
742+
viableParam(call, sc, ppos, result)
743+
)
744+
}
745+
746+
pragma[nomagic]
747+
private ParamNode summaryArgParam(ArgNode arg, ReturnKindExt rk, OutNodeExt out) {
748+
exists(DataFlowCall call |
749+
result = summaryArgParam0(call, arg) and
743750
out = rk.getAnOutNode(call)
744751
)
745752
}

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

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -736,10 +736,17 @@ module Private {
736736
}
737737

738738
pragma[nomagic]
739-
private ParamNode summaryArgParam(ArgNode arg, ReturnKindExt rk, OutNodeExt out) {
740-
exists(DataFlowCall call, ParameterPosition ppos, SummarizedCallable sc |
739+
private ParamNode summaryArgParam0(DataFlowCall call, ArgNode arg) {
740+
exists(ParameterPosition ppos, SummarizedCallable sc |
741741
argumentPositionMatch(call, arg, ppos) and
742-
viableParam(call, sc, ppos, result) and
742+
viableParam(call, sc, ppos, result)
743+
)
744+
}
745+
746+
pragma[nomagic]
747+
private ParamNode summaryArgParam(ArgNode arg, ReturnKindExt rk, OutNodeExt out) {
748+
exists(DataFlowCall call |
749+
result = summaryArgParam0(call, arg) and
743750
out = rk.getAnOutNode(call)
744751
)
745752
}

ruby/ql/lib/codeql/ruby/dataflow/FlowSummary.qll

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,10 +23,10 @@ module SummaryComponent {
2323
predicate content = SC::content/1;
2424

2525
/** Gets a summary component that represents a qualifier. */
26-
SummaryComponent qualifier() { result = argument(-1) }
26+
SummaryComponent qualifier() { result = argument(any(ParameterPosition pos | pos.isSelf())) }
2727

2828
/** Gets a summary component that represents a block argument. */
29-
SummaryComponent block() { result = argument(-2) }
29+
SummaryComponent block() { result = argument(any(ParameterPosition pos | pos.isBlock())) }
3030

3131
/** Gets a summary component that represents the return value of a call. */
3232
SummaryComponent return() { result = SC::return(any(NormalReturnKind rk)) }
@@ -102,10 +102,10 @@ abstract class SummarizedCallable extends LibraryCallable {
102102

103103
/**
104104
* Holds if values stored inside `content` are cleared on objects passed as
105-
* the `i`th argument to this callable.
105+
* arguments at position `pos` to this callable.
106106
*/
107107
pragma[nomagic]
108-
predicate clearsContent(int i, DataFlow::Content content) { none() }
108+
predicate clearsContent(ParameterPosition pos, DataFlow::Content content) { none() }
109109
}
110110

111111
private class SummarizedCallableAdapter extends Impl::Public::SummarizedCallable {
@@ -119,8 +119,8 @@ private class SummarizedCallableAdapter extends Impl::Public::SummarizedCallable
119119
sc.propagatesFlow(input, output, preservesValue)
120120
}
121121

122-
final override predicate clearsContent(ParameterPosition i, DataFlow::Content content) {
123-
sc.clearsContent(i, content)
122+
final override predicate clearsContent(ParameterPosition pos, DataFlow::Content content) {
123+
sc.clearsContent(pos, content)
124124
}
125125
}
126126

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

Lines changed: 81 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ private import DataFlowPrivate
44
private import codeql.ruby.typetracking.TypeTracker
55
private import codeql.ruby.ast.internal.Module
66
private import FlowSummaryImpl as FlowSummaryImpl
7+
private import FlowSummaryImplSpecific as FlowSummaryImplSpecific
78
private import codeql.ruby.dataflow.FlowSummary
89

910
newtype TReturnKind =
@@ -230,6 +231,30 @@ private module Cached {
230231
result = yieldCall(call)
231232
)
232233
}
234+
235+
cached
236+
newtype TArgumentPosition =
237+
TSelfArgumentPosition() or
238+
TBlockArgumentPosition() or
239+
TPositionalArgumentPosition(int pos) {
240+
exists(Call c | exists(c.getArgument(pos)))
241+
or
242+
FlowSummaryImplSpecific::ParsePositions::isParsedParameterPosition(_, pos)
243+
} or
244+
TKeywordArgumentPosition(string name) { name = any(KeywordParameter kp).getName() }
245+
246+
cached
247+
newtype TParameterPosition =
248+
TSelfParameterPosition() or
249+
TBlockParameterPosition() or
250+
TPositionalParameterPosition(int pos) {
251+
pos = any(Parameter p).getPosition()
252+
or
253+
pos in [0 .. 10] // TODO: remove once `Argument[_]` summaries are replaced with `Argument[i..]`
254+
or
255+
FlowSummaryImplSpecific::ParsePositions::isParsedArgumentPosition(_, pos)
256+
} or
257+
TKeywordParameterPosition(string name) { name = any(KeywordParameter kp).getName() }
233258
}
234259

235260
import Cached
@@ -458,18 +483,66 @@ predicate exprNodeReturnedFrom(DataFlow::ExprNode e, Callable c) {
458483
)
459484
}
460485

461-
private int parameterPosition() { result in [-2 .. max([any(Parameter p).getPosition(), 10])] }
486+
/** A parameter position. */
487+
class ParameterPosition extends TParameterPosition {
488+
/** Holds if this position represents a `self` parameter. */
489+
predicate isSelf() { this = TSelfParameterPosition() }
462490

463-
/** A parameter position represented by an integer. */
464-
class ParameterPosition extends int {
465-
ParameterPosition() { this = parameterPosition() }
491+
/** Holds if this position represents a block parameter. */
492+
predicate isBlock() { this = TBlockParameterPosition() }
493+
494+
/** Holds if this position represents a positional parameter at position `pos`. */
495+
predicate isPositional(int pos) { this = TPositionalParameterPosition(pos) }
496+
497+
/** Holds if this position represents a keyword parameter named `name`. */
498+
predicate isKeyword(string name) { this = TKeywordParameterPosition(name) }
499+
500+
/** Gets a textual representation of this position. */
501+
string toString() {
502+
this.isSelf() and result = "self"
503+
or
504+
this.isBlock() and result = "block"
505+
or
506+
exists(int pos | this.isPositional(pos) and result = "position " + pos)
507+
or
508+
exists(string name | this.isKeyword(name) and result = "keyword " + name)
509+
}
466510
}
467511

468-
/** An argument position represented by an integer. */
469-
class ArgumentPosition extends int {
470-
ArgumentPosition() { this = parameterPosition() }
512+
/** An argument position. */
513+
class ArgumentPosition extends TArgumentPosition {
514+
/** Holds if this position represents a `self` argument. */
515+
predicate isSelf() { this = TSelfArgumentPosition() }
516+
517+
/** Holds if this position represents a block argument. */
518+
predicate isBlock() { this = TBlockArgumentPosition() }
519+
520+
/** Holds if this position represents a positional argument at position `pos`. */
521+
predicate isPositional(int pos) { this = TPositionalArgumentPosition(pos) }
522+
523+
/** Holds if this position represents a keyword argument named `name`. */
524+
predicate isKeyword(string name) { this = TKeywordArgumentPosition(name) }
525+
526+
/** Gets a textual representation of this position. */
527+
string toString() {
528+
this.isSelf() and result = "self"
529+
or
530+
this.isBlock() and result = "block"
531+
or
532+
exists(int pos | this.isPositional(pos) and result = "position " + pos)
533+
or
534+
exists(string name | this.isKeyword(name) and result = "keyword " + name)
535+
}
471536
}
472537

473538
/** Holds if arguments at position `apos` match parameters at position `ppos`. */
474539
pragma[inline]
475-
predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) { ppos = apos }
540+
predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) {
541+
ppos.isSelf() and apos.isSelf()
542+
or
543+
ppos.isBlock() and apos.isBlock()
544+
or
545+
exists(int pos | ppos.isPositional(pos) and apos.isPositional(pos))
546+
or
547+
exists(string name | ppos.isKeyword(name) and apos.isKeyword(name))
548+
}

0 commit comments

Comments
 (0)