diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/If.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/If.qll
index 94192397060c..4aa44a2359d0 100644
--- a/powershell/ql/lib/semmle/code/powershell/ast/internal/If.qll
+++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/If.qll
@@ -53,5 +53,13 @@ class If extends Expr, TIf {
)
}
+ StmtBlock getABranch(boolean b) {
+ b = true and result = this.getAThen()
+ or
+ b = false and result = this.getElse()
+ }
+
+ StmtBlock getABranch() { result = this.getAThen() or result = this.getElse() }
+
predicate hasElse() { exists(this.getElse()) }
}
diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/ScriptBlock.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/ScriptBlock.qll
index ad71dd424263..343cd8927f1d 100644
--- a/powershell/ql/lib/semmle/code/powershell/ast/internal/ScriptBlock.qll
+++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/ScriptBlock.qll
@@ -79,6 +79,9 @@ class ScriptBlock extends Ast, TScriptBlock {
result = this.getParameter(index)
)
or
+ i = ThisVar() and
+ result = this.getThisParameter()
+ or
exists(int index |
i = scriptBlockUsing(index) and
result = this.getUsingStmt(index)
@@ -90,13 +93,14 @@ class ScriptBlock extends Ast, TScriptBlock {
or
any(Synthesis s).pipelineParameterHasIndex(this, i) and
synthChild(getRawAst(this), PipelineParamVar(), result)
- or
- i = -1 and
- synthChild(getRawAst(this), ThisVar(), result)
}
+ Parameter getThisParameter() { synthChild(getRawAst(this), ThisVar(), result) }
+
/**
* Gets a parameter of this block.
+ *
+ * Note: This does not include the `this` parameter, but it does include pipeline parameters.
*/
Parameter getAParameter() { result = this.getParameter(_) }
diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Synthesis.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Synthesis.qll
index 8aa76fd11a49..d58b2eb11b04 100644
--- a/powershell/ql/lib/semmle/code/powershell/ast/internal/Synthesis.qll
+++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Synthesis.qll
@@ -84,6 +84,8 @@ class Synthesis extends TSynthesis {
predicate functionName(FunctionBase f, string name) { none() }
+ predicate getAnAccess(VarAccessSynth va, Variable v) { none() }
+
predicate memberName(Member m, string name) { none() }
predicate typeName(Type t, string name) { none() }
@@ -116,13 +118,26 @@ Raw::Ast getRawAst(Ast r) { r = getResultAst(result) }
private module ThisSynthesis {
private class ThisSynthesis extends Synthesis {
+ private predicate thisAccess(Raw::Ast parent, ChildIndex i, Child child, Raw::Scope scope) {
+ scope = parent.getScope() and
+ parent.getChild(toRawChildIndex(i)).(Raw::VarAccess).getUserPath().toLowerCase() = "this" and
+ child = SynthChild(VarAccessSynthKind(TVariableSynth(scope, ThisVar())))
+ }
+
override predicate child(Raw::Ast parent, ChildIndex i, Child child) {
parent instanceof Raw::MethodScriptBlock and
i = ThisVar() and
child = SynthChild(VarSynthKind(ThisVarKind()))
or
- parent.getChild(toRawChildIndex(i)).(Raw::VarAccess).getUserPath().toLowerCase() = "this" and
- child = SynthChild(VarAccessSynthKind(TVariableSynth(parent.getScope(), ThisVar())))
+ this.thisAccess(parent, i, child, _)
+ }
+
+ final override predicate getAnAccess(VarAccessSynth va, Variable v) {
+ exists(Raw::Ast parent, Raw::Scope scope, ChildIndex i |
+ this.thisAccess(parent, i, _, scope) and
+ v = TVariableSynth(scope, ThisVar()) and
+ va = TVarAccessSynth(parent, i)
+ )
}
override predicate variableSynthName(VariableSynth v, string name) {
@@ -731,18 +746,26 @@ private module IteratorAccessSynth {
)
}
+ final override predicate getAnAccess(VarAccessSynth va, Variable v) {
+ exists(Raw::Ast parent, ChildIndex i, Raw::VarAccess r |
+ this.expr(parent, i, r, _) and
+ va = TVarAccessSynth(parent, i) and
+ v = this.varAccess(r)
+ )
+ }
+
override predicate exprStmtExpr(ExprStmt e, Expr expr) {
exists(Raw::Ast p, Raw::VarAccess va, Raw::CmdExpr cmdExpr, ChildIndex i1, ChildIndex i2 |
this.stmt(p, i1, _, _) and
this.expr(cmdExpr, i2, va, _) and
e = TExprStmtSynth(p, i1) and
- expr = TVarAccessSynth(cmdExpr, i2, this.varAccess(va))
+ expr = TVarAccessSynth(cmdExpr, i2)
)
}
final override Expr getResultAstImpl(Raw::Ast r) {
exists(Raw::Ast parent, ChildIndex i | this.expr(parent, i, r, _) |
- result = TVarAccessSynth(parent, i, this.varAccess(r))
+ result = TVarAccessSynth(parent, i)
)
}
diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/TAst.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/TAst.qll
index 6bc4bf7a8bdb..ee7c58d4f656 100644
--- a/powershell/ql/lib/semmle/code/powershell/ast/internal/TAst.qll
+++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/TAst.qll
@@ -61,7 +61,7 @@ private predicate hasScopeAndName(VariableImpl variable, Scope::Range scope, str
scope = variable.getDeclaringScopeImpl()
}
-private predicate access(Raw::VarAccess va, VariableImpl v) {
+predicate access(Raw::VarAccess va, VariableImpl v) {
exists(string name, Scope::Range scope |
pragma[only_bind_into](name) = variableNameInScope(va, scope)
|
@@ -150,11 +150,11 @@ private module Cached {
)
} or
TVariableSynth(Raw::Ast scope, ChildIndex i) { mkSynthChild(VarSynthKind(_), scope, i) } or
- TVarAccessReal(Raw::VarAccess va, Variable v) { access(va, v) } or
- TVarAccessSynth(Raw::Ast parent, ChildIndex i, Variable v) {
- mkSynthChild(VarAccessRealKind(v), parent, i)
+ TVarAccessReal(Raw::VarAccess va) { access(va, _) } or
+ TVarAccessSynth(Raw::Ast parent, ChildIndex i) {
+ mkSynthChild(VarAccessRealKind(_), parent, i)
or
- mkSynthChild(VarAccessSynthKind(v), parent, i)
+ mkSynthChild(VarAccessSynthKind(_), parent, i)
} or
TWhileStmt(Raw::WhileStmt w) or
TTypeNameExpr(Raw::TypeNameExpr t) or
@@ -277,7 +277,7 @@ private module Cached {
n = TTypeConstraint(result) or
n = TUnaryExpr(result) or
n = TUsingStmt(result) or
- n = TVarAccessReal(result, _) or
+ n = TVarAccessReal(result) or
n = TWhileStmt(result) or
n = TFunctionDefinitionStmt(result) or
n = TExpandableSubExpr(result) or
@@ -308,7 +308,7 @@ private module Cached {
result = TFunctionSynth(parent, i) or
result = TBoolLiteral(parent, i) or
result = TNullLiteral(parent, i) or
- result = TVarAccessSynth(parent, i, _) or
+ result = TVarAccessSynth(parent, i) or
result = TEnvVariable(parent, i) or
result = TTypeSynth(parent, i) or
result = TAutomaticVariable(parent, i) or
diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Variable.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Variable.qll
index 27c2ac5063d7..c843a4ac52a7 100644
--- a/powershell/ql/lib/semmle/code/powershell/ast/internal/Variable.qll
+++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Variable.qll
@@ -95,25 +95,23 @@ module Private {
class VarAccessReal extends VarAccessImpl, TVarAccessReal {
Raw::VarAccess va;
- Variable v;
- VarAccessReal() { this = TVarAccessReal(va, v) }
+ VarAccessReal() { this = TVarAccessReal(va) }
- final override Variable getVariableImpl() { result = v }
+ final override Variable getVariableImpl() { access(va, result) }
- final override string toString() { result = v.getName() }
+ final override string toString() { result = va.getUserPath() }
}
class VarAccessSynth extends VarAccessImpl, TVarAccessSynth {
Raw::Ast parent;
ChildIndex i;
- Variable v;
- VarAccessSynth() { this = TVarAccessSynth(parent, i, v) }
+ VarAccessSynth() { this = TVarAccessSynth(parent, i) }
- final override Variable getVariableImpl() { result = v }
+ final override Variable getVariableImpl() { any(Synthesis s).getAnAccess(this, result) }
- final override string toString() { result = v.getName() }
+ final override string toString() { result = this.getVariableImpl().getName() }
final override Location getLocation() { result = parent.getLocation() }
}
diff --git a/powershell/ql/lib/semmle/code/powershell/controlflow/CfgNodes.qll b/powershell/ql/lib/semmle/code/powershell/controlflow/CfgNodes.qll
index 809ef64f8724..ef07239ab51e 100644
--- a/powershell/ql/lib/semmle/code/powershell/controlflow/CfgNodes.qll
+++ b/powershell/ql/lib/semmle/code/powershell/controlflow/CfgNodes.qll
@@ -284,6 +284,26 @@ class ProcessBlockCfgNode extends NamedBlockCfgNode {
ScriptBlockCfgNode getScriptBlock() { result.getProcessBlock() = this }
}
+private class CatchClauseChildMapping extends NonExprChildMapping, CatchClause {
+ override predicate relevantChild(Ast child) {
+ child = this.getBody() or child = this.getACatchType()
+ }
+}
+
+class CatchClauseCfgNode extends AstCfgNode {
+ override string getAPrimaryQlClass() { result = "CatchClauseCfgNode" }
+
+ CatchClauseChildMapping s;
+
+ CatchClause getCatchClause() { result = s }
+
+ StmtCfgNode getBody() { s.hasCfgChild(s.getBody(), this, result) }
+
+ TypeConstraint getCatchType(int i) { result = s.getCatchType(i) }
+
+ TypeConstraint getACatchType() { result = this.getCatchType(_) }
+}
+
module ExprNodes {
private class ArrayExprChildMapping extends ExprChildMapping, ArrayExpr {
override predicate relevantChild(Ast child) {
@@ -371,7 +391,7 @@ module ExprNodes {
ExprCfgNode getOperand() { e.hasCfgChild(e.getOperand(), this, result) }
}
- class ConstExprChildMapping extends ExprChildMapping, ConstExpr {
+ private class ConstExprChildMapping extends ExprChildMapping, ConstExpr {
override predicate relevantChild(Ast child) { none() }
}
@@ -383,7 +403,7 @@ module ExprNodes {
override ConstExpr getExpr() { result = e }
}
- class ConvertExprChildMapping extends ExprChildMapping, ConvertExpr {
+ private class ConvertExprChildMapping extends ExprChildMapping, ConvertExpr {
override predicate relevantChild(Ast child) { child = this.getExpr() }
}
@@ -397,7 +417,7 @@ module ExprNodes {
ExprCfgNode getSubExpr() { e.hasCfgChild(e.getExpr(), this, result) }
}
- class IndexExprChildMapping extends ExprChildMapping, IndexExpr {
+ private class IndexExprChildMapping extends ExprChildMapping, IndexExpr {
override predicate relevantChild(Ast child) {
child = this.getBase()
or
@@ -457,7 +477,7 @@ module ExprNodes {
override IndexExprReadAccess getExpr() { result = e }
}
- class CallExprChildMapping extends ExprChildMapping, CallExpr {
+ private class CallExprChildMapping extends ExprChildMapping, CallExpr {
override predicate relevantChild(Ast child) {
child = this.getQualifier()
or
@@ -503,7 +523,7 @@ module ExprNodes {
predicate isStatic() { this.getExpr().isStatic() }
}
- class ObjectCreationChildMapping extends CallExprChildMapping instanceof ObjectCreation {
+ private class ObjectCreationChildMapping extends CallExprChildMapping instanceof ObjectCreation {
override predicate relevantChild(Ast child) { child = super.getConstructedTypeExpr() }
}
@@ -522,7 +542,7 @@ module ExprNodes {
}
}
- class CallOperatorChildMapping extends CallExprChildMapping instanceof CallOperator {
+ private class CallOperatorChildMapping extends CallExprChildMapping instanceof CallOperator {
override predicate relevantChild(Ast child) { none() }
}
@@ -536,7 +556,7 @@ module ExprNodes {
ExprCfgNode getCommand() { result = this.getArgument(0) }
}
- class MemberExprChildMapping extends ExprChildMapping, MemberExpr {
+ private class MemberExprChildMapping extends ExprChildMapping, MemberExpr {
override predicate relevantChild(Ast child) {
child = this.getQualifier()
or
@@ -603,7 +623,7 @@ module ExprNodes {
override MemberExprReadAccess getExpr() { result = e }
}
- class TypeNameExprChildMapping extends ExprChildMapping, TypeNameExpr {
+ private class TypeNameExprChildMapping extends ExprChildMapping, TypeNameExpr {
override predicate relevantChild(Ast child) { none() }
}
@@ -631,7 +651,7 @@ module ExprNodes {
override QualifiedTypeNameExpr getExpr() { result = e }
}
- class ErrorExprChildMapping extends ExprChildMapping, ErrorExpr {
+ private class ErrorExprChildMapping extends ExprChildMapping, ErrorExpr {
override predicate relevantChild(Ast child) { none() }
}
@@ -643,7 +663,7 @@ module ExprNodes {
override ErrorExpr getExpr() { result = e }
}
- class ScriptBlockExprChildMapping extends ExprChildMapping, ScriptBlockExpr {
+ private class ScriptBlockExprChildMapping extends ExprChildMapping, ScriptBlockExpr {
override predicate relevantChild(Ast child) { child = this.getBody() }
}
@@ -657,7 +677,7 @@ module ExprNodes {
ScriptBlockCfgNode getBody() { e.hasCfgChild(e.getBody(), this, result) }
}
- class StringLiteralExprChildMapping extends ExprChildMapping, StringConstExpr {
+ private class StringLiteralExprChildMapping extends ExprChildMapping, StringConstExpr {
override predicate relevantChild(Ast child) { none() }
}
@@ -671,7 +691,7 @@ module ExprNodes {
string getValueString() { result = e.getValueString() }
}
- class ExpandableStringExprChildMapping extends ExprChildMapping, ExpandableStringExpr {
+ private class ExpandableStringExprChildMapping extends ExprChildMapping, ExpandableStringExpr {
override predicate relevantChild(Ast child) { child = this.getAnExpr() }
}
@@ -728,7 +748,7 @@ module ExprNodes {
override VarReadAccess getExpr() { result = e }
}
- class HashTableExprChildMapping extends ExprChildMapping, HashTableExpr {
+ private class HashTableExprChildMapping extends ExprChildMapping, HashTableExpr {
override predicate relevantChild(Ast child) {
child = this.getAKey()
or
@@ -747,7 +767,7 @@ module ExprNodes {
ExprCfgNode getAnKey() { result = this.getKey(_) }
- ExprCfgNode getValue(int i) { e.hasCfgChild(e.getKey(i), this, result) }
+ ExprCfgNode getValue(int i) { e.hasCfgChild(e.getValue(i), this, result) }
ExprCfgNode getValueFromKey(ExprCfgNode key) {
exists(int i |
@@ -759,7 +779,7 @@ module ExprNodes {
ExprCfgNode getAValue() { result = this.getValue(_) }
}
- class PipelineChildMapping extends ExprChildMapping, Pipeline {
+ private class PipelineChildMapping extends ExprChildMapping, Pipeline {
override predicate relevantChild(Ast child) { child = this.getAComponent() }
}
@@ -775,7 +795,7 @@ module ExprNodes {
ExprCfgNode getAComponent() { result = this.getComponent(_) }
}
- class PipelineChainChildMapping extends ExprChildMapping, PipelineChain {
+ private class PipelineChainChildMapping extends ExprChildMapping, PipelineChain {
override predicate relevantChild(Ast child) {
child = this.getLeft() or child = this.getRight()
}
@@ -793,7 +813,7 @@ module ExprNodes {
ExprCfgNode getRight() { e.hasCfgChild(e.getRight(), this, result) }
}
- class ConditionalExprChildMapping extends ExprChildMapping, ConditionalExpr {
+ private class ConditionalExprChildMapping extends ExprChildMapping, ConditionalExpr {
override predicate relevantChild(Ast child) {
child = this.getCondition()
or
@@ -827,7 +847,7 @@ module ExprNodes {
ExprCfgNode getABranch() { result = this.getBranch(_) }
}
- class ExpandableSubExprChildMapping extends ExprChildMapping, ExpandableSubExpr {
+ private class ExpandableSubExprChildMapping extends ExprChildMapping, ExpandableSubExpr {
override predicate relevantChild(Ast child) { child = this.getExpr() }
}
@@ -841,7 +861,7 @@ module ExprNodes {
ExprCfgNode getSubExpr() { e.hasCfgChild(e.getExpr(), this, result) }
}
- class UsingExprChildMapping extends ExprChildMapping, UsingExpr {
+ private class UsingExprChildMapping extends ExprChildMapping, UsingExpr {
override predicate relevantChild(Ast child) { child = this.getExpr() }
}
@@ -855,7 +875,7 @@ module ExprNodes {
ExprCfgNode getSubExpr() { e.hasCfgChild(e.getExpr(), this, result) }
}
- class AttributedExprChildMapping extends ExprChildMapping, AttributedExpr {
+ private class AttributedExprChildMapping extends ExprChildMapping, AttributedExpr {
override predicate relevantChild(Ast child) {
child = this.getExpr() or
child = this.getAttribute()
@@ -874,7 +894,7 @@ module ExprNodes {
ExprCfgNode getAttribute() { e.hasCfgChild(e.getAttribute(), this, result) }
}
- class IfChildMapping extends ExprChildMapping, If {
+ private class IfChildMapping extends ExprChildMapping, If {
override predicate relevantChild(Ast child) {
child = this.getACondition()
or
@@ -900,9 +920,19 @@ module ExprNodes {
StmtCfgNode getAThen() { result = this.getThen(_) }
StmtCfgNode getElse() { e.hasCfgChild(e.getElse(), this, result) }
+
+ StmtCfgNode getABranch(boolean b) {
+ b = true and
+ result = this.getAThen()
+ or
+ b = false and
+ result = this.getElse()
+ }
+
+ StmtCfgNode getABranch() { result = this.getABranch(_) }
}
- class LiteralChildMapping extends ExprChildMapping, Literal {
+ private class LiteralChildMapping extends ExprChildMapping, Literal {
override predicate relevantChild(Ast child) { none() }
}
@@ -914,7 +944,7 @@ module ExprNodes {
override Literal getExpr() { result = e }
}
- class BoolLiteralChildMapping extends ExprChildMapping, BoolLiteral {
+ private class BoolLiteralChildMapping extends ExprChildMapping, BoolLiteral {
override predicate relevantChild(Ast child) { none() }
}
@@ -926,7 +956,7 @@ module ExprNodes {
override BoolLiteral getExpr() { result = e }
}
- class NullLiteralChildMapping extends ExprChildMapping, NullLiteral {
+ private class NullLiteralChildMapping extends ExprChildMapping, NullLiteral {
override predicate relevantChild(Ast child) { none() }
}
@@ -1004,7 +1034,7 @@ module StmtNodes {
ExprCfgNode getRightHandSide() { s.hasCfgChild(s.getRightHandSide(), this, result) }
}
- class BreakStmtChildMapping extends NonExprChildMapping, BreakStmt {
+ private class BreakStmtChildMapping extends NonExprChildMapping, BreakStmt {
override predicate relevantChild(Ast child) { none() }
}
@@ -1016,7 +1046,7 @@ module StmtNodes {
override BreakStmt getStmt() { result = s }
}
- class ContinueStmtChildMapping extends NonExprChildMapping, ContinueStmt {
+ private class ContinueStmtChildMapping extends NonExprChildMapping, ContinueStmt {
override predicate relevantChild(Ast child) { none() }
}
@@ -1028,7 +1058,7 @@ module StmtNodes {
override ContinueStmt getStmt() { result = s }
}
- class DataStmtChildMapping extends NonExprChildMapping, DataStmt {
+ private class DataStmtChildMapping extends NonExprChildMapping, DataStmt {
override predicate relevantChild(Ast child) {
child = this.getACmdAllowed() or child = this.getBody()
}
@@ -1048,13 +1078,27 @@ module StmtNodes {
StmtCfgNode getBody() { s.hasCfgChild(s.getBody(), this, result) }
}
- class DoUntilStmtChildMapping extends NonExprChildMapping, DoUntilStmt {
+ private class LoopStmtChildMapping extends NonExprChildMapping, LoopStmt {
+ override predicate relevantChild(Ast child) { child = this.getBody() }
+ }
+
+ class LoopStmtCfgNode extends StmtCfgNode {
+ override string getAPrimaryQlClass() { result = "LoopStmtCfgNode" }
+
+ override LoopStmtChildMapping s;
+
+ override LoopStmt getStmt() { result = s }
+
+ StmtCfgNode getBody() { s.hasCfgChild(s.getBody(), this, result) }
+ }
+
+ private class DoUntilStmtChildMapping extends LoopStmtChildMapping, DoUntilStmt {
override predicate relevantChild(Ast child) {
- child = this.getCondition() or child = this.getBody()
+ child = this.getCondition() or super.relevantChild(child)
}
}
- class DoUntilStmtCfgNode extends StmtCfgNode {
+ class DoUntilStmtCfgNode extends LoopStmtCfgNode {
override string getAPrimaryQlClass() { result = "DoUntilStmtCfgNode" }
override DoUntilStmtChildMapping s;
@@ -1062,17 +1106,15 @@ module StmtNodes {
override DoUntilStmt getStmt() { result = s }
ExprCfgNode getCondition() { s.hasCfgChild(s.getCondition(), this, result) }
-
- StmtCfgNode getBody() { s.hasCfgChild(s.getBody(), this, result) }
}
- class DoWhileStmtChildMapping extends NonExprChildMapping, DoWhileStmt {
+ private class DoWhileStmtChildMapping extends LoopStmtChildMapping, DoWhileStmt {
override predicate relevantChild(Ast child) {
- child = this.getCondition() or child = this.getBody()
+ child = this.getCondition() or super.relevantChild(child)
}
}
- class DoWhileStmtCfgNode extends StmtCfgNode {
+ class DoWhileStmtCfgNode extends LoopStmtCfgNode {
override string getAPrimaryQlClass() { result = "DoWhileStmtCfgNode" }
override DoWhileStmtChildMapping s;
@@ -1080,11 +1122,9 @@ module StmtNodes {
override DoWhileStmt getStmt() { result = s }
ExprCfgNode getCondition() { s.hasCfgChild(s.getCondition(), this, result) }
-
- StmtCfgNode getBody() { s.hasCfgChild(s.getBody(), this, result) }
}
- class ErrorStmtChildMapping extends NonExprChildMapping, ErrorStmt {
+ private class ErrorStmtChildMapping extends NonExprChildMapping, ErrorStmt {
override predicate relevantChild(Ast child) { none() }
}
@@ -1096,7 +1136,7 @@ module StmtNodes {
override ErrorStmt getStmt() { result = s }
}
- class ExitStmtChildMapping extends NonExprChildMapping, ExitStmt {
+ private class ExitStmtChildMapping extends NonExprChildMapping, ExitStmt {
override predicate relevantChild(Ast child) { child = this.getPipeline() }
}
@@ -1110,7 +1150,7 @@ module StmtNodes {
ExprCfgNode getPipeline() { s.hasCfgChild(s.getPipeline(), this, result) }
}
- class DynamicStmtChildMapping extends NonExprChildMapping, DynamicStmt {
+ private class DynamicStmtChildMapping extends NonExprChildMapping, DynamicStmt {
override predicate relevantChild(Ast child) {
child = this.getName() or child = this.getScriptBlock() or child = this.getHashTableExpr()
}
@@ -1130,13 +1170,13 @@ module StmtNodes {
ExprCfgNode getHashTableExpr() { s.hasCfgChild(s.getHashTableExpr(), this, result) }
}
- class ForEachStmtChildMapping extends NonExprChildMapping, ForEachStmt {
+ private class ForEachStmtChildMapping extends LoopStmtChildMapping, ForEachStmt {
override predicate relevantChild(Ast child) {
- child = this.getVarAccess() or child = this.getIterableExpr() or child = this.getBody()
+ child = this.getVarAccess() or child = this.getIterableExpr() or super.relevantChild(child)
}
}
- class ForEachStmtCfgNode extends StmtCfgNode {
+ class ForEachStmtCfgNode extends LoopStmtCfgNode {
override string getAPrimaryQlClass() { result = "ForEachStmtCfgNode" }
override ForEachStmtChildMapping s;
@@ -1146,20 +1186,18 @@ module StmtNodes {
ExprCfgNode getVarAccess() { s.hasCfgChild(s.getVarAccess(), this, result) }
ExprCfgNode getIterableExpr() { s.hasCfgChild(s.getIterableExpr(), this, result) }
-
- StmtCfgNode getBody() { s.hasCfgChild(s.getBody(), this, result) }
}
- class ForStmtChildMapping extends NonExprChildMapping, ForStmt {
+ private class ForStmtChildMapping extends LoopStmtChildMapping, ForStmt {
override predicate relevantChild(Ast child) {
child = this.getInitializer() or
child = this.getCondition() or
child = this.getIterator() or
- child = this.getBody()
+ super.relevantChild(child)
}
}
- class ForStmtCfgNode extends StmtCfgNode {
+ class ForStmtCfgNode extends LoopStmtCfgNode {
override string getAPrimaryQlClass() { result = "ForStmtCfgNode" }
override ForStmtChildMapping s;
@@ -1171,11 +1209,9 @@ module StmtNodes {
ExprCfgNode getCondition() { s.hasCfgChild(s.getCondition(), this, result) }
AstCfgNode getIterator() { s.hasCfgChild(s.getIterator(), this, result) }
-
- StmtCfgNode getBody() { s.hasCfgChild(s.getBody(), this, result) }
}
- class GotoStmtChildMapping extends NonExprChildMapping, GotoStmt {
+ private class GotoStmtChildMapping extends NonExprChildMapping, GotoStmt {
override predicate relevantChild(Ast child) { child = this.getLabel() }
}
@@ -1189,7 +1225,7 @@ module StmtNodes {
ExprCfgNode getLabel() { s.hasCfgChild(s.getLabel(), this, result) }
}
- class ReturnStmtChildMapping extends NonExprChildMapping, ReturnStmt {
+ private class ReturnStmtChildMapping extends NonExprChildMapping, ReturnStmt {
override predicate relevantChild(Ast child) { child = this.getPipeline() }
}
@@ -1203,7 +1239,7 @@ module StmtNodes {
ExprCfgNode getPipeline() { s.hasCfgChild(s.getPipeline(), this, result) }
}
- class StmtBlockChildMapping extends NonExprChildMapping, StmtBlock {
+ private class StmtBlockChildMapping extends NonExprChildMapping, StmtBlock {
override predicate relevantChild(Ast child) { child = this.getAStmt() }
}
@@ -1219,7 +1255,7 @@ module StmtNodes {
StmtCfgNode getAStmt() { result = this.getStmt(_) }
}
- class SwitchStmtChildMapping extends NonExprChildMapping, SwitchStmt {
+ private class SwitchStmtChildMapping extends NonExprChildMapping, SwitchStmt {
override predicate relevantChild(Ast child) {
child = this.getCondition() or
child = this.getDefault() or
@@ -1248,7 +1284,7 @@ module StmtNodes {
ExprCfgNode getAPattern() { result = this.getPattern(_) }
}
- class ThrowStmtChildMapping extends NonExprChildMapping, ThrowStmt {
+ private class ThrowStmtChildMapping extends NonExprChildMapping, ThrowStmt {
override predicate relevantChild(Ast child) { child = this.getPipeline() }
}
@@ -1262,7 +1298,7 @@ module StmtNodes {
ExprCfgNode getPipeline() { s.hasCfgChild(s.getPipeline(), this, result) }
}
- class TrapStmtChildMapping extends NonExprChildMapping, TrapStmt {
+ private class TrapStmtChildMapping extends NonExprChildMapping, TrapStmt {
override predicate relevantChild(Ast child) { child = this.getBody() }
}
@@ -1276,7 +1312,7 @@ module StmtNodes {
StmtCfgNode getBody() { s.hasCfgChild(s.getBody(), this, result) }
}
- class TryStmtChildMapping extends NonExprChildMapping, TryStmt {
+ private class TryStmtChildMapping extends NonExprChildMapping, TryStmt {
override predicate relevantChild(Ast child) {
child = this.getBody() or
child = this.getFinally() or
@@ -1298,7 +1334,7 @@ module StmtNodes {
StmtCfgNode getCatchClause(int i) { s.hasCfgChild(s.getCatchClause(i), this, result) }
}
- class UsingStmtChildMapping extends NonExprChildMapping, UsingStmt {
+ private class UsingStmtChildMapping extends NonExprChildMapping, UsingStmt {
override predicate relevantChild(Ast child) { none() }
}
@@ -1310,14 +1346,14 @@ module StmtNodes {
override UsingStmt getStmt() { result = s }
}
- class WhileStmtChildMapping extends NonExprChildMapping, WhileStmt {
+ private class WhileStmtChildMapping extends LoopStmtChildMapping, WhileStmt {
override predicate relevantChild(Ast child) {
child = this.getCondition() or
- child = this.getBody()
+ super.relevantChild(child)
}
}
- class WhileStmtCfgNode extends StmtCfgNode {
+ class WhileStmtCfgNode extends LoopStmtCfgNode {
override string getAPrimaryQlClass() { result = "WhileStmtCfgNode" }
override WhileStmtChildMapping s;
@@ -1325,11 +1361,9 @@ module StmtNodes {
override WhileStmt getStmt() { result = s }
ExprCfgNode getCondition() { s.hasCfgChild(s.getCondition(), this, result) }
-
- StmtCfgNode getBody() { s.hasCfgChild(s.getBody(), this, result) }
}
- class ConfigurationChildMapping extends NonExprChildMapping, Configuration {
+ private class ConfigurationChildMapping extends NonExprChildMapping, Configuration {
override predicate relevantChild(Ast child) { child = this.getName() or child = this.getBody() }
}
@@ -1345,7 +1379,7 @@ module StmtNodes {
StmtCfgNode getBody() { s.hasCfgChild(s.getBody(), this, result) }
}
- class TypeStmtChildMapping extends NonExprChildMapping, TypeDefinitionStmt {
+ private class TypeStmtChildMapping extends NonExprChildMapping, TypeDefinitionStmt {
override predicate relevantChild(Ast child) { none() }
}
@@ -1369,7 +1403,7 @@ module StmtNodes {
string getName() { result = s.getName() }
}
- class FunctionDefinitionChildMapping extends NonExprChildMapping, FunctionDefinitionStmt {
+ private class FunctionDefinitionChildMapping extends NonExprChildMapping, FunctionDefinitionStmt {
override predicate relevantChild(Ast child) { none() }
}
@@ -1383,7 +1417,7 @@ module StmtNodes {
FunctionBase getFunction() { result = s.getFunction() }
}
- class ExprStmtChildMapping extends NonExprChildMapping, ExprStmt {
+ private class ExprStmtChildMapping extends NonExprChildMapping, ExprStmt {
override predicate relevantChild(Ast child) { child = this.getExpr() }
}
diff --git a/powershell/ql/lib/semmle/code/powershell/controlflow/internal/ControlFlowGraphImpl.qll b/powershell/ql/lib/semmle/code/powershell/controlflow/internal/ControlFlowGraphImpl.qll
index 25d0773b0c07..f67a748068e4 100644
--- a/powershell/ql/lib/semmle/code/powershell/controlflow/internal/ControlFlowGraphImpl.qll
+++ b/powershell/ql/lib/semmle/code/powershell/controlflow/internal/ControlFlowGraphImpl.qll
@@ -151,6 +151,30 @@ module Trees {
override predicate succ(AstNode pred, AstNode succ, Completion c) {
this.succEntry(pred, c) and
+ (
+ first(super.getThisParameter(), succ)
+ or
+ not exists(super.getThisParameter()) and
+ first(super.getParameter(0), succ)
+ or
+ not exists(super.getThisParameter()) and
+ not exists(super.getAParameter()) and
+ first(super.getBeginBlock(), succ)
+ or
+ not exists(super.getThisParameter()) and
+ not exists(super.getAParameter()) and
+ not exists(super.getBeginBlock()) and
+ first(super.getProcessBlock(), succ)
+ or
+ not exists(super.getThisParameter()) and
+ not exists(super.getAParameter()) and
+ not exists(super.getBeginBlock()) and
+ not exists(super.getProcessBlock()) and
+ first(super.getEndBlock(), succ)
+ )
+ or
+ last(super.getThisParameter(), pred, c) and
+ completionIsNormal(c) and
(
first(super.getParameter(0), succ)
or
diff --git a/powershell/ql/lib/semmle/code/powershell/dataflow/Ssa.qll b/powershell/ql/lib/semmle/code/powershell/dataflow/Ssa.qll
index e023162d437f..212936b3643d 100644
--- a/powershell/ql/lib/semmle/code/powershell/dataflow/Ssa.qll
+++ b/powershell/ql/lib/semmle/code/powershell/dataflow/Ssa.qll
@@ -113,7 +113,7 @@ module Ssa {
override ThisParameter getSourceVariable() { result = v }
- final override string toString() { result = "self (" + v.getDeclaringScope() + ")" }
+ final override string toString() { result = "this (" + v.getDeclaringScope() + ")" }
final override Location getLocation() { result = this.getControlFlowNode().getLocation() }
}
diff --git a/powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowPrivate.qll b/powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowPrivate.qll
index c5aa29ceff98..46380b0a3e1b 100644
--- a/powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowPrivate.qll
+++ b/powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowPrivate.qll
@@ -8,6 +8,7 @@ private import DataFlowDispatch
private import SsaImpl as SsaImpl
private import FlowSummaryImpl as FlowSummaryImpl
private import semmle.code.powershell.frameworks.data.ModelsAsData
+private import PipelineReturns as PipelineReturns
/** Gets the callable in which this node occurs. */
DataFlowCallable nodeGetEnclosingCallable(Node n) { result = n.(NodeImpl).getEnclosingCallable() }
@@ -61,6 +62,8 @@ module SsaFlow {
private ParameterNodeImpl toParameterNode(SsaImpl::ParameterExt p) {
result = TNormalParameterNode(p.asParameter())
+ or
+ result = TThisParameterNode(p.asThis())
}
Impl::Node asNode(Node n) {
@@ -85,6 +88,16 @@ module SsaFlow {
}
}
+private module ArrayExprFlow {
+ private module Input implements PipelineReturns::InputSig {
+ predicate isSource(CfgNodes::AstCfgNode source) {
+ source = any(CfgNodes::ExprNodes::ArrayExprCfgNode ae).getStmtBlock()
+ }
+ }
+
+ import PipelineReturns::Make
+}
+
/** Provides predicates related to local data flow. */
module LocalFlow {
pragma[nomagic]
@@ -97,16 +110,13 @@ module LocalFlow {
or
nodeFrom.asExpr() = nodeTo.asExpr().(CfgNodes::ExprNodes::ParenExprCfgNode).getSubExpr()
or
- exists(
- CfgNodes::ExprNodes::ArrayExprCfgNode arrayExpr, EscapeContainer::EscapeContainer container
- |
- nodeTo.asExpr() = arrayExpr and
- container = arrayExpr.getStmtBlock().getAstNode() and
- nodeFrom.(AstNode).getCfgNode() = container.getAnEscapingElement() and
- not container.mayBeMultiReturned(_)
- )
+ nodeFrom.asExpr() = nodeTo.asExpr().(CfgNodes::ExprNodes::ArrayExprCfgNode)
or
- nodeFrom.(AstNode).getCfgNode() = nodeTo.(PreReturNodeImpl).getReturnedNode()
+ exists(CfgNodes::ExprCfgNode e |
+ e = nodeFrom.(AstNode).getCfgNode() and
+ isReturned(e) and
+ e.getScope() = nodeTo.(PreReturNodeImpl).getCfgScope()
+ )
or
exists(CfgNode cfgNode |
nodeFrom = TPreReturnNodeImpl(cfgNode, true) and
@@ -118,10 +128,12 @@ module LocalFlow {
nodeTo = TReturnNodeImpl(cfgNode.getScope())
)
or
- exists(CfgNode cfgNode |
- cfgNode = nodeFrom.(AstNode).getCfgNode() and
- isUniqueReturned(cfgNode) and
- nodeTo.(ReturnNodeImpl).getCfgScope() = cfgNode.getScope()
+ exists(CfgNodes::ExprCfgNode e, CfgNodes::ScriptBlockCfgNode scriptBlock |
+ e = nodeFrom.(AstNode).getCfgNode() and
+ isReturned(e) and
+ e.getScope() = scriptBlock.getAstNode() and
+ not blockMayReturnMultipleValues(scriptBlock) and
+ nodeTo.(ReturnNodeImpl).getCfgScope() = scriptBlock.getAstNode()
)
}
@@ -164,7 +176,6 @@ private module Cached {
cached
newtype TNode =
TExprNode(CfgNodes::ExprCfgNode n) or
- TStmtNode(CfgNodes::StmtCfgNode n) or
TSsaNode(SsaImpl::DataFlowIntegration::SsaNode node) or
TNormalParameterNode(SsaImpl::NormalParameter p) or
TThisParameterNode(Method m) or
@@ -183,8 +194,12 @@ private module Cached {
n = any(CfgNodes::ExprNodes::IndexExprCfgNode index).getBase()
} or
TFlowSummaryNode(FlowSummaryImpl::Private::SummaryNode sn) or
- TPreReturnNodeImpl(CfgNodes::AstCfgNode n, Boolean isArray) { isMultiReturned(n) } or
- TImplicitWrapNode(CfgNodes::AstCfgNode n, Boolean shouldWrap) { isMultiReturned(n) } or
+ TPreReturnNodeImpl(CfgNodes::ScriptBlockCfgNode scriptBlock, Boolean isArray) {
+ blockMayReturnMultipleValues(scriptBlock)
+ } or
+ TImplicitWrapNode(CfgNodes::ScriptBlockCfgNode scriptBlock, Boolean shouldWrap) {
+ blockMayReturnMultipleValues(scriptBlock)
+ } or
TReturnNodeImpl(CfgScope scope) or
TProcessNode(ProcessBlock process) or
TProcessPropertyByNameNode(PipelineByPropertyNameIteratorVariable iter) {
@@ -549,7 +564,7 @@ private module ParameterNodes {
ThisParameterNode() { this = TThisParameterNode(m) }
- override Parameter getParameter() { none() }
+ override Parameter getParameter() { result = m.getThisParameter() }
override predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
m.getBody() = c.asCfgScope() and
@@ -751,64 +766,41 @@ abstract class ReturnNode extends Node {
abstract ReturnKind getKind();
}
-private module EscapeContainer {
- private import semmle.code.powershell.internal.AstEscape::Private
-
- private module ReturnContainerInterpreter implements InterpretAstInputSig {
- class T = CfgNodes::AstCfgNode;
-
- T interpret(Ast a) { result.(CfgNodes::ExprCfgNode).getExpr() = a } // TODO: Recutse into expr-to-stmt conversions
- }
-
- class EscapeContainer extends AstEscape::Element {
- /** Holds if `n` may be returned multiples times. */
- predicate mayBeMultiReturned(CfgNode n) {
- n = this.getANode() and
- n.getASuccessor+() = n
- or
- this.getAChild().(EscapeContainer).mayBeMultiReturned(n)
- }
- }
-
- private class SummaryReturnNode extends FlowSummaryNode, ReturnNode {
- private ReturnKind rk;
+private class SummaryReturnNode extends FlowSummaryNode, ReturnNode {
+ private ReturnKind rk;
- SummaryReturnNode() { FlowSummaryImpl::Private::summaryReturnNode(this.getSummaryNode(), rk) }
+ SummaryReturnNode() { FlowSummaryImpl::Private::summaryReturnNode(this.getSummaryNode(), rk) }
- override ReturnKind getKind() { result = rk }
- }
+ override ReturnKind getKind() { result = rk }
}
private module ReturnNodes {
- private import EscapeContainer
+ private CfgNodes::NamedBlockCfgNode getAReturnBlock(CfgNodes::ScriptBlockCfgNode sb) {
+ result = sb.getBeginBlock()
+ or
+ result = sb.getEndBlock()
+ or
+ result = sb.getProcessBlock()
+ }
- private predicate isReturnedImpl(CfgNodes::AstCfgNode n, EscapeContainer container) {
- container = n.getScope() and
- n = container.getAnEscapingElement()
+ private module CfgScopeReturn implements PipelineReturns::InputSig {
+ predicate isSource(CfgNodes::AstCfgNode source) { source = getAReturnBlock(_) }
}
+ private module P = PipelineReturns::Make;
+
/**
* Holds if `n` may be returned, and there are possibly
* more than one return value from the function.
*/
- predicate isMultiReturned(CfgNodes::AstCfgNode n) {
- exists(EscapeContainer container | isReturnedImpl(n, container) |
- strictcount(container.getAnEscapingElement()) > 1
- or
- container.mayBeMultiReturned(n)
- )
+ predicate blockMayReturnMultipleValues(CfgNodes::ScriptBlockCfgNode scriptBlock) {
+ P::mayReturnMultipleValues(getAReturnBlock(scriptBlock))
}
/**
* Holds if `n` may be returned.
*/
- predicate isReturned(CfgNodes::AstCfgNode n) { isReturnedImpl(n, _) }
-
- /**
- * Holds if `n` may be returned, and this is the only value that may be
- * returned from the function.
- */
- predicate isUniqueReturned(CfgNodes::AstCfgNode n) { isReturned(n) and not isMultiReturned(n) }
+ predicate isReturned(CfgNodes::AstCfgNode n) { n = P::getAReturn(_) }
class NormalReturnNode extends ReturnNode instanceof ReturnNodeImpl {
final override NormalReturnKind getKind() { any() }
@@ -851,6 +843,24 @@ predicate jumpStep(Node pred, Node succ) {
succ.(FlowSummaryNode).getSummaryNode())
}
+private predicate arrayExprStore(Node node1, ContentSet cs, Node node2, CfgNodes::ExprCfgNode e) {
+ exists(CfgNodes::ExprNodes::ArrayExprCfgNode ae, CfgNodes::StmtNodes::StmtBlockCfgNode block |
+ e = node1.(AstNode).getCfgNode() and
+ ae = node2.asExpr() and
+ block = ae.getStmtBlock()
+ |
+ exists(Content::KnownElementContent ec, int index |
+ e = ArrayExprFlow::getReturn(block, index) and
+ cs.isKnownOrUnknownElement(ec) and
+ index = ec.getIndex().asInt()
+ )
+ or
+ not ArrayExprFlow::eachValueIsReturnedOnce(block) and
+ e = ArrayExprFlow::getAReturn(block) and
+ cs.isAnyElement()
+ )
+}
+
/**
* Holds if data can flow from `node1` to `node2` via an assignment to
* content `c`.
@@ -877,8 +887,10 @@ predicate storeStep(Node node1, ContentSet c, Node node2) {
c.isAnyElement()
)
or
- exists(Content::KnownElementContent ec, int index |
- node2.asExpr().(CfgNodes::ExprNodes::ArrayLiteralCfgNode).getExpr(index) = node1.asExpr() and
+ exists(Content::KnownElementContent ec, int index, CfgNodes::ExprCfgNode e |
+ e = node1.asExpr() and
+ not arrayExprStore(node1, _, _, e) and
+ node2.asExpr().(CfgNodes::ExprNodes::ArrayLiteralCfgNode).getExpr(index) = e and
c.isKnownOrUnknownElement(ec) and
index = ec.getIndex().asInt()
)
@@ -895,15 +907,7 @@ predicate storeStep(Node node1, ContentSet c, Node node2) {
c.isAnyElement()
)
or
- c.isAnyElement() and
- exists(
- CfgNodes::ExprNodes::ArrayExprCfgNode arrayExpr, EscapeContainer::EscapeContainer container
- |
- node2.asExpr() = arrayExpr and
- container = arrayExpr.getStmtBlock().getAstNode() and
- node1.(AstNode).getCfgNode() = container.getAnEscapingElement() and
- container.mayBeMultiReturned(_)
- )
+ arrayExprStore(node1, c, node2, _)
or
c.isAnyElement() and
exists(CfgNode cfgNode |
@@ -1089,12 +1093,12 @@ private import PostUpdateNodes
* (or statement) is being returned from a function.
*/
private class ImplicitWrapNode extends TImplicitWrapNode, NodeImpl {
- private CfgNodes::AstCfgNode n;
+ private CfgNodes::ScriptBlockCfgNode n;
private boolean shouldWrap;
ImplicitWrapNode() { this = TImplicitWrapNode(n, shouldWrap) }
- CfgNodes::AstCfgNode getReturnedNode() { result = n }
+ CfgNodes::ScriptBlockCfgNode getScriptBlock() { result = n }
predicate shouldWrap() { shouldWrap = true }
@@ -1112,12 +1116,12 @@ private class ImplicitWrapNode extends TImplicitWrapNode, NodeImpl {
* has been performed.
*/
private class PreReturNodeImpl extends TPreReturnNodeImpl, NodeImpl {
- private CfgNodes::AstCfgNode n;
+ private CfgNodes::ScriptBlockCfgNode n;
private boolean isArray;
PreReturNodeImpl() { this = TPreReturnNodeImpl(n, isArray) }
- CfgNodes::AstCfgNode getReturnedNode() { result = n }
+ CfgNodes::AstCfgNode getScriptBlock() { result = n }
override CfgScope getCfgScope() { result = n.getScope() }
diff --git a/powershell/ql/lib/semmle/code/powershell/dataflow/internal/PipelineReturns.qll b/powershell/ql/lib/semmle/code/powershell/dataflow/internal/PipelineReturns.qll
new file mode 100644
index 000000000000..fd14591617dc
--- /dev/null
+++ b/powershell/ql/lib/semmle/code/powershell/dataflow/internal/PipelineReturns.qll
@@ -0,0 +1,199 @@
+private import semmle.code.powershell.controlflow.CfgNodes
+
+/**
+ * The input module which defines the set of sources for which to calculate
+ * "escaping expressions".
+ */
+signature module InputSig {
+ /**
+ * Holds if `source` is a relevant AST element that we want to compute
+ * which expressions are returned from.
+ */
+ predicate isSource(AstCfgNode source);
+}
+
+/** The output signature from the "escape analysis". */
+signature module OutputSig {
+ /** Gets an expression that escapes from `source` */
+ ExprCfgNode getAReturn(AstCfgNode source);
+
+ /**
+ * Gets the `i`'th expression that escapes from `source`, if an ordering can
+ * be determined statically.
+ */
+ ExprCfgNode getReturn(AstCfgNode source, int i);
+
+ /** Holds multiple value may escape from `source`. */
+ predicate mayReturnMultipleValues(AstCfgNode source);
+
+ /**
+ * Holds if each value escaping from `source` is guarenteed to only escape
+ * once. In particular, if `count(getAReturn(source)) = 1` and this predicate
+ * holds, then only one value can escape from `source`.
+ *
+ * If `count(getAReturn(source)) > 1` and this predicate holds,
+ * it means that a sequence of values may escape from `source`.
+ */
+ predicate eachValueIsReturnedOnce(AstCfgNode source);
+}
+
+module Make implements OutputSig {
+ private import Input
+
+ private predicate step0(AstCfgNode pred, AstCfgNode succ) {
+ exists(NamedBlockCfgNode nb |
+ pred = nb and
+ succ = nb.getAStmt()
+ )
+ or
+ exists(StmtNodes::StmtBlockCfgNode sb |
+ pred = sb and
+ succ = sb.getAStmt()
+ )
+ or
+ exists(StmtNodes::ExprStmtCfgNode es |
+ pred = es and
+ succ = es.getExpr()
+ )
+ or
+ exists(StmtNodes::ReturnStmtCfgNode es |
+ pred = es and
+ succ = es.getPipeline()
+ )
+ or
+ exists(ExprNodes::ArrayLiteralCfgNode al |
+ pred = al and
+ succ = al.getAnExpr()
+ )
+ or
+ exists(StmtNodes::LoopStmtCfgNode loop |
+ pred = loop and
+ succ = loop.getBody()
+ )
+ or
+ exists(ExprNodes::IfCfgNode if_ |
+ pred = if_ and
+ succ = if_.getABranch()
+ )
+ or
+ exists(StmtNodes::SwitchStmtCfgNode switch |
+ pred = switch and
+ succ = switch.getACase()
+ )
+ or
+ exists(CatchClauseCfgNode catch |
+ pred = catch and
+ succ = catch.getBody()
+ )
+ or
+ exists(StmtNodes::TryStmtCfgNode try |
+ pred = try and
+ succ = [try.getBody(), try.getFinally()]
+ )
+ }
+
+ private predicate fwd(AstCfgNode n) {
+ isSource(n)
+ or
+ exists(AstCfgNode pred |
+ fwd(pred) and
+ step0(pred, n)
+ )
+ }
+
+ private predicate isSink(AstCfgNode sink) {
+ fwd(sink) and
+ (
+ sink instanceof ExprCfgNode and
+ // If is not really an expression
+ not sink instanceof ExprNodes::IfCfgNode and
+ // When `a, b, c` is returned it is flattened to returning a, and b, and c.
+ not sink instanceof ExprNodes::ArrayLiteralCfgNode
+ )
+ }
+
+ private predicate rev(AstCfgNode n) {
+ fwd(n) and
+ (
+ isSink(n)
+ or
+ exists(AstCfgNode succ |
+ rev(succ) and
+ step0(n, succ)
+ )
+ )
+ }
+
+ private predicate step(AstCfgNode n1, AstCfgNode n2) {
+ rev(n1) and
+ rev(n2) and
+ step0(n1, n2)
+ }
+
+ private predicate stepPlus(AstCfgNode n1, AstCfgNode n2) =
+ doublyBoundedFastTC(step/2, isSource/1, isSink/1)(n1, n2)
+
+ /** Gets a value that may be returned from `source`. */
+ private ExprCfgNode getAReturn0(AstCfgNode source) {
+ isSource(source) and
+ isSink(result) and
+ stepPlus(source, result)
+ }
+
+ private predicate inScopeOfSource(AstCfgNode n, AstCfgNode source) {
+ isSource(source) and
+ n.getAstNode().getParent*() = source.getAstNode()
+ }
+
+ private predicate getASuccessor(AstCfgNode pred, AstCfgNode succ) {
+ exists(AstCfgNode source |
+ inScopeOfSource(pred, source) and
+ pred.getASuccessor() = succ and
+ inScopeOfSource(succ, source)
+ )
+ }
+
+ /** Holds if `e` may be returned multiple times from `source`. */
+ private predicate mayBeReturnedMoreThanOnce(ExprCfgNode e, AstCfgNode source) {
+ e = getAReturn0(source) and getASuccessor+(e, e)
+ }
+
+ predicate eachValueIsReturnedOnce(AstCfgNode source) {
+ isSource(source) and
+ not mayBeReturnedMoreThanOnce(_, source)
+ }
+
+ private predicate isSourceForSingularReturn(AstCfgNode source) {
+ isSource(source) and
+ eachValueIsReturnedOnce(source)
+ }
+
+ private predicate hasReturnOrderImpl0(int dist, ExprCfgNode e, AstCfgNode source) =
+ shortestDistances(isSourceForSingularReturn/1, getASuccessor/2)(source, e, dist)
+
+ private predicate hasReturnOrderImpl(int dist, ExprCfgNode e) {
+ hasReturnOrderImpl0(dist, e, _) and
+ e = getAReturn0(_)
+ }
+
+ private predicate hasReturnOrder(int i, ExprCfgNode e) {
+ e = rank[i + 1](ExprCfgNode e0, int i0 | hasReturnOrderImpl(i0, e0) | e0 order by i0)
+ }
+
+ ExprCfgNode getReturn(AstCfgNode source, int i) {
+ result = getAReturn0(source) and
+ eachValueIsReturnedOnce(source) and
+ hasReturnOrder(i, result)
+ }
+
+ ExprCfgNode getAReturn(AstCfgNode source) { result = getAReturn0(source) }
+
+ /**
+ * Holds if `source` may return multiple values, and `n` is one of the values.
+ */
+ predicate mayReturnMultipleValues(AstCfgNode source) {
+ strictcount(getAReturn0(source)) > 1
+ or
+ mayBeReturnedMoreThanOnce(_, source)
+ }
+}
diff --git a/powershell/ql/lib/semmle/code/powershell/dataflow/internal/SsaImpl.qll b/powershell/ql/lib/semmle/code/powershell/dataflow/internal/SsaImpl.qll
index d9dceb4d27a4..a1e34e36af34 100644
--- a/powershell/ql/lib/semmle/code/powershell/dataflow/internal/SsaImpl.qll
+++ b/powershell/ql/lib/semmle/code/powershell/dataflow/internal/SsaImpl.qll
@@ -27,12 +27,6 @@ module SsaInput implements SsaImplCommon::InputSig {
*/
predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain) {
(
- exists(Scope scope | scope = v.(ThisParameter).getDeclaringScope() |
- // We consider the `this` variable to have a single write at the entry to a method block
- scope = bb.(BasicBlocks::EntryBasicBlock).getScope() and
- i = 0
- )
- or
uninitializedWrite(bb, i, v)
or
variableWriteActual(bb, i, v, _)
@@ -138,9 +132,7 @@ private module Cached {
* AST write access is `write`.
*/
cached
- predicate variableWriteActual(
- Cfg::BasicBlock bb, int i, Variable v, VarWriteAccessCfgNode write
- ) {
+ predicate variableWriteActual(Cfg::BasicBlock bb, int i, Variable v, VarWriteAccessCfgNode write) {
exists(Cfg::CfgNode n |
write.getVariable() = v and
n = bb.getNode(i)
@@ -277,7 +269,8 @@ private Parameter getANonPipelineParameter(FunctionBase f) {
class NormalParameter extends Parameter {
NormalParameter() {
not this instanceof PipelineParameter and
- not this instanceof PipelineByPropertyNameParameter
+ not this instanceof PipelineByPropertyNameParameter and
+ not this instanceof ThisParameter
}
int getIndexExcludingPipelines() {
@@ -295,18 +288,18 @@ class NormalParameter extends Parameter {
private newtype TParameterExt =
TNormalParameter(NormalParameter p) or
- TSelfMethodParameter(Method m)
+ TThisMethodParameter(Method m)
-/** A normal parameter or an implicit `self` parameter. */
+/** A normal parameter or an implicit `this` parameter. */
class ParameterExt extends TParameterExt {
NormalParameter asParameter() { this = TNormalParameter(result) }
- Method asThis() { this = TSelfMethodParameter(result) }
+ Method asThis() { this = TThisMethodParameter(result) }
predicate isInitializedBy(WriteDefinition def) {
def = getParameterDef(this.asParameter())
or
- def.(Ssa::ThisDefinition).getSourceVariable().getDeclaringScope() = this.asThis().(Scope)
+ def.(Ssa::ThisDefinition).getSourceVariable().getDeclaringScope() = this.asThis().getBody()
}
string toString() { result = [this.asParameter().toString(), this.asThis().toString()] }
diff --git a/powershell/ql/lib/semmle/code/powershell/internal/AstEscape.qll b/powershell/ql/lib/semmle/code/powershell/internal/AstEscape.qll
deleted file mode 100644
index 7e031d537bdb..000000000000
--- a/powershell/ql/lib/semmle/code/powershell/internal/AstEscape.qll
+++ /dev/null
@@ -1,84 +0,0 @@
-private import powershell as PS
-
-/**
- * TODO: This whole computation cab be sped up by providing a set of "root"s and doing
- * a forward/backwards traversal first.
- */
-module Private {
- signature module InterpretAstInputSig {
- /** The type on which to translate `Ast` elements during escape calculations */
- class T;
-
- /** Interpret `a` into a `T` */
- T interpret(PS::Ast a);
- }
-
- module AstEscape {
- private import Interpret
-
- /** An AST element that may produce a value which can escape from this `Ast` when evaluated. */
- abstract private class ElementImpl instanceof PS::Ast {
- string toString() { result = super.toString() }
-
- /** Gets a direct node that will may escape when evaluating this element. */
- T getANode() { none() }
-
- /** Gets a child that may produce more elements that may escape. */
- abstract Element getAChild();
-
- /**
- * Gets a (possibly transitive) element that may escape when evaluating
- * this element.
- */
- final T getAnEscapingElement() {
- result = this.getANode()
- or
- result = this.getAChild().getAnEscapingElement()
- }
- }
-
- final class Element = ElementImpl;
-
- private class ScriptBlockElement extends ElementImpl instanceof PS::ScriptBlock {
- final override Element getAChild() { result = super.getEndBlock() }
- }
-
- private class NamedBlockElement extends ElementImpl instanceof PS::NamedBlock {
- final override Element getAChild() { result = super.getAStmt() }
- }
-
- private class ExprStmtElement extends ElementImpl instanceof PS::ExprStmt {
- final override T getANode() { result = interpret(super.getExpr()) }
-
- final override Element getAChild() { none() }
- }
-
- private class LoopStmtElement extends ElementImpl instanceof PS::LoopStmt {
- final override Element getAChild() { result = super.getBody() }
- }
-
- private class StmtBlockElement extends ElementImpl instanceof PS::StmtBlock {
- final override Element getAChild() { result = super.getAStmt() }
- }
-
- private class TryStmtElement extends ElementImpl instanceof PS::TryStmt {
- final override Element getAChild() {
- result = super.getBody() or result = super.getACatchClause() or result = super.getFinally()
- }
- }
-
- private class ReturnStmtElement extends ElementImpl instanceof PS::ReturnStmt {
- final override Element getAChild() { result = super.getPipeline() }
- }
-
- private class CatchClausElement extends ElementImpl instanceof PS::CatchClause {
- final override Element getAChild() { result = super.getBody() }
- }
-
- private class SwitchStmtElement extends ElementImpl instanceof PS::SwitchStmt {
- final override Element getAChild() { result = super.getACase() }
- }
- }
-}
-
-module Public { }
diff --git a/powershell/ql/test/library-tests/controlflow/graph/Cfg.expected b/powershell/ql/test/library-tests/controlflow/graph/Cfg.expected
index c2432f65b155..d4be5cad40bf 100644
--- a/powershell/ql/test/library-tests/controlflow/graph/Cfg.expected
+++ b/powershell/ql/test/library-tests/controlflow/graph/Cfg.expected
@@ -247,7 +247,9 @@
| functions.ps1:13:28:20:1 | enter {...} | functions.ps1:13:28:20:1 | {...} | |
| functions.ps1:13:28:20:1 | exit {...} (normal) | functions.ps1:13:28:20:1 | exit {...} | |
| functions.ps1:13:28:20:1 | name0 | functions.ps1:13:28:20:1 | name1 | |
+| functions.ps1:13:28:20:1 | name1 | functions.ps1:13:28:20:1 | name2 | |
| functions.ps1:13:28:20:1 | name1 | functions.ps1:16:24:16:24 | 0 | |
+| functions.ps1:13:28:20:1 | name2 | functions.ps1:13:28:20:1 | [synth] pipeline | |
| functions.ps1:13:28:20:1 | name2 | functions.ps1:17:24:17:29 | name1 | |
| functions.ps1:13:28:20:1 | {...} | functions.ps1:16:24:16:24 | 0 | |
| functions.ps1:14:5:19:18 | {...} | functions.ps1:19:5:19:18 | [Stmt] ...+... | |
diff --git a/powershell/ql/test/library-tests/controlflow/graph/consistency.expected b/powershell/ql/test/library-tests/controlflow/graph/consistency.expected
index 68e5304a2904..33994ab4888b 100644
--- a/powershell/ql/test/library-tests/controlflow/graph/consistency.expected
+++ b/powershell/ql/test/library-tests/controlflow/graph/consistency.expected
@@ -8,6 +8,10 @@ multipleSuccessors
| functions.ps1:8:5:8:23 | [Stmt] ...+... | successor | functions.ps1:46:17:46:18 | __pipeline_iterator |
| functions.ps1:8:5:8:23 | [Stmt] __pipeline_iterator | successor | functions.ps1:8:5:8:12 | number1 |
| functions.ps1:8:5:8:23 | [Stmt] __pipeline_iterator | successor | functions.ps1:46:17:46:18 | __pipeline_iterator |
+| functions.ps1:13:28:20:1 | name1 | successor | functions.ps1:13:28:20:1 | name2 |
+| functions.ps1:13:28:20:1 | name1 | successor | functions.ps1:16:24:16:24 | 0 |
+| functions.ps1:13:28:20:1 | name2 | successor | functions.ps1:13:28:20:1 | [synth] pipeline |
+| functions.ps1:13:28:20:1 | name2 | successor | functions.ps1:17:24:17:29 | name1 |
| functions.ps1:16:24:16:24 | 0 | successor | functions.ps1:13:28:20:1 | name2 |
| functions.ps1:16:24:16:24 | 0 | successor | functions.ps1:17:24:17:29 | name1 |
| functions.ps1:17:24:17:33 | ...+... | successor | functions.ps1:13:28:20:1 | [synth] pipeline |
diff --git a/powershell/ql/test/library-tests/dataflow/fields/test.expected b/powershell/ql/test/library-tests/dataflow/fields/test.expected
index 8916976e2a57..0908f093abc0 100644
--- a/powershell/ql/test/library-tests/dataflow/fields/test.expected
+++ b/powershell/ql/test/library-tests/dataflow/fields/test.expected
@@ -40,11 +40,33 @@ edges
| test.ps1:40:6:40:10 | arr8 [element 2] | test.ps1:40:6:40:13 | ...[...] | provenance | |
| test.ps1:41:6:41:10 | arr8 [element 2] | test.ps1:41:6:41:20 | ...[...] | provenance | |
| test.ps1:43:6:43:16 | Call to Source | test.ps1:45:17:45:18 | y | provenance | |
-| test.ps1:45:11:45:18 | ...,... [element 2] | test.ps1:48:6:48:10 | arr9 [element 2] | provenance | |
-| test.ps1:45:11:45:18 | ...,... [element 2] | test.ps1:49:6:49:10 | arr9 [element 2] | provenance | |
-| test.ps1:45:17:45:18 | y | test.ps1:45:11:45:18 | ...,... [element 2] | provenance | |
+| test.ps1:45:9:45:19 | @(...) [element 2] | test.ps1:48:6:48:10 | arr9 [element 2] | provenance | |
+| test.ps1:45:9:45:19 | @(...) [element 2] | test.ps1:49:6:49:10 | arr9 [element 2] | provenance | |
+| test.ps1:45:17:45:18 | y | test.ps1:45:9:45:19 | @(...) [element 2] | provenance | |
| test.ps1:48:6:48:10 | arr9 [element 2] | test.ps1:48:6:48:13 | ...[...] | provenance | |
| test.ps1:49:6:49:10 | arr9 [element 2] | test.ps1:49:6:49:20 | ...[...] | provenance | |
+| test.ps1:54:5:56:5 | this [field] | test.ps1:55:14:55:24 | this [field] | provenance | |
+| test.ps1:55:14:55:24 | this [field] | test.ps1:55:14:55:24 | field | provenance | |
+| test.ps1:61:1:61:8 | [post] myClass [field] | test.ps1:63:1:63:8 | myClass [field] | provenance | |
+| test.ps1:61:18:61:28 | Call to Source | test.ps1:61:1:61:8 | [post] myClass [field] | provenance | |
+| test.ps1:63:1:63:8 | myClass [field] | test.ps1:54:5:56:5 | this [field] | provenance | |
+| test.ps1:66:10:66:20 | Call to Source | test.ps1:69:5:69:6 | x | provenance | |
+| test.ps1:67:10:67:20 | Call to Source | test.ps1:70:5:70:6 | y | provenance | |
+| test.ps1:68:10:68:20 | Call to Source | test.ps1:70:9:70:10 | z | provenance | |
+| test.ps1:69:5:69:6 | x | test.ps1:73:6:73:12 | Call to produce [element] | provenance | |
+| test.ps1:70:5:70:6 | y | test.ps1:73:6:73:12 | Call to produce [element] | provenance | |
+| test.ps1:70:9:70:10 | z | test.ps1:73:6:73:12 | Call to produce [element] | provenance | |
+| test.ps1:73:6:73:12 | Call to produce [element] | test.ps1:74:6:74:7 | x [element] | provenance | |
+| test.ps1:73:6:73:12 | Call to produce [element] | test.ps1:75:6:75:7 | x [element] | provenance | |
+| test.ps1:73:6:73:12 | Call to produce [element] | test.ps1:76:6:76:7 | x [element] | provenance | |
+| test.ps1:74:6:74:7 | x [element] | test.ps1:74:6:74:10 | ...[...] | provenance | |
+| test.ps1:75:6:75:7 | x [element] | test.ps1:75:6:75:10 | ...[...] | provenance | |
+| test.ps1:76:6:76:7 | x [element] | test.ps1:76:6:76:10 | ...[...] | provenance | |
+| test.ps1:78:9:81:1 | ${...} [element a] | test.ps1:83:6:83:10 | hash [element a] | provenance | |
+| test.ps1:78:9:81:1 | ${...} [element a] | test.ps1:87:6:87:10 | hash [element a] | provenance | |
+| test.ps1:79:7:79:17 | Call to Source | test.ps1:78:9:81:1 | ${...} [element a] | provenance | |
+| test.ps1:83:6:83:10 | hash [element a] | test.ps1:83:6:83:15 | ...[...] | provenance | |
+| test.ps1:87:6:87:10 | hash [element a] | test.ps1:87:6:87:15 | ...[...] | provenance | |
| test.ps1:88:1:88:5 | [post] hash [b] | test.ps1:89:6:89:10 | hash [b] | provenance | |
| test.ps1:88:11:88:21 | Call to Source | test.ps1:88:1:88:5 | [post] hash [b] | provenance | |
| test.ps1:89:6:89:10 | hash [b] | test.ps1:89:6:89:12 | b | provenance | |
@@ -98,30 +120,43 @@ nodes
| test.ps1:41:6:41:10 | arr8 [element 2] | semmle.label | arr8 [element 2] |
| test.ps1:41:6:41:20 | ...[...] | semmle.label | ...[...] |
| test.ps1:43:6:43:16 | Call to Source | semmle.label | Call to Source |
-| test.ps1:45:11:45:18 | ...,... [element 2] | semmle.label | ...,... [element 2] |
+| test.ps1:45:9:45:19 | @(...) [element 2] | semmle.label | @(...) [element 2] |
| test.ps1:45:17:45:18 | y | semmle.label | y |
| test.ps1:48:6:48:10 | arr9 [element 2] | semmle.label | arr9 [element 2] |
| test.ps1:48:6:48:13 | ...[...] | semmle.label | ...[...] |
| test.ps1:49:6:49:10 | arr9 [element 2] | semmle.label | arr9 [element 2] |
| test.ps1:49:6:49:20 | ...[...] | semmle.label | ...[...] |
+| test.ps1:54:5:56:5 | this [field] | semmle.label | this [field] |
+| test.ps1:55:14:55:24 | field | semmle.label | field |
+| test.ps1:55:14:55:24 | this [field] | semmle.label | this [field] |
+| test.ps1:61:1:61:8 | [post] myClass [field] | semmle.label | [post] myClass [field] |
+| test.ps1:61:18:61:28 | Call to Source | semmle.label | Call to Source |
+| test.ps1:63:1:63:8 | myClass [field] | semmle.label | myClass [field] |
+| test.ps1:66:10:66:20 | Call to Source | semmle.label | Call to Source |
+| test.ps1:67:10:67:20 | Call to Source | semmle.label | Call to Source |
+| test.ps1:68:10:68:20 | Call to Source | semmle.label | Call to Source |
+| test.ps1:69:5:69:6 | x | semmle.label | x |
+| test.ps1:70:5:70:6 | y | semmle.label | y |
+| test.ps1:70:9:70:10 | z | semmle.label | z |
+| test.ps1:73:6:73:12 | Call to produce [element] | semmle.label | Call to produce [element] |
+| test.ps1:74:6:74:7 | x [element] | semmle.label | x [element] |
+| test.ps1:74:6:74:10 | ...[...] | semmle.label | ...[...] |
+| test.ps1:75:6:75:7 | x [element] | semmle.label | x [element] |
+| test.ps1:75:6:75:10 | ...[...] | semmle.label | ...[...] |
+| test.ps1:76:6:76:7 | x [element] | semmle.label | x [element] |
+| test.ps1:76:6:76:10 | ...[...] | semmle.label | ...[...] |
+| test.ps1:78:9:81:1 | ${...} [element a] | semmle.label | ${...} [element a] |
+| test.ps1:79:7:79:17 | Call to Source | semmle.label | Call to Source |
+| test.ps1:83:6:83:10 | hash [element a] | semmle.label | hash [element a] |
+| test.ps1:83:6:83:15 | ...[...] | semmle.label | ...[...] |
+| test.ps1:87:6:87:10 | hash [element a] | semmle.label | hash [element a] |
+| test.ps1:87:6:87:15 | ...[...] | semmle.label | ...[...] |
| test.ps1:88:1:88:5 | [post] hash [b] | semmle.label | [post] hash [b] |
| test.ps1:88:11:88:21 | Call to Source | semmle.label | Call to Source |
| test.ps1:89:6:89:10 | hash [b] | semmle.label | hash [b] |
| test.ps1:89:6:89:12 | b | semmle.label | b |
subpaths
testFailures
-| test.ps1:55:26:55:44 | # $ hasValueFlow=12 | Missing result: hasValueFlow=12 |
-| test.ps1:74:12:74:62 | # $ hasValueFlow=13 hasValueFlow=14 hasValueFlow=15 | Missing result: hasValueFlow=13 |
-| test.ps1:74:12:74:62 | # $ hasValueFlow=13 hasValueFlow=14 hasValueFlow=15 | Missing result: hasValueFlow=14 |
-| test.ps1:74:12:74:62 | # $ hasValueFlow=13 hasValueFlow=14 hasValueFlow=15 | Missing result: hasValueFlow=15 |
-| test.ps1:75:12:75:62 | # $ hasValueFlow=13 hasValueFlow=14 hasValueFlow=15 | Missing result: hasValueFlow=13 |
-| test.ps1:75:12:75:62 | # $ hasValueFlow=13 hasValueFlow=14 hasValueFlow=15 | Missing result: hasValueFlow=14 |
-| test.ps1:75:12:75:62 | # $ hasValueFlow=13 hasValueFlow=14 hasValueFlow=15 | Missing result: hasValueFlow=15 |
-| test.ps1:76:12:76:62 | # $ hasValueFlow=13 hasValueFlow=14 hasValueFlow=15 | Missing result: hasValueFlow=13 |
-| test.ps1:76:12:76:62 | # $ hasValueFlow=13 hasValueFlow=14 hasValueFlow=15 | Missing result: hasValueFlow=14 |
-| test.ps1:76:12:76:62 | # $ hasValueFlow=13 hasValueFlow=14 hasValueFlow=15 | Missing result: hasValueFlow=15 |
-| test.ps1:83:17:83:35 | # $ hasValueFlow=16 | Missing result: hasValueFlow=16 |
-| test.ps1:87:17:87:45 | # $ SPURIOUS: hasValueFlow=16 | Fixed spurious result: hasValueFlow=16 |
#select
| test.ps1:4:6:4:9 | f | test.ps1:3:8:3:17 | Call to Source | test.ps1:4:6:4:9 | f | $@ | test.ps1:3:8:3:17 | Call to Source | Call to Source |
| test.ps1:11:6:11:13 | ...[...] | test.ps1:10:12:10:21 | Call to Source | test.ps1:11:6:11:13 | ...[...] | $@ | test.ps1:10:12:10:21 | Call to Source | Call to Source |
@@ -136,4 +171,16 @@ testFailures
| test.ps1:41:6:41:20 | ...[...] | test.ps1:35:6:35:16 | Call to Source | test.ps1:41:6:41:20 | ...[...] | $@ | test.ps1:35:6:35:16 | Call to Source | Call to Source |
| test.ps1:48:6:48:13 | ...[...] | test.ps1:43:6:43:16 | Call to Source | test.ps1:48:6:48:13 | ...[...] | $@ | test.ps1:43:6:43:16 | Call to Source | Call to Source |
| test.ps1:49:6:49:20 | ...[...] | test.ps1:43:6:43:16 | Call to Source | test.ps1:49:6:49:20 | ...[...] | $@ | test.ps1:43:6:43:16 | Call to Source | Call to Source |
+| test.ps1:55:14:55:24 | field | test.ps1:61:18:61:28 | Call to Source | test.ps1:55:14:55:24 | field | $@ | test.ps1:61:18:61:28 | Call to Source | Call to Source |
+| test.ps1:74:6:74:10 | ...[...] | test.ps1:66:10:66:20 | Call to Source | test.ps1:74:6:74:10 | ...[...] | $@ | test.ps1:66:10:66:20 | Call to Source | Call to Source |
+| test.ps1:74:6:74:10 | ...[...] | test.ps1:67:10:67:20 | Call to Source | test.ps1:74:6:74:10 | ...[...] | $@ | test.ps1:67:10:67:20 | Call to Source | Call to Source |
+| test.ps1:74:6:74:10 | ...[...] | test.ps1:68:10:68:20 | Call to Source | test.ps1:74:6:74:10 | ...[...] | $@ | test.ps1:68:10:68:20 | Call to Source | Call to Source |
+| test.ps1:75:6:75:10 | ...[...] | test.ps1:66:10:66:20 | Call to Source | test.ps1:75:6:75:10 | ...[...] | $@ | test.ps1:66:10:66:20 | Call to Source | Call to Source |
+| test.ps1:75:6:75:10 | ...[...] | test.ps1:67:10:67:20 | Call to Source | test.ps1:75:6:75:10 | ...[...] | $@ | test.ps1:67:10:67:20 | Call to Source | Call to Source |
+| test.ps1:75:6:75:10 | ...[...] | test.ps1:68:10:68:20 | Call to Source | test.ps1:75:6:75:10 | ...[...] | $@ | test.ps1:68:10:68:20 | Call to Source | Call to Source |
+| test.ps1:76:6:76:10 | ...[...] | test.ps1:66:10:66:20 | Call to Source | test.ps1:76:6:76:10 | ...[...] | $@ | test.ps1:66:10:66:20 | Call to Source | Call to Source |
+| test.ps1:76:6:76:10 | ...[...] | test.ps1:67:10:67:20 | Call to Source | test.ps1:76:6:76:10 | ...[...] | $@ | test.ps1:67:10:67:20 | Call to Source | Call to Source |
+| test.ps1:76:6:76:10 | ...[...] | test.ps1:68:10:68:20 | Call to Source | test.ps1:76:6:76:10 | ...[...] | $@ | test.ps1:68:10:68:20 | Call to Source | Call to Source |
+| test.ps1:83:6:83:15 | ...[...] | test.ps1:79:7:79:17 | Call to Source | test.ps1:83:6:83:15 | ...[...] | $@ | test.ps1:79:7:79:17 | Call to Source | Call to Source |
+| test.ps1:87:6:87:15 | ...[...] | test.ps1:79:7:79:17 | Call to Source | test.ps1:87:6:87:15 | ...[...] | $@ | test.ps1:79:7:79:17 | Call to Source | Call to Source |
| test.ps1:89:6:89:12 | b | test.ps1:88:11:88:21 | Call to Source | test.ps1:89:6:89:12 | b | $@ | test.ps1:88:11:88:21 | Call to Source | Call to Source |
diff --git a/powershell/ql/test/library-tests/dataflow/local/flow.expected b/powershell/ql/test/library-tests/dataflow/local/flow.expected
index 080873884dfe..e7aa288529cb 100644
--- a/powershell/ql/test/library-tests/dataflow/local/flow.expected
+++ b/powershell/ql/test/library-tests/dataflow/local/flow.expected
@@ -1,51 +1,37 @@
| test.ps1:1:1:1:3 | a1 | test.ps1:2:6:2:8 | a1 |
+| test.ps1:1:1:21:27 | implicit unwrapping of {...} | test.ps1:1:1:21:27 | return value for {...} |
+| test.ps1:1:1:21:27 | pre-return value for {...} | test.ps1:1:1:21:27 | implicit unwrapping of {...} |
| test.ps1:1:7:1:12 | Call to Source | test.ps1:1:1:1:3 | a1 |
-| test.ps1:2:1:2:8 | Call to Sink | test.ps1:2:1:2:8 | pre-return value for Call to Sink |
-| test.ps1:2:1:2:8 | Call to Sink | test.ps1:2:1:2:8 | pre-return value for Call to Sink |
-| test.ps1:2:1:2:8 | implicit unwrapping of Call to Sink | test.ps1:1:1:21:27 | return value for {...} |
-| test.ps1:2:1:2:8 | pre-return value for Call to Sink | test.ps1:2:1:2:8 | implicit unwrapping of Call to Sink |
+| test.ps1:2:1:2:8 | Call to Sink | test.ps1:1:1:21:27 | pre-return value for {...} |
+| test.ps1:2:1:2:8 | Call to Sink | test.ps1:1:1:21:27 | pre-return value for {...} |
| test.ps1:4:1:4:2 | b | test.ps1:5:4:5:5 | b |
| test.ps1:4:6:4:12 | Call to GetBool | test.ps1:4:1:4:2 | b |
-| test.ps1:5:1:7:1 | if (...) {...} | test.ps1:5:1:7:1 | pre-return value for if (...) {...} |
-| test.ps1:5:1:7:1 | if (...) {...} | test.ps1:5:1:7:1 | pre-return value for if (...) {...} |
-| test.ps1:5:1:7:1 | implicit unwrapping of if (...) {...} | test.ps1:1:1:21:27 | return value for {...} |
| test.ps1:5:1:7:1 | phi | test.ps1:8:6:8:8 | a2 |
-| test.ps1:5:1:7:1 | pre-return value for if (...) {...} | test.ps1:5:1:7:1 | implicit unwrapping of if (...) {...} |
| test.ps1:5:4:5:5 | b | test.ps1:10:14:10:15 | b |
| test.ps1:6:5:6:7 | a2 | test.ps1:6:11:6:16 | [input] phi |
| test.ps1:6:11:6:16 | Call to Source | test.ps1:6:5:6:7 | a2 |
| test.ps1:6:11:6:16 | [input] phi | test.ps1:5:1:7:1 | phi |
-| test.ps1:8:1:8:8 | Call to Sink | test.ps1:8:1:8:8 | pre-return value for Call to Sink |
-| test.ps1:8:1:8:8 | Call to Sink | test.ps1:8:1:8:8 | pre-return value for Call to Sink |
-| test.ps1:8:1:8:8 | implicit unwrapping of Call to Sink | test.ps1:1:1:21:27 | return value for {...} |
-| test.ps1:8:1:8:8 | pre-return value for Call to Sink | test.ps1:8:1:8:8 | implicit unwrapping of Call to Sink |
+| test.ps1:8:1:8:8 | Call to Sink | test.ps1:1:1:21:27 | pre-return value for {...} |
+| test.ps1:8:1:8:8 | Call to Sink | test.ps1:1:1:21:27 | pre-return value for {...} |
| test.ps1:10:1:10:2 | c | test.ps1:11:6:11:7 | c |
| test.ps1:10:6:10:15 | [...]... | test.ps1:10:1:10:2 | c |
| test.ps1:10:14:10:15 | b | test.ps1:10:6:10:15 | [...]... |
-| test.ps1:11:1:11:7 | Call to Sink | test.ps1:11:1:11:7 | pre-return value for Call to Sink |
-| test.ps1:11:1:11:7 | Call to Sink | test.ps1:11:1:11:7 | pre-return value for Call to Sink |
-| test.ps1:11:1:11:7 | implicit unwrapping of Call to Sink | test.ps1:1:1:21:27 | return value for {...} |
-| test.ps1:11:1:11:7 | pre-return value for Call to Sink | test.ps1:11:1:11:7 | implicit unwrapping of Call to Sink |
+| test.ps1:11:1:11:7 | Call to Sink | test.ps1:1:1:21:27 | pre-return value for {...} |
+| test.ps1:11:1:11:7 | Call to Sink | test.ps1:1:1:21:27 | pre-return value for {...} |
| test.ps1:11:6:11:7 | [post] c | test.ps1:13:7:13:8 | c |
| test.ps1:11:6:11:7 | c | test.ps1:13:7:13:8 | c |
| test.ps1:13:1:13:2 | d | test.ps1:14:6:14:7 | d |
| test.ps1:13:6:13:9 | (...) | test.ps1:13:1:13:2 | d |
| test.ps1:13:7:13:8 | c | test.ps1:13:6:13:9 | (...) |
-| test.ps1:14:1:14:7 | Call to Sink | test.ps1:14:1:14:7 | pre-return value for Call to Sink |
-| test.ps1:14:1:14:7 | Call to Sink | test.ps1:14:1:14:7 | pre-return value for Call to Sink |
-| test.ps1:14:1:14:7 | implicit unwrapping of Call to Sink | test.ps1:1:1:21:27 | return value for {...} |
-| test.ps1:14:1:14:7 | pre-return value for Call to Sink | test.ps1:14:1:14:7 | implicit unwrapping of Call to Sink |
+| test.ps1:14:1:14:7 | Call to Sink | test.ps1:1:1:21:27 | pre-return value for {...} |
+| test.ps1:14:1:14:7 | Call to Sink | test.ps1:1:1:21:27 | pre-return value for {...} |
| test.ps1:14:6:14:7 | [post] d | test.ps1:16:6:16:7 | d |
| test.ps1:14:6:14:7 | d | test.ps1:16:6:16:7 | d |
| test.ps1:16:1:16:2 | e | test.ps1:17:6:17:7 | e |
| test.ps1:16:6:16:11 | ...+... | test.ps1:16:1:16:2 | e |
-| test.ps1:17:1:17:7 | Call to Sink | test.ps1:17:1:17:7 | pre-return value for Call to Sink |
-| test.ps1:17:1:17:7 | Call to Sink | test.ps1:17:1:17:7 | pre-return value for Call to Sink |
-| test.ps1:17:1:17:7 | implicit unwrapping of Call to Sink | test.ps1:1:1:21:27 | return value for {...} |
-| test.ps1:17:1:17:7 | pre-return value for Call to Sink | test.ps1:17:1:17:7 | implicit unwrapping of Call to Sink |
+| test.ps1:17:1:17:7 | Call to Sink | test.ps1:1:1:21:27 | pre-return value for {...} |
+| test.ps1:17:1:17:7 | Call to Sink | test.ps1:1:1:21:27 | pre-return value for {...} |
| test.ps1:19:1:19:2 | f | test.ps1:21:25:21:26 | f |
| test.ps1:19:6:19:11 | Call to Source | test.ps1:19:1:19:2 | f |
-| test.ps1:21:1:21:27 | Call to Sink | test.ps1:21:1:21:27 | pre-return value for Call to Sink |
-| test.ps1:21:1:21:27 | Call to Sink | test.ps1:21:1:21:27 | pre-return value for Call to Sink |
-| test.ps1:21:1:21:27 | implicit unwrapping of Call to Sink | test.ps1:1:1:21:27 | return value for {...} |
-| test.ps1:21:1:21:27 | pre-return value for Call to Sink | test.ps1:21:1:21:27 | implicit unwrapping of Call to Sink |
+| test.ps1:21:1:21:27 | Call to Sink | test.ps1:1:1:21:27 | pre-return value for {...} |
+| test.ps1:21:1:21:27 | Call to Sink | test.ps1:1:1:21:27 | pre-return value for {...} |
diff --git a/powershell/ql/test/library-tests/dataflow/local/taint.expected b/powershell/ql/test/library-tests/dataflow/local/taint.expected
index 5a68287270e1..381f685afbdf 100644
--- a/powershell/ql/test/library-tests/dataflow/local/taint.expected
+++ b/powershell/ql/test/library-tests/dataflow/local/taint.expected
@@ -1,61 +1,41 @@
| test.ps1:1:1:1:3 | a1 | test.ps1:2:6:2:8 | a1 |
+| test.ps1:1:1:21:27 | implicit unwrapping of {...} | test.ps1:1:1:21:27 | return value for {...} |
+| test.ps1:1:1:21:27 | pre-return value for {...} | test.ps1:1:1:21:27 | implicit unwrapping of {...} |
+| test.ps1:1:1:21:27 | pre-return value for {...} | test.ps1:1:1:21:27 | implicit unwrapping of {...} |
| test.ps1:1:7:1:12 | Call to Source | test.ps1:1:1:1:3 | a1 |
-| test.ps1:2:1:2:8 | Call to Sink | test.ps1:2:1:2:8 | pre-return value for Call to Sink |
-| test.ps1:2:1:2:8 | Call to Sink | test.ps1:2:1:2:8 | pre-return value for Call to Sink |
-| test.ps1:2:1:2:8 | implicit unwrapping of Call to Sink | test.ps1:1:1:21:27 | return value for {...} |
-| test.ps1:2:1:2:8 | pre-return value for Call to Sink | test.ps1:2:1:2:8 | implicit unwrapping of Call to Sink |
-| test.ps1:2:1:2:8 | pre-return value for Call to Sink | test.ps1:2:1:2:8 | implicit unwrapping of Call to Sink |
+| test.ps1:2:1:2:8 | Call to Sink | test.ps1:1:1:21:27 | pre-return value for {...} |
+| test.ps1:2:1:2:8 | Call to Sink | test.ps1:1:1:21:27 | pre-return value for {...} |
| test.ps1:4:1:4:2 | b | test.ps1:5:4:5:5 | b |
| test.ps1:4:6:4:12 | Call to GetBool | test.ps1:4:1:4:2 | b |
-| test.ps1:5:1:7:1 | if (...) {...} | test.ps1:5:1:7:1 | pre-return value for if (...) {...} |
-| test.ps1:5:1:7:1 | if (...) {...} | test.ps1:5:1:7:1 | pre-return value for if (...) {...} |
-| test.ps1:5:1:7:1 | implicit unwrapping of if (...) {...} | test.ps1:1:1:21:27 | return value for {...} |
| test.ps1:5:1:7:1 | phi | test.ps1:8:6:8:8 | a2 |
-| test.ps1:5:1:7:1 | pre-return value for if (...) {...} | test.ps1:5:1:7:1 | implicit unwrapping of if (...) {...} |
-| test.ps1:5:1:7:1 | pre-return value for if (...) {...} | test.ps1:5:1:7:1 | implicit unwrapping of if (...) {...} |
| test.ps1:5:4:5:5 | b | test.ps1:10:14:10:15 | b |
| test.ps1:6:5:6:7 | a2 | test.ps1:6:11:6:16 | [input] phi |
| test.ps1:6:11:6:16 | Call to Source | test.ps1:6:5:6:7 | a2 |
| test.ps1:6:11:6:16 | [input] phi | test.ps1:5:1:7:1 | phi |
-| test.ps1:8:1:8:8 | Call to Sink | test.ps1:8:1:8:8 | pre-return value for Call to Sink |
-| test.ps1:8:1:8:8 | Call to Sink | test.ps1:8:1:8:8 | pre-return value for Call to Sink |
-| test.ps1:8:1:8:8 | implicit unwrapping of Call to Sink | test.ps1:1:1:21:27 | return value for {...} |
-| test.ps1:8:1:8:8 | pre-return value for Call to Sink | test.ps1:8:1:8:8 | implicit unwrapping of Call to Sink |
-| test.ps1:8:1:8:8 | pre-return value for Call to Sink | test.ps1:8:1:8:8 | implicit unwrapping of Call to Sink |
+| test.ps1:8:1:8:8 | Call to Sink | test.ps1:1:1:21:27 | pre-return value for {...} |
+| test.ps1:8:1:8:8 | Call to Sink | test.ps1:1:1:21:27 | pre-return value for {...} |
| test.ps1:10:1:10:2 | c | test.ps1:11:6:11:7 | c |
| test.ps1:10:6:10:15 | [...]... | test.ps1:10:1:10:2 | c |
| test.ps1:10:14:10:15 | b | test.ps1:10:6:10:15 | [...]... |
-| test.ps1:11:1:11:7 | Call to Sink | test.ps1:11:1:11:7 | pre-return value for Call to Sink |
-| test.ps1:11:1:11:7 | Call to Sink | test.ps1:11:1:11:7 | pre-return value for Call to Sink |
-| test.ps1:11:1:11:7 | implicit unwrapping of Call to Sink | test.ps1:1:1:21:27 | return value for {...} |
-| test.ps1:11:1:11:7 | pre-return value for Call to Sink | test.ps1:11:1:11:7 | implicit unwrapping of Call to Sink |
-| test.ps1:11:1:11:7 | pre-return value for Call to Sink | test.ps1:11:1:11:7 | implicit unwrapping of Call to Sink |
+| test.ps1:11:1:11:7 | Call to Sink | test.ps1:1:1:21:27 | pre-return value for {...} |
+| test.ps1:11:1:11:7 | Call to Sink | test.ps1:1:1:21:27 | pre-return value for {...} |
| test.ps1:11:6:11:7 | [post] c | test.ps1:13:7:13:8 | c |
| test.ps1:11:6:11:7 | c | test.ps1:13:7:13:8 | c |
| test.ps1:13:1:13:2 | d | test.ps1:14:6:14:7 | d |
| test.ps1:13:6:13:9 | (...) | test.ps1:13:1:13:2 | d |
| test.ps1:13:7:13:8 | c | test.ps1:13:6:13:9 | (...) |
-| test.ps1:14:1:14:7 | Call to Sink | test.ps1:14:1:14:7 | pre-return value for Call to Sink |
-| test.ps1:14:1:14:7 | Call to Sink | test.ps1:14:1:14:7 | pre-return value for Call to Sink |
-| test.ps1:14:1:14:7 | implicit unwrapping of Call to Sink | test.ps1:1:1:21:27 | return value for {...} |
-| test.ps1:14:1:14:7 | pre-return value for Call to Sink | test.ps1:14:1:14:7 | implicit unwrapping of Call to Sink |
-| test.ps1:14:1:14:7 | pre-return value for Call to Sink | test.ps1:14:1:14:7 | implicit unwrapping of Call to Sink |
+| test.ps1:14:1:14:7 | Call to Sink | test.ps1:1:1:21:27 | pre-return value for {...} |
+| test.ps1:14:1:14:7 | Call to Sink | test.ps1:1:1:21:27 | pre-return value for {...} |
| test.ps1:14:6:14:7 | [post] d | test.ps1:16:6:16:7 | d |
| test.ps1:14:6:14:7 | d | test.ps1:16:6:16:7 | d |
| test.ps1:16:1:16:2 | e | test.ps1:17:6:17:7 | e |
| test.ps1:16:6:16:7 | d | test.ps1:16:6:16:11 | ...+... |
| test.ps1:16:6:16:11 | ...+... | test.ps1:16:1:16:2 | e |
| test.ps1:16:11:16:11 | 1 | test.ps1:16:6:16:11 | ...+... |
-| test.ps1:17:1:17:7 | Call to Sink | test.ps1:17:1:17:7 | pre-return value for Call to Sink |
-| test.ps1:17:1:17:7 | Call to Sink | test.ps1:17:1:17:7 | pre-return value for Call to Sink |
-| test.ps1:17:1:17:7 | implicit unwrapping of Call to Sink | test.ps1:1:1:21:27 | return value for {...} |
-| test.ps1:17:1:17:7 | pre-return value for Call to Sink | test.ps1:17:1:17:7 | implicit unwrapping of Call to Sink |
-| test.ps1:17:1:17:7 | pre-return value for Call to Sink | test.ps1:17:1:17:7 | implicit unwrapping of Call to Sink |
+| test.ps1:17:1:17:7 | Call to Sink | test.ps1:1:1:21:27 | pre-return value for {...} |
+| test.ps1:17:1:17:7 | Call to Sink | test.ps1:1:1:21:27 | pre-return value for {...} |
| test.ps1:19:1:19:2 | f | test.ps1:21:25:21:26 | f |
| test.ps1:19:6:19:11 | Call to Source | test.ps1:19:1:19:2 | f |
-| test.ps1:21:1:21:27 | Call to Sink | test.ps1:21:1:21:27 | pre-return value for Call to Sink |
-| test.ps1:21:1:21:27 | Call to Sink | test.ps1:21:1:21:27 | pre-return value for Call to Sink |
-| test.ps1:21:1:21:27 | implicit unwrapping of Call to Sink | test.ps1:1:1:21:27 | return value for {...} |
-| test.ps1:21:1:21:27 | pre-return value for Call to Sink | test.ps1:21:1:21:27 | implicit unwrapping of Call to Sink |
-| test.ps1:21:1:21:27 | pre-return value for Call to Sink | test.ps1:21:1:21:27 | implicit unwrapping of Call to Sink |
+| test.ps1:21:1:21:27 | Call to Sink | test.ps1:1:1:21:27 | pre-return value for {...} |
+| test.ps1:21:1:21:27 | Call to Sink | test.ps1:1:1:21:27 | pre-return value for {...} |
| test.ps1:21:25:21:26 | f | test.ps1:21:6:21:27 | here is a string: $f |
diff --git a/powershell/ql/test/library-tests/dataflow/returns/test.expected b/powershell/ql/test/library-tests/dataflow/returns/test.expected
index ae3eefed04d1..cfd34b3abcdd 100644
--- a/powershell/ql/test/library-tests/dataflow/returns/test.expected
+++ b/powershell/ql/test/library-tests/dataflow/returns/test.expected
@@ -8,6 +8,16 @@ edges
| test.ps1:13:6:13:20 | Call to callSourceTwice [element] | test.ps1:16:6:16:7 | x [element] | provenance | |
| test.ps1:15:6:15:7 | x [element] | test.ps1:15:6:15:10 | ...[...] | provenance | |
| test.ps1:16:6:16:7 | x [element] | test.ps1:16:6:16:10 | ...[...] | provenance | |
+| test.ps1:19:12:19:21 | Call to Source | test.ps1:22:6:22:18 | Call to returnSource1 | provenance | |
+| test.ps1:22:6:22:18 | Call to returnSource1 | test.ps1:23:6:23:7 | x | provenance | |
+| test.ps1:26:10:26:19 | Call to Source | test.ps1:27:5:27:6 | x | provenance | |
+| test.ps1:27:5:27:6 | x | test.ps1:32:6:32:18 | Call to returnSource2 [element] | provenance | |
+| test.ps1:28:10:28:19 | Call to Source | test.ps1:29:12:29:13 | y | provenance | |
+| test.ps1:29:12:29:13 | y | test.ps1:32:6:32:18 | Call to returnSource2 [element] | provenance | |
+| test.ps1:32:6:32:18 | Call to returnSource2 [element] | test.ps1:33:6:33:7 | x [element] | provenance | |
+| test.ps1:32:6:32:18 | Call to returnSource2 [element] | test.ps1:34:6:34:7 | x [element] | provenance | |
+| test.ps1:33:6:33:7 | x [element] | test.ps1:33:6:33:10 | ...[...] | provenance | |
+| test.ps1:34:6:34:7 | x [element] | test.ps1:34:6:34:10 | ...[...] | provenance | |
| test.ps1:38:9:38:18 | Call to Source | test.ps1:42:6:42:21 | Call to callSourceInLoop [element] | provenance | |
| test.ps1:42:6:42:21 | Call to callSourceInLoop [element] | test.ps1:43:6:43:7 | x [element] | provenance | |
| test.ps1:42:6:42:21 | Call to callSourceInLoop [element] | test.ps1:44:6:44:7 | x [element] | provenance | |
@@ -24,6 +34,18 @@ nodes
| test.ps1:15:6:15:10 | ...[...] | semmle.label | ...[...] |
| test.ps1:16:6:16:7 | x [element] | semmle.label | x [element] |
| test.ps1:16:6:16:10 | ...[...] | semmle.label | ...[...] |
+| test.ps1:19:12:19:21 | Call to Source | semmle.label | Call to Source |
+| test.ps1:22:6:22:18 | Call to returnSource1 | semmle.label | Call to returnSource1 |
+| test.ps1:23:6:23:7 | x | semmle.label | x |
+| test.ps1:26:10:26:19 | Call to Source | semmle.label | Call to Source |
+| test.ps1:27:5:27:6 | x | semmle.label | x |
+| test.ps1:28:10:28:19 | Call to Source | semmle.label | Call to Source |
+| test.ps1:29:12:29:13 | y | semmle.label | y |
+| test.ps1:32:6:32:18 | Call to returnSource2 [element] | semmle.label | Call to returnSource2 [element] |
+| test.ps1:33:6:33:7 | x [element] | semmle.label | x [element] |
+| test.ps1:33:6:33:10 | ...[...] | semmle.label | ...[...] |
+| test.ps1:34:6:34:7 | x [element] | semmle.label | x [element] |
+| test.ps1:34:6:34:10 | ...[...] | semmle.label | ...[...] |
| test.ps1:38:9:38:18 | Call to Source | semmle.label | Call to Source |
| test.ps1:42:6:42:21 | Call to callSourceInLoop [element] | semmle.label | Call to callSourceInLoop [element] |
| test.ps1:43:6:43:7 | x [element] | semmle.label | x [element] |
@@ -32,16 +54,16 @@ nodes
| test.ps1:44:6:44:10 | ...[...] | semmle.label | ...[...] |
subpaths
testFailures
-| test.ps1:23:9:23:26 | # $ hasValueFlow=4 | Missing result: hasValueFlow=4 |
-| test.ps1:33:12:33:54 | # $ hasValueFlow=5 SPURIOUS: hasValueFlow=6 | Fixed spurious result: hasValueFlow=6 |
-| test.ps1:33:12:33:54 | # $ hasValueFlow=5 SPURIOUS: hasValueFlow=6 | Missing result: hasValueFlow=5 |
-| test.ps1:34:12:34:54 | # $ hasValueFlow=6 SPURIOUS: hasValueFlow=5 | Fixed spurious result: hasValueFlow=5 |
-| test.ps1:34:12:34:54 | # $ hasValueFlow=6 SPURIOUS: hasValueFlow=5 | Missing result: hasValueFlow=6 |
#select
| test.ps1:6:6:6:7 | x | test.ps1:2:5:2:14 | Call to Source | test.ps1:6:6:6:7 | x | $@ | test.ps1:2:5:2:14 | Call to Source | Call to Source |
| test.ps1:15:6:15:10 | ...[...] | test.ps1:9:5:9:14 | Call to Source | test.ps1:15:6:15:10 | ...[...] | $@ | test.ps1:9:5:9:14 | Call to Source | Call to Source |
| test.ps1:15:6:15:10 | ...[...] | test.ps1:10:5:10:14 | Call to Source | test.ps1:15:6:15:10 | ...[...] | $@ | test.ps1:10:5:10:14 | Call to Source | Call to Source |
| test.ps1:16:6:16:10 | ...[...] | test.ps1:9:5:9:14 | Call to Source | test.ps1:16:6:16:10 | ...[...] | $@ | test.ps1:9:5:9:14 | Call to Source | Call to Source |
| test.ps1:16:6:16:10 | ...[...] | test.ps1:10:5:10:14 | Call to Source | test.ps1:16:6:16:10 | ...[...] | $@ | test.ps1:10:5:10:14 | Call to Source | Call to Source |
+| test.ps1:23:6:23:7 | x | test.ps1:19:12:19:21 | Call to Source | test.ps1:23:6:23:7 | x | $@ | test.ps1:19:12:19:21 | Call to Source | Call to Source |
+| test.ps1:33:6:33:10 | ...[...] | test.ps1:26:10:26:19 | Call to Source | test.ps1:33:6:33:10 | ...[...] | $@ | test.ps1:26:10:26:19 | Call to Source | Call to Source |
+| test.ps1:33:6:33:10 | ...[...] | test.ps1:28:10:28:19 | Call to Source | test.ps1:33:6:33:10 | ...[...] | $@ | test.ps1:28:10:28:19 | Call to Source | Call to Source |
+| test.ps1:34:6:34:10 | ...[...] | test.ps1:26:10:26:19 | Call to Source | test.ps1:34:6:34:10 | ...[...] | $@ | test.ps1:26:10:26:19 | Call to Source | Call to Source |
+| test.ps1:34:6:34:10 | ...[...] | test.ps1:28:10:28:19 | Call to Source | test.ps1:34:6:34:10 | ...[...] | $@ | test.ps1:28:10:28:19 | Call to Source | Call to Source |
| test.ps1:43:6:43:10 | ...[...] | test.ps1:38:9:38:18 | Call to Source | test.ps1:43:6:43:10 | ...[...] | $@ | test.ps1:38:9:38:18 | Call to Source | Call to Source |
| test.ps1:44:6:44:10 | ...[...] | test.ps1:38:9:38:18 | Call to Source | test.ps1:44:6:44:10 | ...[...] | $@ | test.ps1:38:9:38:18 | Call to Source | Call to Source |