Merge pull request #123 from microsoft/flow-through-ValueFromPipelineByPropertyName

PS: Flow through `ValueFromPipelineByPropertyName` parameters
This commit is contained in:
Mathias Vorreiter Pedersen
2024-10-15 16:11:42 +01:00
committed by GitHub
8 changed files with 80 additions and 21 deletions

View File

@@ -51,10 +51,10 @@ abstract private class AbstractFunction extends Ast {
result.getIndex() = i
}
final Parameter getParameterExcludingPipline(int i) {
final Parameter getParameterExcludingPiplines(int i) {
result = this.getFunctionParameter(i)
or
result = this.getBody().getParamBlock().getParameterExcludingPipline(i)
result = this.getBody().getParamBlock().getParameterExcludingPiplines(i)
}
final Parameter getThisParameter() {

View File

@@ -13,3 +13,7 @@ class NamedAttributeArgument extends @named_attribute_argument, Ast {
class ValueFromPipelineAttribute extends NamedAttributeArgument {
ValueFromPipelineAttribute() { this.getName() = "ValueFromPipeline" }
}
class ValueFromPipelineByPropertyName extends NamedAttributeArgument {
ValueFromPipelineByPropertyName() { this.getName() = "ValueFromPipelineByPropertyName" }
}

View File

@@ -15,7 +15,7 @@ class ParamBlock extends @param_block, Ast {
Parameter getParameter(int i) { result.hasParameterBlock(this, i) }
Parameter getParameterExcludingPipline(int i) { result.hasParameterBlockExcludingPipeline(this, i) }
Parameter getParameterExcludingPiplines(int i) { result.hasParameterBlockExcludingPipelines(this, i) }
Parameter getAParameter() { result = this.getParameter(_) }
}

View File

@@ -10,14 +10,16 @@ private predicate hasParameterBlockImpl(Internal::Parameter p, ParamBlock block,
param_block_parameter(block, i, p)
}
private predicate hasParameterBlockExcludingPipelineImpl(
private predicate hasParameterBlockExcludingPipelinesImpl(
Internal::Parameter p, ParamBlock block, int i
) {
p =
rank[i + 1](Internal::Parameter cand, int j |
hasParameterBlockImpl(cand, block, j) and
not cand.getAnAttribute().(Attribute).getANamedArgument() instanceof
ValueFromPipelineAttribute
ValueFromPipelineAttribute and
not cand.getAnAttribute().(Attribute).getANamedArgument() instanceof
ValueFromPipelineByPropertyName
|
cand order by j
)
@@ -69,7 +71,7 @@ private class ParameterImpl extends TParameterImpl {
predicate hasParameterBlock(ParamBlock block, int i) { none() }
predicate hasParameterBlockExcludingPipeline(ParamBlock block, int i) { none() }
predicate hasParameterBlockExcludingPipelines(ParamBlock block, int i) { none() }
predicate isFunctionParameter(Function f, int i) { none() }
@@ -84,6 +86,8 @@ private class ParameterImpl extends TParameterImpl {
}
abstract predicate isPipeline();
abstract predicate isPipelineByPropertyName();
}
private class InternalParameter extends ParameterImpl, TInternalParameter {
@@ -101,8 +105,8 @@ private class InternalParameter extends ParameterImpl, TInternalParameter {
hasParameterBlockImpl(p, block, i)
}
override predicate hasParameterBlockExcludingPipeline(ParamBlock block, int i) {
hasParameterBlockExcludingPipelineImpl(p, block, i)
override predicate hasParameterBlockExcludingPipelines(ParamBlock block, int i) {
hasParameterBlockExcludingPipelinesImpl(p, block, i)
}
override predicate isFunctionParameter(Function f, int i) { isFunctionParameterImpl(p, f, i) }
@@ -114,6 +118,10 @@ private class InternalParameter extends ParameterImpl, TInternalParameter {
override predicate isPipeline() {
this.getAnAttribute().getANamedArgument() instanceof ValueFromPipelineAttribute
}
override predicate isPipelineByPropertyName() {
this.getAnAttribute().getANamedArgument() instanceof ValueFromPipelineByPropertyName
}
}
/**
@@ -147,6 +155,8 @@ private class Underscore extends ParameterImpl, TUnderscore {
final override predicate isPipeline() { any() }
final override predicate isPipelineByPropertyName() { none() }
final override predicate isFunctionParameter(Function f, int i) { f.getBody() = scope and i = -1 }
}
@@ -164,6 +174,8 @@ private class ThisParameter extends ParameterImpl, TThisParameter {
final override Attribute getAnAttribute() { none() }
final override predicate isPipeline() { none() }
final override predicate isPipelineByPropertyName() { none() }
}
private newtype TVariable =
@@ -241,8 +253,8 @@ class Parameter extends AbstractLocalScopeVariable, TParameter {
predicate hasParameterBlock(ParamBlock block, int i) { p.hasParameterBlock(block, i) }
predicate hasParameterBlockExcludingPipeline(ParamBlock block, int i) {
p.hasParameterBlockExcludingPipeline(block, i)
predicate hasParameterBlockExcludingPipelines(ParamBlock block, int i) {
p.hasParameterBlockExcludingPipelines(block, i)
}
predicate isFunctionParameter(Function f, int i) { p.isFunctionParameter(f, i) }
@@ -261,14 +273,14 @@ class Parameter extends AbstractLocalScopeVariable, TParameter {
*/
int getIndex() { result = this.getFunctionIndex() or result = this.getBlockIndex() }
int getIndexExcludingPipeline() {
result = this.getFunctionIndex() or result = this.getBlockIndexExcludingPipeline()
int getIndexExcludingPipelines() {
result = this.getFunctionIndex() or result = this.getBlockIndexExcludingPipelines()
}
/** Gets the index of this parameter in the parameter block, if any. */
int getBlockIndex() { this.hasParameterBlock(_, result) }
int getBlockIndexExcludingPipeline() { this.hasParameterBlockExcludingPipeline(_, result) }
int getBlockIndexExcludingPipelines() { this.hasParameterBlockExcludingPipelines(_, result) }
/** Gets the index of this parameter in the function, if any. */
int getFunctionIndex() { this.isFunctionParameter(_, result) }
@@ -278,6 +290,8 @@ class Parameter extends AbstractLocalScopeVariable, TParameter {
Attribute getAnAttribute() { result = p.getAnAttribute() }
predicate isPipeline() { p.isPipeline() }
predicate isPipelineByPropertyName() { p.isPipelineByPropertyName() }
}
class PipelineParameter extends Parameter {

View File

@@ -84,7 +84,9 @@ module SsaFlow {
}
predicate localFlowStep(SsaImpl::DefinitionExt def, Node nodeFrom, Node nodeTo, boolean isUseStep) {
Impl::localFlowStep(def, asNode(nodeFrom), asNode(nodeTo), isUseStep)
Impl::localFlowStep(def, asNode(nodeFrom), asNode(nodeTo), isUseStep) and
// Flow out of property name parameter nodes are covered by `readStep`.
not nodeFrom instanceof PipelineByPropertyNameParameter
}
predicate localMustFlowStep(SsaImpl::DefinitionExt def, Node nodeFrom, Node nodeTo) {
@@ -471,7 +473,7 @@ private module ParameterNodes {
// keywords in S are specified.
exists(int i, int j, string name, NamedSet ns, Function f |
pos.isPositional(j, ns) and
parameter.getIndexExcludingPipeline() = i and
parameter.getIndexExcludingPipelines() = i and
f = parameter.getFunction() and
f = ns.getAFunction() and
name = parameter.getName() and
@@ -480,12 +482,12 @@ private module ParameterNodes {
i -
count(int k, Parameter p |
k < i and
p = f.getParameterExcludingPipline(k) and
p = f.getParameterExcludingPiplines(k) and
p.getName() = ns.getAName()
)
)
or
parameter.isPipeline() and
(parameter.isPipeline() or parameter.isPipelineByPropertyName()) and
pos.isPipeline()
)
}
@@ -498,6 +500,12 @@ private module ParameterNodes {
override string toStringImpl() { result = parameter.toString() }
}
class PipelineByPropertyNameParameter extends NormalParameterNode {
PipelineByPropertyNameParameter() { this.getParameter().isPipelineByPropertyName() }
string getPropretyName() { result = this.getParameter().getName() }
}
}
import ParameterNodes
@@ -741,7 +749,7 @@ predicate readStep(Node node1, ContentSet c, Node node2) {
exists(CfgNode cfgNode |
node1 = TPreReturnNodeImpl(cfgNode, true) and
node2 = TImplicitWrapNode(cfgNode, true) and
c.isSingleton(any(Content::KnownElementContent ec))
c.isSingleton(any(Content::KnownElementContent ec | exists(ec.getIndex().asInt())))
)
or
c.isAnyElement() and
@@ -749,6 +757,13 @@ predicate readStep(Node node1, ContentSet c, Node node2) {
node1.(ProcessNode).getIteratorVariable() = def.getSourceVariable() and
SsaImpl::firstRead(def, node2.asExpr())
)
or
exists(Content::KnownElementContent ec, SsaImpl::DefinitionExt def |
c.isSingleton(ec) and
node1.(PipelineByPropertyNameParameter).getPropretyName() = ec.getIndex().asString() and
def.getSourceVariable() = node1.(PipelineByPropertyNameParameter).getParameter() and
SsaImpl::firstRead(def, node2.asExpr())
)
}
/**
@@ -770,13 +785,18 @@ predicate clearsContent(Node n, ContentSet c) {
*/
predicate expectsContent(Node n, ContentSet c) {
n = TPreReturnNodeImpl(_, true) and
c.isKnownOrUnknownElement(_)
c.isKnownOrUnknownElement(any(Content::KnownElementContent ec | exists(ec.getIndex().asInt())))
or
n = TImplicitWrapNode(_, false) and
c.isSingleton(any(Content::UnknownElementContent ec))
or
n instanceof ProcessNode and
c.isAnyElement()
or
exists(Content::KnownElementContent ec |
ec.getIndex().asString() = n.(PipelineByPropertyNameParameter).getPropretyName() and
c.isSingleton(ec)
)
}
class DataFlowType extends TDataFlowType {

View File

@@ -340,7 +340,7 @@ import Cached
* Only intended for internal use.
*/
class DefinitionExt extends Impl::DefinitionExt {
VarReadAccessCfgNode getARead() { result = getARead(this) }
AstCfgNode getARead() { result = getARead(this) }
override string toString() { result = this.(Ssa::Definition).toString() }

View File

@@ -30,6 +30,11 @@ edges
| test.ps1:31:1:31:7 | ...,... [element 1] | test.ps1:25:14:25:16 | _ [element 1] | provenance | |
| test.ps1:31:1:31:7 | ...,... [element 1] | test.ps1:31:1:31:7 | ...,... [element 1] | provenance | |
| test.ps1:31:5:31:7 | y | test.ps1:31:1:31:7 | ...,... [element 1] | provenance | |
| test.ps1:34:11:34:58 | x [element x] | test.ps1:36:10:36:12 | x | provenance | |
| test.ps1:39:6:39:17 | Source | test.ps1:40:23:40:25 | x | provenance | |
| test.ps1:40:1:40:26 | [...]... [element x] | test.ps1:34:11:34:58 | x [element x] | provenance | |
| test.ps1:40:17:40:26 | ${...} [element x] | test.ps1:40:1:40:26 | [...]... [element x] | provenance | |
| test.ps1:40:23:40:25 | x | test.ps1:40:17:40:26 | ${...} [element x] | provenance | |
nodes
| test.ps1:2:10:2:21 | Source | semmle.label | Source |
| test.ps1:3:10:3:21 | Source | semmle.label | Source |
@@ -63,6 +68,12 @@ nodes
| test.ps1:31:1:31:7 | ...,... [element 1] | semmle.label | ...,... [element 1] |
| test.ps1:31:1:31:7 | ...,... [element 1] | semmle.label | ...,... [element 1] |
| test.ps1:31:5:31:7 | y | semmle.label | y |
| test.ps1:34:11:34:58 | x [element x] | semmle.label | x [element x] |
| test.ps1:36:10:36:12 | x | semmle.label | x |
| test.ps1:39:6:39:17 | Source | semmle.label | Source |
| test.ps1:40:1:40:26 | [...]... [element x] | semmle.label | [...]... [element x] |
| test.ps1:40:17:40:26 | ${...} [element x] | semmle.label | ${...} [element x] |
| test.ps1:40:23:40:25 | x | semmle.label | x |
subpaths
testFailures
#select
@@ -73,3 +84,4 @@ testFailures
| test.ps1:13:14:13:16 | x | test.ps1:20:6:20:17 | Source | test.ps1:13:14:13:16 | x | $@ | test.ps1:20:6:20:17 | Source | Source |
| test.ps1:25:14:25:16 | _ | test.ps1:29:6:29:17 | Source | test.ps1:25:14:25:16 | _ | $@ | test.ps1:29:6:29:17 | Source | Source |
| test.ps1:25:14:25:16 | _ | test.ps1:30:6:30:17 | Source | test.ps1:25:14:25:16 | _ | $@ | test.ps1:30:6:30:17 | Source | Source |
| test.ps1:36:10:36:12 | x | test.ps1:39:6:39:17 | Source | test.ps1:36:10:36:12 | x | $@ | test.ps1:39:6:39:17 | Source | Source |

View File

@@ -28,4 +28,13 @@ function consume2 {
$x = Source "21"
$y = Source "22"
$x, $y | consume2
$x, $y | consume2
function consumeValueFromPipelineByPropertyName {
Param([Parameter(ValueFromPipelineByPropertyName)] $x)
Sink $x # $ hasValueFlow=23
}
$x = Source "23"
[pscustomobject]@{x = $x} | consumeValueFromPipelineByPropertyName