Ruby: track flow from *args to positional params

This models flow in the following case:

    def foo(x, y)
      sink x # 1
      sink y # 2
    end

    args = [source 1, source 2]
    foo(*args)

We do this by introducing a SynthSplatParameterNode which accepts
content from the splat argument, if one is given at the callsite.
From this node we add read steps to each positional parameter.
This commit is contained in:
Harry Maclean
2023-07-31 17:17:54 +01:00
parent 01ff690d51
commit 72356d1515
6 changed files with 270 additions and 25 deletions

View File

@@ -439,6 +439,7 @@ private module Cached {
} or
THashSplatArgumentPosition() or
TSplatAllArgumentPosition() or
TSplatArgumentPosition(int pos) { exists(Call c | c.getArgument(pos) instanceof SplatExpr) } or
TAnyArgumentPosition() or
TAnyKeywordArgumentPosition()
@@ -468,6 +469,10 @@ private module Cached {
// synthetic parameter position.
TSynthHashSplatParameterPosition() or
TSplatAllParameterPosition() or
TSplatParameterPosition(int pos) {
exists(Parameter p | p.getPosition() = pos and p instanceof SplatParameter)
} or
TSynthSplatParameterPosition() or
TAnyParameterPosition() or
TAnyKeywordParameterPosition()
}
@@ -1288,8 +1293,12 @@ class ParameterPosition extends TParameterPosition {
predicate isSynthHashSplat() { this = TSynthHashSplatParameterPosition() }
predicate isSynthSplat() { this = TSynthSplatParameterPosition() }
predicate isSplatAll() { this = TSplatAllParameterPosition() }
predicate isSplat(int n) { this = TSplatParameterPosition(n) }
/**
* Holds if this position represents any parameter, except `self` parameters. This
* includes both positional, named, and block parameters.
@@ -1320,6 +1329,10 @@ class ParameterPosition extends TParameterPosition {
this.isAny() and result = "any"
or
this.isAnyNamed() and result = "any-named"
or
this.isSynthSplat() and result = "synthetic *"
or
exists(int pos | this.isSplat(pos) and result = "* (position " + pos + ")")
}
}
@@ -1354,6 +1367,8 @@ class ArgumentPosition extends TArgumentPosition {
predicate isSplatAll() { this = TSplatAllArgumentPosition() }
predicate isSplat(int n) { this = TSplatArgumentPosition(n) }
/** Gets a textual representation of this position. */
string toString() {
this.isSelf() and result = "self"
@@ -1371,6 +1386,8 @@ class ArgumentPosition extends TArgumentPosition {
this.isHashSplat() and result = "**"
or
this.isSplatAll() and result = "*"
or
exists(int pos | this.isSplat(pos) and result = "* (position " + pos + ")")
}
}
@@ -1408,6 +1425,11 @@ predicate parameterMatch(ParameterPosition ppos, ArgumentPosition apos) {
ppos.isAnyNamed() and apos.isKeyword(_)
or
apos.isAnyNamed() and ppos.isKeyword(_)
or
ppos.isSynthSplat() and apos.isSplatAll()
or
// Exact splat match
exists(int n | apos.isSplat(n) and ppos.isSplat(n))
}
/**

View File

@@ -245,6 +245,7 @@ private class Argument extends CfgNodes::ExprCfgNode {
not this.getExpr() instanceof BlockArgument and
not this.getExpr().(Pair).getKey().getConstantValue().isSymbol(_) and
not this.getExpr() instanceof HashSplatExpr and
not this.getExpr() instanceof SplatExpr and
arg.isPositional(i)
)
or
@@ -261,8 +262,15 @@ private class Argument extends CfgNodes::ExprCfgNode {
arg.isHashSplat()
or
this = call.getArgument(0) and
not exists(call.getArgument(1)) and
this.getExpr() instanceof SplatExpr and
arg.isSplatAll()
or
exists(int pos | pos > 0 or exists(call.getArgument(pos + 1)) |
this = call.getArgument(pos) and
this.getExpr() instanceof SplatExpr and
arg.isSplat(pos)
)
}
/** Holds if this expression is the `i`th argument of `c`. */
@@ -300,6 +308,10 @@ private module Cached {
TSynthHashSplatParameterNode(DataFlowCallable c) {
isParameterNode(_, c, any(ParameterPosition p | p.isKeyword(_)))
} or
TSynthSplatParameterNode(DataFlowCallable c) {
exists(c.asCallable()) and // exclude library callables
isParameterNode(_, c, any(ParameterPosition p | p.isPositional(_)))
} or
TExprPostUpdateNode(CfgNodes::ExprCfgNode n) {
// filter out nodes that clearly don't need post-update nodes
isNonConstantExpr(n) and
@@ -318,7 +330,7 @@ private module Cached {
class TSourceParameterNode =
TNormalParameterNode or TBlockParameterNode or TSelfParameterNode or
TSynthHashSplatParameterNode;
TSynthHashSplatParameterNode or TSynthSplatParameterNode;
cached
Location getLocation(NodeImpl n) { result = n.getLocationImpl() }
@@ -514,6 +526,8 @@ predicate nodeIsHidden(Node n) {
n instanceof SynthHashSplatParameterNode
or
n instanceof SynthHashSplatArgumentNode
or
n instanceof SynthSplatParameterNode
}
/** An SSA definition, viewed as a node in a data flow graph. */
@@ -610,7 +624,13 @@ private module ParameterNodes {
pos.isHashSplat()
or
parameter = callable.getParameter(0).(SplatParameter) and
not exists(callable.getParameter(1)) and
pos.isSplatAll()
or
exists(int n | n > 0 |
parameter = callable.getParameter(n).(SplatParameter) and
pos.isSplat(n)
)
)
}
@@ -749,6 +769,66 @@ private module ParameterNodes {
final override string toStringImpl() { result = "**kwargs" }
}
/**
* A synthetic data-flow node to allow flow to positional parameters from a splat argument.
*
* For example, in the following code:
*
* ```rb
* def foo(x, y); end
*
* foo(*[a, b])
* ```
*
* We want `a` to flow to `x` and `b` to flow to `y`. We do this by constructing
* a `SynthSplatParameterNode` for the method `foo`, and matching the splat argument to this
* parameter node via `parameterMatch/2`. We then add read steps from this node to parameters
* `x` and `y`, for content at indices 0 and 1 respectively (see `readStep`).
*
* We don't yet correctly handle cases where the splat argument is not the first argument, e.g. in
* ```rb
* foo(a, *[b])
* ```
*/
class SynthSplatParameterNode extends ParameterNodeImpl, TSynthSplatParameterNode {
private DataFlowCallable callable;
SynthSplatParameterNode() { this = TSynthSplatParameterNode(callable) }
/**
* Gets a parameter which will contain the value given by `c`, assuming
* that the method was called with a single splat argument.
* For example, if the synth splat parameter is for the following method
*
* ```rb
* def foo(x, y, a:, *rest)
* end
* ```
*
* Then `getAParameter(element 0) = x` and `getAParameter(element 1) = y`.
*/
ParameterNode getAParameter(ContentSet c) {
exists(int n |
isParameterNode(result, callable, (any(ParameterPosition p | p.isPositional(n)))) and
c = getPositionalContent(n)
)
}
final override Parameter getParameter() { none() }
final override predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
c = callable and pos.isSynthSplat()
}
final override CfgScope getCfgScope() { result = callable.asCallable() }
final override DataFlowCallable getEnclosingCallable() { result = callable }
final override Location getLocationImpl() { result = callable.getLocation() }
final override string toStringImpl() { result = "synthetic *args" }
}
/** A parameter for a library callable with a flow summary. */
class SummaryParameterNode extends ParameterNodeImpl, FlowSummaryNode {
private ParameterPosition pos_;
@@ -1099,6 +1179,13 @@ private ContentSet getKeywordContent(string name) {
)
}
private ContentSet getPositionalContent(int n) {
exists(ConstantValue::ConstantIntegerValue i |
result.isSingleton(TKnownElementContent(i)) and
i.isInt(n)
)
}
/**
* Subset of `storeStep` that should be shared with type-tracking.
*/
@@ -1187,6 +1274,8 @@ predicate readStep(Node node1, ContentSet c, Node node2) {
or
node2 = node1.(SynthHashSplatParameterNode).getAKeywordParameter(c)
or
node2 = node1.(SynthSplatParameterNode).getAParameter(c)
or
FlowSummaryImpl::Private::Steps::summaryReadStep(node1.(FlowSummaryNode).getSummaryNode(), c,
node2.(FlowSummaryNode).getSummaryNode())
}

View File

@@ -2796,6 +2796,7 @@
| UseUseExplosion.rb:21:3675:21:3680 | call to use | UseUseExplosion.rb:21:3670:21:3680 | else ... |
| UseUseExplosion.rb:21:3686:21:3696 | else ... | UseUseExplosion.rb:21:9:21:3700 | if ... |
| UseUseExplosion.rb:21:3691:21:3696 | call to use | UseUseExplosion.rb:21:3686:21:3696 | else ... |
| UseUseExplosion.rb:24:5:25:7 | synthetic *args | UseUseExplosion.rb:24:13:24:13 | i |
| UseUseExplosion.rb:24:5:25:7 | use | UseUseExplosion.rb:1:1:26:3 | C |
| file://:0:0:0:0 | [summary param] position 0 in & | file://:0:0:0:0 | [summary] read: Argument[0].Element[any] in & |
| file://:0:0:0:0 | [summary param] position 0 in + | file://:0:0:0:0 | [summary] read: Argument[0].Element[any] in + |
@@ -2840,6 +2841,7 @@
| file://:0:0:0:0 | [summary] read: Argument[0].Element[any] in Hash[] | file://:0:0:0:0 | [summary] read: Argument[0].Element[any].Element[1] in Hash[] |
| local_dataflow.rb:1:1:7:3 | self (foo) | local_dataflow.rb:3:8:3:10 | self |
| local_dataflow.rb:1:1:7:3 | self in foo | local_dataflow.rb:1:1:7:3 | self (foo) |
| local_dataflow.rb:1:1:7:3 | synthetic *args | local_dataflow.rb:1:9:1:9 | a |
| local_dataflow.rb:1:1:150:3 | self (local_dataflow.rb) | local_dataflow.rb:49:1:53:3 | self |
| local_dataflow.rb:1:9:1:9 | a | local_dataflow.rb:1:9:1:9 | a |
| local_dataflow.rb:1:9:1:9 | a | local_dataflow.rb:2:7:2:7 | a |
@@ -2874,6 +2876,7 @@
| local_dataflow.rb:10:5:13:3 | __synth__0__1 | local_dataflow.rb:10:5:13:3 | __synth__0__1 |
| local_dataflow.rb:10:5:13:3 | __synth__0__1 | local_dataflow.rb:10:9:10:9 | x |
| local_dataflow.rb:10:5:13:3 | call to each | local_dataflow.rb:10:1:13:3 | ... = ... |
| local_dataflow.rb:10:5:13:3 | synthetic *args | local_dataflow.rb:10:5:13:3 | __synth__0__1 |
| local_dataflow.rb:10:9:10:9 | x | local_dataflow.rb:12:5:12:5 | x |
| local_dataflow.rb:10:14:10:18 | [post] array | local_dataflow.rb:15:10:15:14 | array |
| local_dataflow.rb:10:14:10:18 | array | local_dataflow.rb:15:10:15:14 | array |
@@ -2883,6 +2886,7 @@
| local_dataflow.rb:15:1:17:3 | __synth__0__1 | local_dataflow.rb:15:1:17:3 | __synth__0__1 |
| local_dataflow.rb:15:1:17:3 | __synth__0__1 | local_dataflow.rb:15:1:17:3 | __synth__0__1 |
| local_dataflow.rb:15:1:17:3 | __synth__0__1 | local_dataflow.rb:15:5:15:5 | x |
| local_dataflow.rb:15:1:17:3 | synthetic *args | local_dataflow.rb:15:1:17:3 | __synth__0__1 |
| local_dataflow.rb:15:10:15:14 | [post] array | local_dataflow.rb:19:10:19:14 | array |
| local_dataflow.rb:15:10:15:14 | array | local_dataflow.rb:19:10:19:14 | array |
| local_dataflow.rb:16:9:16:10 | 10 | local_dataflow.rb:16:3:16:10 | break |
@@ -2890,6 +2894,7 @@
| local_dataflow.rb:19:1:21:3 | __synth__0__1 | local_dataflow.rb:19:1:21:3 | __synth__0__1 |
| local_dataflow.rb:19:1:21:3 | __synth__0__1 | local_dataflow.rb:19:1:21:3 | __synth__0__1 |
| local_dataflow.rb:19:1:21:3 | __synth__0__1 | local_dataflow.rb:19:5:19:5 | x |
| local_dataflow.rb:19:1:21:3 | synthetic *args | local_dataflow.rb:19:1:21:3 | __synth__0__1 |
| local_dataflow.rb:19:5:19:5 | x | local_dataflow.rb:20:6:20:6 | x |
| local_dataflow.rb:20:6:20:6 | x | local_dataflow.rb:20:6:20:10 | ... > ... |
| local_dataflow.rb:20:10:20:10 | 1 | local_dataflow.rb:20:6:20:10 | ... > ... |
@@ -2901,11 +2906,13 @@
| local_dataflow.rb:30:14:30:20 | "class" | local_dataflow.rb:30:5:30:24 | C |
| local_dataflow.rb:32:5:32:25 | bar | local_dataflow.rb:32:1:32:1 | x |
| local_dataflow.rb:32:5:32:25 | bar | local_dataflow.rb:32:1:32:25 | ... = ... |
| local_dataflow.rb:34:1:39:3 | synthetic *args | local_dataflow.rb:34:7:34:7 | x |
| local_dataflow.rb:34:7:34:7 | x | local_dataflow.rb:34:7:34:7 | x |
| local_dataflow.rb:34:7:34:7 | x | local_dataflow.rb:35:6:35:6 | x |
| local_dataflow.rb:35:6:35:6 | x | local_dataflow.rb:35:6:35:11 | ... == ... |
| local_dataflow.rb:35:11:35:11 | 4 | local_dataflow.rb:35:6:35:11 | ... == ... |
| local_dataflow.rb:36:13:36:13 | 7 | local_dataflow.rb:36:6:36:13 | return |
| local_dataflow.rb:41:1:47:3 | synthetic *args | local_dataflow.rb:41:7:41:7 | x |
| local_dataflow.rb:41:7:41:7 | x | local_dataflow.rb:41:7:41:7 | x |
| local_dataflow.rb:41:7:41:7 | x | local_dataflow.rb:42:6:42:6 | x |
| local_dataflow.rb:42:6:42:6 | x | local_dataflow.rb:42:6:42:11 | ... == ... |
@@ -2924,8 +2931,10 @@
| local_dataflow.rb:51:20:51:20 | x | local_dataflow.rb:51:20:51:24 | ... < ... |
| local_dataflow.rb:51:24:51:24 | 9 | local_dataflow.rb:51:20:51:24 | ... < ... |
| local_dataflow.rb:55:5:55:13 | Array | local_dataflow.rb:55:5:55:13 | call to [] |
| local_dataflow.rb:57:1:58:3 | synthetic *args | local_dataflow.rb:57:9:57:9 | x |
| local_dataflow.rb:60:1:90:3 | self (test_case) | local_dataflow.rb:78:12:78:20 | self |
| local_dataflow.rb:60:1:90:3 | self in test_case | local_dataflow.rb:60:1:90:3 | self (test_case) |
| local_dataflow.rb:60:1:90:3 | synthetic *args | local_dataflow.rb:60:15:60:15 | x |
| local_dataflow.rb:60:15:60:15 | x | local_dataflow.rb:60:15:60:15 | x |
| local_dataflow.rb:60:15:60:15 | x | local_dataflow.rb:61:12:61:12 | x |
| local_dataflow.rb:61:7:68:5 | SSA phi read(x) | local_dataflow.rb:69:12:69:12 | x |
@@ -3098,6 +3107,7 @@
| local_dataflow.rb:118:3:118:11 | call to source | local_dataflow.rb:118:3:118:31 | call to tap |
| local_dataflow.rb:118:3:118:11 | self | local_dataflow.rb:119:3:119:31 | self |
| local_dataflow.rb:118:17:118:31 | <captured entry> self | local_dataflow.rb:118:23:118:29 | self |
| local_dataflow.rb:118:17:118:31 | synthetic *args | local_dataflow.rb:118:20:118:20 | x |
| local_dataflow.rb:118:20:118:20 | x | local_dataflow.rb:118:20:118:20 | x |
| local_dataflow.rb:118:20:118:20 | x | local_dataflow.rb:118:28:118:28 | x |
| local_dataflow.rb:119:3:119:31 | [post] self | local_dataflow.rb:119:8:119:16 | self |
@@ -3112,8 +3122,10 @@
| local_dataflow.rb:123:8:123:20 | call to dup | local_dataflow.rb:123:8:123:45 | call to tap |
| local_dataflow.rb:123:8:123:45 | call to tap | local_dataflow.rb:123:8:123:49 | call to dup |
| local_dataflow.rb:123:26:123:45 | <captured entry> self | local_dataflow.rb:123:32:123:43 | self |
| local_dataflow.rb:123:26:123:45 | synthetic *args | local_dataflow.rb:123:29:123:29 | x |
| local_dataflow.rb:126:1:128:3 | self (use) | local_dataflow.rb:127:3:127:8 | self |
| local_dataflow.rb:126:1:128:3 | self in use | local_dataflow.rb:126:1:128:3 | self (use) |
| local_dataflow.rb:126:1:128:3 | synthetic *args | local_dataflow.rb:126:9:126:9 | x |
| local_dataflow.rb:130:1:150:3 | self (use_use_madness) | local_dataflow.rb:132:6:132:11 | self |
| local_dataflow.rb:130:1:150:3 | self in use_use_madness | local_dataflow.rb:130:1:150:3 | self (use_use_madness) |
| local_dataflow.rb:131:3:131:3 | x | local_dataflow.rb:132:10:132:10 | x |

View File

@@ -42,15 +42,49 @@ edges
| params_flow.rb:41:24:41:29 | ** ... [element :p1] | params_flow.rb:16:13:16:14 | p1 |
| params_flow.rb:41:26:41:29 | args [element :p1] | params_flow.rb:41:24:41:29 | ** ... [element :p1] |
| params_flow.rb:44:12:44:20 | call to taint | params_flow.rb:9:16:9:17 | p1 |
| params_flow.rb:46:1:46:4 | args [element 0] | params_flow.rb:47:13:47:16 | args [element 0] |
| params_flow.rb:46:1:46:4 | args [element 1] | params_flow.rb:47:13:47:16 | args [element 1] |
| params_flow.rb:46:9:46:17 | call to taint | params_flow.rb:46:1:46:4 | args [element 0] |
| params_flow.rb:46:20:46:28 | call to taint | params_flow.rb:46:1:46:4 | args [element 1] |
| params_flow.rb:47:12:47:16 | * ... [element 0] | params_flow.rb:9:16:9:17 | p1 |
| params_flow.rb:47:12:47:16 | * ... [element 1] | params_flow.rb:9:20:9:21 | p2 |
| params_flow.rb:47:13:47:16 | args [element 0] | params_flow.rb:47:12:47:16 | * ... [element 0] |
| params_flow.rb:47:13:47:16 | args [element 1] | params_flow.rb:47:12:47:16 | * ... [element 1] |
| params_flow.rb:49:13:49:14 | p1 | params_flow.rb:50:10:50:11 | p1 |
| params_flow.rb:54:9:54:17 | call to taint | params_flow.rb:49:13:49:14 | p1 |
| params_flow.rb:57:9:57:17 | call to taint | params_flow.rb:49:13:49:14 | p1 |
| params_flow.rb:62:1:62:4 | args | params_flow.rb:66:13:66:16 | args |
| params_flow.rb:62:8:62:16 | call to taint | params_flow.rb:62:1:62:4 | args |
| params_flow.rb:63:16:63:17 | *x [element 0] | params_flow.rb:64:10:64:10 | x [element 0] |
| params_flow.rb:64:10:64:10 | x [element 0] | params_flow.rb:64:10:64:13 | ...[...] |
| params_flow.rb:66:12:66:16 | * ... [element 0] | params_flow.rb:63:16:63:17 | *x [element 0] |
| params_flow.rb:66:13:66:16 | args | params_flow.rb:66:12:66:16 | * ... [element 0] |
| params_flow.rb:49:17:49:24 | *posargs [element 0] | params_flow.rb:51:11:51:17 | posargs [element 0] |
| params_flow.rb:51:11:51:17 | posargs [element 0] | params_flow.rb:51:11:51:20 | ...[...] |
| params_flow.rb:51:11:51:20 | ...[...] | params_flow.rb:51:10:51:21 | ( ... ) |
| params_flow.rb:55:9:55:17 | call to taint | params_flow.rb:49:13:49:14 | p1 |
| params_flow.rb:57:1:57:4 | args [element 0] | params_flow.rb:58:21:58:24 | args [element 0] |
| params_flow.rb:57:9:57:17 | call to taint | params_flow.rb:57:1:57:4 | args [element 0] |
| params_flow.rb:58:9:58:17 | call to taint | params_flow.rb:49:13:49:14 | p1 |
| params_flow.rb:58:20:58:24 | * ... [element 0] | params_flow.rb:49:17:49:24 | *posargs [element 0] |
| params_flow.rb:58:21:58:24 | args [element 0] | params_flow.rb:58:20:58:24 | * ... [element 0] |
| params_flow.rb:60:1:60:4 | args [element 0] | params_flow.rb:61:10:61:13 | args [element 0] |
| params_flow.rb:60:9:60:17 | call to taint | params_flow.rb:60:1:60:4 | args [element 0] |
| params_flow.rb:61:9:61:13 | * ... [element 0] | params_flow.rb:49:13:49:14 | p1 |
| params_flow.rb:61:10:61:13 | args [element 0] | params_flow.rb:61:9:61:13 | * ... [element 0] |
| params_flow.rb:63:1:63:4 | args | params_flow.rb:67:13:67:16 | args |
| params_flow.rb:63:8:63:16 | call to taint | params_flow.rb:63:1:63:4 | args |
| params_flow.rb:64:16:64:17 | *x [element 0] | params_flow.rb:65:10:65:10 | x [element 0] |
| params_flow.rb:65:10:65:10 | x [element 0] | params_flow.rb:65:10:65:13 | ...[...] |
| params_flow.rb:67:12:67:16 | * ... [element 0] | params_flow.rb:64:16:64:17 | *x [element 0] |
| params_flow.rb:67:13:67:16 | args | params_flow.rb:67:12:67:16 | * ... [element 0] |
| params_flow.rb:69:14:69:14 | x | params_flow.rb:70:10:70:10 | x |
| params_flow.rb:69:17:69:17 | y | params_flow.rb:71:10:71:10 | y |
| params_flow.rb:69:24:69:24 | w | params_flow.rb:74:10:74:10 | w |
| params_flow.rb:69:27:69:27 | r | params_flow.rb:75:10:75:10 | r |
| params_flow.rb:78:10:78:18 | call to taint | params_flow.rb:69:14:69:14 | x |
| params_flow.rb:78:21:78:29 | call to taint | params_flow.rb:69:17:69:17 | y |
| params_flow.rb:78:43:78:51 | call to taint | params_flow.rb:69:24:69:24 | w |
| params_flow.rb:78:54:78:62 | call to taint | params_flow.rb:69:27:69:27 | r |
| params_flow.rb:81:10:81:18 | call to taint | params_flow.rb:69:14:69:14 | x |
| params_flow.rb:83:14:83:14 | t | params_flow.rb:84:10:84:10 | t |
| params_flow.rb:83:17:83:17 | u | params_flow.rb:85:10:85:10 | u |
| params_flow.rb:83:23:83:23 | w | params_flow.rb:87:10:87:10 | w |
| params_flow.rb:94:10:94:18 | call to taint | params_flow.rb:83:14:83:14 | t |
| params_flow.rb:94:21:94:29 | call to taint | params_flow.rb:83:17:83:17 | u |
| params_flow.rb:94:39:94:47 | call to taint | params_flow.rb:83:23:83:23 | w |
nodes
| params_flow.rb:9:16:9:17 | p1 | semmle.label | p1 |
| params_flow.rb:9:20:9:21 | p2 | semmle.label | p2 |
@@ -100,22 +134,66 @@ nodes
| params_flow.rb:41:24:41:29 | ** ... [element :p1] | semmle.label | ** ... [element :p1] |
| params_flow.rb:41:26:41:29 | args [element :p1] | semmle.label | args [element :p1] |
| params_flow.rb:44:12:44:20 | call to taint | semmle.label | call to taint |
| params_flow.rb:46:1:46:4 | args [element 0] | semmle.label | args [element 0] |
| params_flow.rb:46:1:46:4 | args [element 1] | semmle.label | args [element 1] |
| params_flow.rb:46:9:46:17 | call to taint | semmle.label | call to taint |
| params_flow.rb:46:20:46:28 | call to taint | semmle.label | call to taint |
| params_flow.rb:47:12:47:16 | * ... [element 0] | semmle.label | * ... [element 0] |
| params_flow.rb:47:12:47:16 | * ... [element 1] | semmle.label | * ... [element 1] |
| params_flow.rb:47:13:47:16 | args [element 0] | semmle.label | args [element 0] |
| params_flow.rb:47:13:47:16 | args [element 1] | semmle.label | args [element 1] |
| params_flow.rb:49:13:49:14 | p1 | semmle.label | p1 |
| params_flow.rb:49:17:49:24 | *posargs [element 0] | semmle.label | *posargs [element 0] |
| params_flow.rb:50:10:50:11 | p1 | semmle.label | p1 |
| params_flow.rb:54:9:54:17 | call to taint | semmle.label | call to taint |
| params_flow.rb:51:10:51:21 | ( ... ) | semmle.label | ( ... ) |
| params_flow.rb:51:11:51:17 | posargs [element 0] | semmle.label | posargs [element 0] |
| params_flow.rb:51:11:51:20 | ...[...] | semmle.label | ...[...] |
| params_flow.rb:55:9:55:17 | call to taint | semmle.label | call to taint |
| params_flow.rb:57:1:57:4 | args [element 0] | semmle.label | args [element 0] |
| params_flow.rb:57:9:57:17 | call to taint | semmle.label | call to taint |
| params_flow.rb:62:1:62:4 | args | semmle.label | args |
| params_flow.rb:62:8:62:16 | call to taint | semmle.label | call to taint |
| params_flow.rb:63:16:63:17 | *x [element 0] | semmle.label | *x [element 0] |
| params_flow.rb:64:10:64:10 | x [element 0] | semmle.label | x [element 0] |
| params_flow.rb:64:10:64:13 | ...[...] | semmle.label | ...[...] |
| params_flow.rb:66:12:66:16 | * ... [element 0] | semmle.label | * ... [element 0] |
| params_flow.rb:66:13:66:16 | args | semmle.label | args |
| params_flow.rb:58:9:58:17 | call to taint | semmle.label | call to taint |
| params_flow.rb:58:20:58:24 | * ... [element 0] | semmle.label | * ... [element 0] |
| params_flow.rb:58:21:58:24 | args [element 0] | semmle.label | args [element 0] |
| params_flow.rb:60:1:60:4 | args [element 0] | semmle.label | args [element 0] |
| params_flow.rb:60:9:60:17 | call to taint | semmle.label | call to taint |
| params_flow.rb:61:9:61:13 | * ... [element 0] | semmle.label | * ... [element 0] |
| params_flow.rb:61:10:61:13 | args [element 0] | semmle.label | args [element 0] |
| params_flow.rb:63:1:63:4 | args | semmle.label | args |
| params_flow.rb:63:8:63:16 | call to taint | semmle.label | call to taint |
| params_flow.rb:64:16:64:17 | *x [element 0] | semmle.label | *x [element 0] |
| params_flow.rb:65:10:65:10 | x [element 0] | semmle.label | x [element 0] |
| params_flow.rb:65:10:65:13 | ...[...] | semmle.label | ...[...] |
| params_flow.rb:67:12:67:16 | * ... [element 0] | semmle.label | * ... [element 0] |
| params_flow.rb:67:13:67:16 | args | semmle.label | args |
| params_flow.rb:69:14:69:14 | x | semmle.label | x |
| params_flow.rb:69:17:69:17 | y | semmle.label | y |
| params_flow.rb:69:24:69:24 | w | semmle.label | w |
| params_flow.rb:69:27:69:27 | r | semmle.label | r |
| params_flow.rb:70:10:70:10 | x | semmle.label | x |
| params_flow.rb:71:10:71:10 | y | semmle.label | y |
| params_flow.rb:74:10:74:10 | w | semmle.label | w |
| params_flow.rb:75:10:75:10 | r | semmle.label | r |
| params_flow.rb:78:10:78:18 | call to taint | semmle.label | call to taint |
| params_flow.rb:78:21:78:29 | call to taint | semmle.label | call to taint |
| params_flow.rb:78:43:78:51 | call to taint | semmle.label | call to taint |
| params_flow.rb:78:54:78:62 | call to taint | semmle.label | call to taint |
| params_flow.rb:81:10:81:18 | call to taint | semmle.label | call to taint |
| params_flow.rb:83:14:83:14 | t | semmle.label | t |
| params_flow.rb:83:17:83:17 | u | semmle.label | u |
| params_flow.rb:83:23:83:23 | w | semmle.label | w |
| params_flow.rb:84:10:84:10 | t | semmle.label | t |
| params_flow.rb:85:10:85:10 | u | semmle.label | u |
| params_flow.rb:87:10:87:10 | w | semmle.label | w |
| params_flow.rb:94:10:94:18 | call to taint | semmle.label | call to taint |
| params_flow.rb:94:21:94:29 | call to taint | semmle.label | call to taint |
| params_flow.rb:94:39:94:47 | call to taint | semmle.label | call to taint |
subpaths
#select
| params_flow.rb:10:10:10:11 | p1 | params_flow.rb:14:12:14:19 | call to taint | params_flow.rb:10:10:10:11 | p1 | $@ | params_flow.rb:14:12:14:19 | call to taint | call to taint |
| params_flow.rb:10:10:10:11 | p1 | params_flow.rb:44:12:44:20 | call to taint | params_flow.rb:10:10:10:11 | p1 | $@ | params_flow.rb:44:12:44:20 | call to taint | call to taint |
| params_flow.rb:10:10:10:11 | p1 | params_flow.rb:46:9:46:17 | call to taint | params_flow.rb:10:10:10:11 | p1 | $@ | params_flow.rb:46:9:46:17 | call to taint | call to taint |
| params_flow.rb:11:10:11:11 | p2 | params_flow.rb:14:22:14:29 | call to taint | params_flow.rb:11:10:11:11 | p2 | $@ | params_flow.rb:14:22:14:29 | call to taint | call to taint |
| params_flow.rb:11:10:11:11 | p2 | params_flow.rb:46:20:46:28 | call to taint | params_flow.rb:11:10:11:11 | p2 | $@ | params_flow.rb:46:20:46:28 | call to taint | call to taint |
| params_flow.rb:17:10:17:11 | p1 | params_flow.rb:21:13:21:20 | call to taint | params_flow.rb:17:10:17:11 | p1 | $@ | params_flow.rb:21:13:21:20 | call to taint | call to taint |
| params_flow.rb:17:10:17:11 | p1 | params_flow.rb:22:27:22:34 | call to taint | params_flow.rb:17:10:17:11 | p1 | $@ | params_flow.rb:22:27:22:34 | call to taint | call to taint |
| params_flow.rb:17:10:17:11 | p1 | params_flow.rb:23:33:23:40 | call to taint | params_flow.rb:17:10:17:11 | p1 | $@ | params_flow.rb:23:33:23:40 | call to taint | call to taint |
@@ -131,6 +209,16 @@ subpaths
| params_flow.rb:28:10:28:22 | ( ... ) | params_flow.rb:37:34:37:42 | call to taint | params_flow.rb:28:10:28:22 | ( ... ) | $@ | params_flow.rb:37:34:37:42 | call to taint | call to taint |
| params_flow.rb:29:10:29:22 | ( ... ) | params_flow.rb:33:41:33:49 | call to taint | params_flow.rb:29:10:29:22 | ( ... ) | $@ | params_flow.rb:33:41:33:49 | call to taint | call to taint |
| params_flow.rb:29:10:29:22 | ( ... ) | params_flow.rb:34:14:34:22 | call to taint | params_flow.rb:29:10:29:22 | ( ... ) | $@ | params_flow.rb:34:14:34:22 | call to taint | call to taint |
| params_flow.rb:50:10:50:11 | p1 | params_flow.rb:54:9:54:17 | call to taint | params_flow.rb:50:10:50:11 | p1 | $@ | params_flow.rb:54:9:54:17 | call to taint | call to taint |
| params_flow.rb:50:10:50:11 | p1 | params_flow.rb:57:9:57:17 | call to taint | params_flow.rb:50:10:50:11 | p1 | $@ | params_flow.rb:57:9:57:17 | call to taint | call to taint |
| params_flow.rb:64:10:64:13 | ...[...] | params_flow.rb:62:8:62:16 | call to taint | params_flow.rb:64:10:64:13 | ...[...] | $@ | params_flow.rb:62:8:62:16 | call to taint | call to taint |
| params_flow.rb:50:10:50:11 | p1 | params_flow.rb:55:9:55:17 | call to taint | params_flow.rb:50:10:50:11 | p1 | $@ | params_flow.rb:55:9:55:17 | call to taint | call to taint |
| params_flow.rb:50:10:50:11 | p1 | params_flow.rb:58:9:58:17 | call to taint | params_flow.rb:50:10:50:11 | p1 | $@ | params_flow.rb:58:9:58:17 | call to taint | call to taint |
| params_flow.rb:50:10:50:11 | p1 | params_flow.rb:60:9:60:17 | call to taint | params_flow.rb:50:10:50:11 | p1 | $@ | params_flow.rb:60:9:60:17 | call to taint | call to taint |
| params_flow.rb:51:10:51:21 | ( ... ) | params_flow.rb:57:9:57:17 | call to taint | params_flow.rb:51:10:51:21 | ( ... ) | $@ | params_flow.rb:57:9:57:17 | call to taint | call to taint |
| params_flow.rb:65:10:65:13 | ...[...] | params_flow.rb:63:8:63:16 | call to taint | params_flow.rb:65:10:65:13 | ...[...] | $@ | params_flow.rb:63:8:63:16 | call to taint | call to taint |
| params_flow.rb:70:10:70:10 | x | params_flow.rb:78:10:78:18 | call to taint | params_flow.rb:70:10:70:10 | x | $@ | params_flow.rb:78:10:78:18 | call to taint | call to taint |
| params_flow.rb:70:10:70:10 | x | params_flow.rb:81:10:81:18 | call to taint | params_flow.rb:70:10:70:10 | x | $@ | params_flow.rb:81:10:81:18 | call to taint | call to taint |
| params_flow.rb:71:10:71:10 | y | params_flow.rb:78:21:78:29 | call to taint | params_flow.rb:71:10:71:10 | y | $@ | params_flow.rb:78:21:78:29 | call to taint | call to taint |
| params_flow.rb:74:10:74:10 | w | params_flow.rb:78:43:78:51 | call to taint | params_flow.rb:74:10:74:10 | w | $@ | params_flow.rb:78:43:78:51 | call to taint | call to taint |
| params_flow.rb:75:10:75:10 | r | params_flow.rb:78:54:78:62 | call to taint | params_flow.rb:75:10:75:10 | r | $@ | params_flow.rb:78:54:78:62 | call to taint | call to taint |
| params_flow.rb:84:10:84:10 | t | params_flow.rb:94:10:94:18 | call to taint | params_flow.rb:84:10:84:10 | t | $@ | params_flow.rb:94:10:94:18 | call to taint | call to taint |
| params_flow.rb:85:10:85:10 | u | params_flow.rb:94:21:94:29 | call to taint | params_flow.rb:85:10:85:10 | u | $@ | params_flow.rb:94:21:94:29 | call to taint | call to taint |
| params_flow.rb:87:10:87:10 | w | params_flow.rb:94:39:94:47 | call to taint | params_flow.rb:87:10:87:10 | w | $@ | params_flow.rb:94:39:94:47 | call to taint | call to taint |

View File

@@ -7,8 +7,8 @@ def sink x
end
def positional(p1, p2)
sink p1 # $ hasValueFlow=1 $ hasValueFlow=16 $ MISSING: hasValueFlow=18
sink p2 # $ hasValueFlow=2 $ MISSING: hasValueFlow=17 $ MISSING: hasValueFlow=19
sink p1 # $ hasValueFlow=1 $ hasValueFlow=16 $ hasValueFlow=18
sink p2 # $ hasValueFlow=2 $ hasValueFlow=19 $ MISSING: hasValueFlow=17
end
positional(taint(1), taint(2))
@@ -47,8 +47,9 @@ args = [taint(18), taint(19)]
positional(*args)
def posargs(p1, *posargs)
sink p1 # $ hasValueFlow=20 $ hasValueFlow=23 $ MISSING: hasValueFlow=24
sink (posargs[0]) # $ MISSING: hasValueFlow=21 $ MISSING: hasValueFlow=22 $ MISSING: hasValueFlow=25
sink p1 # $ hasValueFlow=20 $ hasValueFlow=23 $ hasValueFlow=24
sink (posargs[0]) # $ hasValueFlow=22 $ MISSING: hasValueFlow=21 $ MISSING: hasValueFlow=25
sink (posargs[1])
end
posargs(taint(20), taint(21))
@@ -63,4 +64,31 @@ args = taint(26)
def splatstuff(*x)
sink x[0] # $ hasValueFlow=26
end
splatstuff(*args)
splatstuff(*args)
def splatmid(x, y, *z, w, r)
sink x # $ hasValueFlow=27 $ hasValueFlow=32
sink y # $ hasValueFlow=28 $ MISSING: hasValueFlow=33
sink z[0] # $ MISSING: hasValueFlow=29 $ MISSING: hasValueFlow=34
sink z[1] # $ MISSING: hasValueFlow=35
sink w # $ hasValueFlow=30 $ MISSING: hasValueFlow=36
sink r # $ hasValueFlow=31 $ MISSING: hasValueFlow=37
end
splatmid(taint(27), taint(28), taint(29), taint(30), taint(31))
args = [taint(33), taint(34), taint(35), taint(36)]
splatmid(taint(32), *args, taint(37))
def pos_many(t, u, v, w, x, y, z)
sink t # $ hasValueFlow=38
sink u # $ hasValueFlow=39
sink v # $ MISSING: hasValueFlow=40
sink w # $ MISSING: hasValueFlow=41 $ SPURIOUS: hasValueFlow=44
sink x # $ MISSING: hasValueFlow=42
sink y # $ MISSING: hasValueFlow=43
sink z # $ MISSING: hasValueFlow=44
end
args = [taint(40), taint(41), taint(42), taint(43)]
pos_many(taint(38), taint(39), *args, taint(44))

View File

@@ -7,6 +7,7 @@ track
| type_tracker.rb:2:5:5:7 | field= | type tracker without call steps | type_tracker.rb:2:5:5:7 | field= |
| type_tracker.rb:2:5:5:7 | self in field= | type tracker with call steps | type_tracker.rb:7:5:9:7 | self in field |
| type_tracker.rb:2:5:5:7 | self in field= | type tracker without call steps | type_tracker.rb:2:5:5:7 | self in field= |
| type_tracker.rb:2:5:5:7 | synthetic *args | type tracker without call steps | type_tracker.rb:2:5:5:7 | synthetic *args |
| type_tracker.rb:2:16:2:18 | val | type tracker without call steps | type_tracker.rb:2:16:2:18 | val |
| type_tracker.rb:2:16:2:18 | val | type tracker without call steps | type_tracker.rb:2:16:2:18 | val |
| type_tracker.rb:2:16:2:18 | val | type tracker without call steps | type_tracker.rb:3:14:3:23 | call to field |
@@ -46,6 +47,7 @@ track
| type_tracker.rb:18:1:21:3 | &block | type tracker without call steps | type_tracker.rb:18:1:21:3 | &block |
| type_tracker.rb:18:1:21:3 | positional | type tracker without call steps | type_tracker.rb:18:1:21:3 | positional |
| type_tracker.rb:18:1:21:3 | self in positional | type tracker without call steps | type_tracker.rb:18:1:21:3 | self in positional |
| type_tracker.rb:18:1:21:3 | synthetic *args | type tracker without call steps | type_tracker.rb:18:1:21:3 | synthetic *args |
| type_tracker.rb:18:16:18:17 | p1 | type tracker without call steps | type_tracker.rb:18:16:18:17 | p1 |
| type_tracker.rb:18:16:18:17 | p1 | type tracker without call steps | type_tracker.rb:18:16:18:17 | p1 |
| type_tracker.rb:18:20:18:21 | p2 | type tracker without call steps | type_tracker.rb:18:20:18:21 | p2 |
@@ -118,6 +120,7 @@ track
| type_tracker.rb:32:26:32:26 | 8 | type tracker without call steps with content element :p1 | type_tracker.rb:32:1:32:27 | ** |
| type_tracker.rb:34:1:53:3 | &block | type tracker without call steps | type_tracker.rb:34:1:53:3 | &block |
| type_tracker.rb:34:1:53:3 | self in throughArray | type tracker without call steps | type_tracker.rb:34:1:53:3 | self in throughArray |
| type_tracker.rb:34:1:53:3 | synthetic *args | type tracker without call steps | type_tracker.rb:34:1:53:3 | synthetic *args |
| type_tracker.rb:34:1:53:3 | throughArray | type tracker without call steps | type_tracker.rb:34:1:53:3 | throughArray |
| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps | type_tracker.rb:34:18:34:20 | obj |
| type_tracker.rb:34:18:34:20 | obj | type tracker without call steps | type_tracker.rb:34:18:34:20 | obj |
@@ -272,6 +275,7 @@ trackEnd
| type_tracker.rb:2:5:5:7 | self in field= | type_tracker.rb:7:5:9:7 | self (field) |
| type_tracker.rb:2:5:5:7 | self in field= | type_tracker.rb:7:5:9:7 | self in field |
| type_tracker.rb:2:5:5:7 | self in field= | type_tracker.rb:8:9:8:14 | self |
| type_tracker.rb:2:5:5:7 | synthetic *args | type_tracker.rb:2:5:5:7 | synthetic *args |
| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:2:16:2:18 | val |
| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:2:16:2:18 | val |
| type_tracker.rb:2:16:2:18 | val | type_tracker.rb:2:16:2:18 | val |
@@ -340,6 +344,7 @@ trackEnd
| type_tracker.rb:18:1:21:3 | self in positional | type_tracker.rb:18:1:21:3 | self in positional |
| type_tracker.rb:18:1:21:3 | self in positional | type_tracker.rb:19:5:19:11 | self |
| type_tracker.rb:18:1:21:3 | self in positional | type_tracker.rb:20:5:20:11 | self |
| type_tracker.rb:18:1:21:3 | synthetic *args | type_tracker.rb:18:1:21:3 | synthetic *args |
| type_tracker.rb:18:16:18:17 | p1 | type_tracker.rb:18:16:18:17 | p1 |
| type_tracker.rb:18:16:18:17 | p1 | type_tracker.rb:18:16:18:17 | p1 |
| type_tracker.rb:18:16:18:17 | p1 | type_tracker.rb:18:16:18:17 | p1 |
@@ -427,6 +432,7 @@ trackEnd
| type_tracker.rb:32:26:32:26 | 8 | type_tracker.rb:32:26:32:26 | 8 |
| type_tracker.rb:34:1:53:3 | &block | type_tracker.rb:34:1:53:3 | &block |
| type_tracker.rb:34:1:53:3 | self in throughArray | type_tracker.rb:34:1:53:3 | self in throughArray |
| type_tracker.rb:34:1:53:3 | synthetic *args | type_tracker.rb:34:1:53:3 | synthetic *args |
| type_tracker.rb:34:1:53:3 | throughArray | type_tracker.rb:34:1:53:3 | throughArray |
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:34:18:34:20 | obj |
| type_tracker.rb:34:18:34:20 | obj | type_tracker.rb:34:18:34:20 | obj |