diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/CallExpr.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/CallExpr.qll index 96659f6cda24..c8dd8dbc9ad5 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/CallExpr.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/CallExpr.qll @@ -28,6 +28,10 @@ class CallExpr extends Expr, TCallExpr { /** Gets the qualifier of this call, if any. */ Expr getQualifier() { none() } + Expr getPipelineArgument() { + exists(Pipeline p, int i | this = p.getComponent(i + 1) and result = p.getComponent(i)) + } + final override string toString() { result = "Call to " + this.getName() } predicate isStatic() { none() } @@ -52,3 +56,11 @@ class Qualifier extends Expr { CallExpr getCall() { result = call } } + +class PipelineArgument extends Expr { + CallExpr call; + + PipelineArgument() { this = call.getPipelineArgument() } + + CallExpr getCall() { result = call } +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/ChildIndex.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/ChildIndex.qll index 01eefb967621..df29eb7f516d 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/ChildIndex.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/ChildIndex.qll @@ -36,14 +36,87 @@ newtype ChildIndex = // PipelineByPropertNameVar(Raw::PipelineByPropertyNameParameter p) or PipelineIteratorVar() or PipelineByPropertyNameIteratorVar(Raw::PipelineByPropertyNameParameter p) or - RealVar(string name) { name = variableNameInScope(_, _) } + RealVar(string name) { name = variableNameInScope(_, _) } or + ProcessBlockPipelineVarReadAccess() int synthPipelineParameterChildIndex(Raw::ScriptBlock sb) { + // If there is a parameter block, but no pipeline parameter exists(Raw::ParamBlock pb | pb = sb.getParamBlock() and not pb.getAParameter() instanceof Raw::PipelineParameter and result = pb.getNumParameters() ) + or + // There is no parameter block + not exists(sb.getParamBlock()) and + exists(Raw::FunctionDefinitionStmt funDefStmt | + funDefStmt.getBody() = sb and + result = funDefStmt.getNumParameters() + ) +} + +string stringOfChildIndex(ChildIndex i) { + exists(Raw::ChildIndex rawIndex | + i = RawChildIndex(rawIndex) and + result = Raw::stringOfChildIndex(rawIndex) + ) + or + i = ParamPipeline() and + result = "ParamPipeline" + or + i = ParamDefaultVal() and + result = "ParamDefaultVal" + or + i = FunParam(_) and + result = "FunParam" + or + i = CmdArgument(_) and + result = "CmdArgument" + or + i = ExprStmtExpr() and + result = "ExprStmtExpr" + or + i = MethodBody() and + result = "MethodBody" + or + i = ThisVar() and + result = "ThisVar" + or + i = PipelineParamVar() and + result = "PipelineParamVar" + or + i = PipelineIteratorVar() and + result = "PipelineIteratorVar" + or + i = PipelineByPropertyNameIteratorVar(_) and + result = "PipelineByPropertyNameIteratorVar" + or + i = RealVar(_) and + result = "RealVar" + or + i = ExprRedirection(_) and + result = "ExprRedirection" + or + i = FunDefFun() and + result = "FunDefFun" + or + i = TypeDefType() and + result = "TypeDefType" + or + i = TypeMember(_) and + result = "TypeMember" + or + i = ScriptBlockAttr(_) and + result = "ScriptBlockAttr" + or + i = ParamAttr(_) and + result = "ParamAttr" + or + i = FunctionBody() and + result = "FunctionBody" + or + i = ProcessBlockPipelineVarReadAccess() and + result = "ProcessBlockPipelineVarReadAccess" } Raw::ChildIndex toRawChildIndex(ChildIndex i) { i = RawChildIndex(result) } @@ -265,3 +338,5 @@ ChildIndex usingExprExpr() { result = RawChildIndex(Raw::UsingExprExpr()) } ChildIndex whileStmtCond() { result = RawChildIndex(Raw::WhileStmtCond()) } ChildIndex whileStmtBody() { result = RawChildIndex(Raw::WhileStmtBody()) } + +ChildIndex processBlockPipelineVarReadAccess() { result = ProcessBlockPipelineVarReadAccess() } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/NamedBlock.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/NamedBlock.qll index a23106fff648..10da368db65e 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/NamedBlock.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/NamedBlock.qll @@ -50,6 +50,14 @@ class ProcessBlock extends NamedBlock { result = this.getEnclosingFunction().getPipelineParameter() } + PipelineIteratorVariable getPipelineIteratorVariable() { + result = TVariableSynth(getRawAst(this), PipelineIteratorVar()) + } + + VarReadAccess getPipelineParameterAccess() { + synthChild(getRawAst(this), processBlockPipelineVarReadAccess(), result) + } + PipelineByPropertyNameParameter getAPipelineByPropertyNameParameter() { result = scriptBlock.getEnclosingFunction().getAParameter() } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ChildIndex.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ChildIndex.qll index 8da1c5e2fb22..b78fb4e16442 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ChildIndex.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/ChildIndex.qll @@ -99,3 +99,201 @@ newtype ChildIndex = UsingExprExpr() or WhileStmtCond() or WhileStmtBody() + +string stringOfChildIndex(ChildIndex i) { + i = ArrayExprStmtBlock() and result = "ArrayExprStmtBlock" + or + i = ArrayLiteralExpr(_) and result = "ArrayLiteralExpr" + or + i = AssignStmtLeftHandSide() and result = "AssignStmtLeftHandSide" + or + i = AssignStmtRightHandSide() and result = "AssignStmtRightHandSide" + or + i = AttributeNamedArg(_) and result = "AttributeNamedArg" + or + i = AttributePosArg(_) and result = "AttributePosArg" + or + i = AttributedExprExpr() and result = "AttributedExprExpr" + or + i = AttributedExprAttr() and result = "AttributedExprAttr" + or + i = BinaryExprLeft() and result = "BinaryExprLeft" + or + i = BinaryExprRight() and result = "BinaryExprRight" + or + i = CatchClauseBody() and result = "CatchClauseBody" + or + i = CatchClauseType(_) and result = "CatchClauseType" + or + i = CmdElement_(_) and result = "CmdElement" + or + i = CmdCallee() and result = "CmdCallee" + or + i = CmdRedirection(_) and result = "CmdRedirection" + or + i = CmdExprExpr() and result = "CmdExprExpr" + or + i = ConfigurationName() and result = "ConfigurationName" + or + i = ConfigurationBody() and result = "ConfigurationBody" + or + i = ConvertExprExpr() and result = "ConvertExprExpr" + or + i = ConvertExprType() and result = "ConvertExprType" + or + i = ConvertExprAttr() and result = "ConvertExprAttr" + or + i = DataStmtBody() and result = "DataStmtBody" + or + i = DataStmtCmdAllowed(_) and result = "DataStmtCmdAllowed" + or + i = DoUntilStmtCond() and result = "DoUntilStmtCond" + or + i = DoUntilStmtBody() and result = "DoUntilStmtBody" + or + i = DoWhileStmtCond() and result = "DoWhileStmtCond" + or + i = DoWhileStmtBody() and result = "DoWhileStmtBody" + or + i = DynamicStmtName() and result = "DynamicStmtName" + or + i = DynamicStmtBody() and result = "DynamicStmtBody" + or + i = ExitStmtPipeline() and result = "ExitStmtPipeline" + or + i = ExpandableStringExprExpr(_) and result = "ExpandableStringExprExpr" + or + i = ForEachStmtVar() and result = "ForEachStmtVar" + or + i = ForEachStmtIter() and result = "ForEachStmtIter" + or + i = ForEachStmtBody() and result = "ForEachStmtBody" + or + i = ForStmtInit() and result = "ForStmtInit" + or + i = ForStmtCond() and result = "ForStmtCond" + or + i = ForStmtIter() and result = "ForStmtIter" + or + i = ForStmtBody() and result = "ForStmtBody" + or + i = FunDefStmtBody() and result = "FunDefStmtBody" + or + i = FunDefStmtParam(_) and result = "FunDefStmtParam" + or + i = GotoStmtLabel() and result = "GotoStmtLabel" + or + i = HashTableExprKey(_) and result = "HashTableExprKey" + or + i = HashTableExprStmt(_) and result = "HashTableExprStmt" + or + i = IfStmtElse() and result = "IfStmtElse" + or + i = IfStmtCond(_) and result = "IfStmtCond" + or + i = IfStmtThen(_) and result = "IfStmtThen" + or + i = IndexExprIndex() and result = "IndexExprIndex" + or + i = IndexExprBase() and result = "IndexExprBase" + or + i = InvokeMemberExprQual() and result = "InvokeMemberExprQual" + or + i = InvokeMemberExprCallee() and result = "InvokeMemberExprCallee" + or + i = InvokeMemberExprArg(_) and result = "InvokeMemberExprArg" + or + i = MemberExprQual() and result = "MemberExprQual" + or + i = MemberExprMember() and result = "MemberExprMember" + or + i = NamedAttributeArgVal() and result = "NamedAttributeArgVal" + or + i = MemberAttr(_) and result = "MemberAttr" + or + i = MemberTypeConstraint() and result = "MemberTypeConstraint" + or + i = NamedBlockStmt(_) and result = "NamedBlockStmt" + or + i = NamedBlockTrap(_) and result = "NamedBlockTrap" + or + i = ParamBlockAttr(_) and result = "ParamBlockAttr" + or + i = ParamBlockParam(_) and result = "ParamBlockParam" + or + i = ParamAttr(_) and result = "ParamAttr" + or + i = ParamDefaultVal() and result = "ParamDefaultVal" + or + i = ParenExprExpr() and result = "ParenExprExpr" + or + i = PipelineComp(_) and result = "PipelineComp" + or + i = PipelineChainLeft() and result = "PipelineChainLeft" + or + i = PipelineChainRight() and result = "PipelineChainRight" + or + i = ReturnStmtPipeline() and result = "ReturnStmtPipeline" + or + i = RedirectionExpr() and result = "RedirectionExpr" + or + i = ScriptBlockUsing(_) and result = "ScriptBlockUsing" + or + i = ScriptBlockParamBlock() and result = "ScriptBlockParamBlock" + or + i = ScriptBlockBeginBlock() and result = "ScriptBlockBeginBlock" + or + i = ScriptBlockCleanBlock() and result = "ScriptBlockCleanBlock" + or + i = ScriptBlockDynParamBlock() and result = "ScriptBlockDynParamBlock" + or + i = ScriptBlockEndBlock() and result = "ScriptBlockEndBlock" + or + i = ScriptBlockProcessBlock() and result = "ScriptBlockProcessBlock" + or + i = ScriptBlockExprBody() and result = "ScriptBlockExprBody" + or + i = StmtBlockStmt(_) and result = "StmtBlockStmt" + or + i = StmtBlockTrapStmt(_) and result = "StmtBlockTrapStmt" + or + i = ExpandableSubExprExpr() and result = "ExpandableSubExprExpr" + or + i = SwitchStmtCond() and result = "SwitchStmtCond" + or + i = SwitchStmtDefault() and result = "SwitchStmtDefault" + or + i = SwitchStmtCase(_) and result = "SwitchStmtCase" + or + i = SwitchStmtPat(_) and result = "SwitchStmtPat" + or + i = CondExprCond() and result = "CondExprCond" + or + i = CondExprTrue() and result = "CondExprTrue" + or + i = CondExprFalse() and result = "CondExprFalse" + or + i = ThrowStmtPipeline() and result = "ThrowStmtPipeline" + or + i = TryStmtBody() and result = "TryStmtBody" + or + i = TryStmtCatchClause(_) and result = "TryStmtCatchClause" + or + i = TryStmtFinally() and result = "TryStmtFinally" + or + i = TypeStmtMember(_) and result = "TypeStmtMember" + or + i = TypeStmtBaseType(_) and result = "TypeStmtBaseType" + or + i = TrapStmtBody() and result = "TrapStmtBody" + or + i = TrapStmtTypeConstraint() and result = "TrapStmtTypeConstraint" + or + i = UnaryExprOp() and result = "UnaryExprOp" + or + i = UsingExprExpr() and result = "UsingExprExpr" + or + i = WhileStmtCond() and result = "WhileStmtCond" + or + i = WhileStmtBody() and result = "WhileStmtBody" +} diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Function.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Function.qll index 6b303fb36be5..d1e9a572a02b 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Function.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Function.qll @@ -11,6 +11,8 @@ class FunctionDefinitionStmt extends @function_definition, Stmt { Parameter getAParameter() { result = this.getParameter(_) } + int getNumParameters() { result = count(this.getParameter(_)) } + override Ast getChild(ChildIndex i) { i = FunDefStmtBody() and result = this.getBody() or diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Parameter.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Parameter.qll index 32669d0141ea..08ee3f9e2091 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Parameter.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Parameter.qll @@ -35,7 +35,7 @@ class PipelineParameter extends Parameter { this.getAnAttribute().(Attribute).getANamedArgument() = namedAttribute and namedAttribute.getName().toLowerCase() = "valuefrompipeline" | - namedAttribute.getValue().(ConstExpr).getValue().getValue() = "true" + namedAttribute.getValue().(ConstExpr).getValue().getValue().toLowerCase() = "true" or not exists(namedAttribute.getValue().(ConstExpr).getValue().getValue()) ) @@ -50,7 +50,7 @@ class PipelineByPropertyNameParameter extends Parameter { this.getAnAttribute().(Attribute).getANamedArgument() = namedAttribute and namedAttribute.getName().toLowerCase() = "valuefrompipelinebypropertyname" | - namedAttribute.getValue().(ConstExpr).getValue().getValue() = "true" + namedAttribute.getValue().(ConstExpr).getValue().getValue().toLowerCase() = "true" or not exists(namedAttribute.getValue().(ConstExpr).getValue().getValue()) ) diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/VariableExpression.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/VariableExpression.qll index 00bc726699c5..c3088de4444d 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/VariableExpression.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/VariableExpression.qll @@ -24,6 +24,10 @@ class VarAccess extends @variable_expression, Expr { boolean isVariable() { variable_expression(this, _, _, _, _, _, _, _, _, _, result, _) } boolean isDriveQualified() { variable_expression(this, _, _, _, _, _, _, _, _, _, _, result) } + + predicate isReadAccess() { not this.isWriteAccess() } + + predicate isWriteAccess() { any(AssignStmt assign).getLeftHandSide() = this } } class ThisAccess extends VarAccess { 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 d58b2eb11b04..30356666b25f 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/Synthesis.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Synthesis.qll @@ -587,6 +587,57 @@ private module CmdArguments { * Synthesize literals from known constant strings. */ private module LiteralSynth { + pragma[nomagic] + private predicate assignmentHasLocation( + Raw::Scope scope, string name, File file, int startLine, int startColumn + ) { + Raw::isAutomaticVariableAccess(_, name) and + exists(Raw::Ast n, Location loc | + scopeAssigns(scope, name, n) and + loc = n.getLocation() and + file = loc.getFile() and + startLine = loc.getStartLine() and + startColumn = loc.getStartColumn() + ) + } + + pragma[nomagic] + private predicate varAccessHasLocation( + Raw::VarAccess va, File file, int startLine, int startColumn + ) { + exists(Location loc | + loc = va.getLocation() and + loc.getFile() = file and + loc.getStartLine() = startLine and + loc.getStartColumn() = startColumn + ) + } + + /** + * Holds if `va` is an access to the automatic variable named `name`. + * + * Unlike `Raw::isAutomaticVariableAccess`, this predicate also checks for + * shadowing. + */ + private predicate isAutomaticVariableAccess(Raw::VarAccess va, string name) { + Raw::isAutomaticVariableAccess(va, name) and + exists(Raw::Scope scope, File file, int startLine, int startColumn | + scope = Raw::scopeOf(va) and + varAccessHasLocation(va, file, startLine, startColumn) + | + // If it's a read then make sure there is no assignment precedeeding it + va.isReadAccess() and + not exists(int assignStartLine, int assignStartCoumn | + assignmentHasLocation(scope, name, file, assignStartLine, assignStartCoumn) + | + assignStartLine < startLine + or + assignStartLine = startLine and + assignStartCoumn < startColumn + ) + ) + } + private class LiteralSynth extends Synthesis { final override predicate isRelevant(Raw::Ast a) { exists(Raw::VarAccess va | a = va | @@ -598,7 +649,7 @@ private module LiteralSynth { or Raw::isEnvVariableAccess(va, _) or - Raw::isAutomaticVariableAccess(va, _) + isAutomaticVariableAccess(va, _) ) } @@ -628,7 +679,7 @@ private module LiteralSynth { Raw::isEnvVariableAccess(va, s) and child = SynthChild(EnvVariableKind(s)) or - Raw::isAutomaticVariableAccess(va, s) and + isAutomaticVariableAccess(va, s) and child = SynthChild(AutomaticVariableKind(s)) ) } @@ -710,12 +761,25 @@ private module IteratorAccessSynth { } private class IteratorAccessSynth extends Synthesis { + final override predicate isRelevant(Raw::Ast a) { + exists(Raw::ProcessBlock pb, Raw::VarAccess va | + va = a and + pb = va.getParent+() + | + va.getUserPath() = "_" + or + va.getUserPath().toLowerCase() = + pb.getScriptBlock().getParamBlock().getPipelineParameter().getName().toLowerCase() + ) + } + private predicate expr(Raw::Ast rawParent, ChildIndex i, Raw::VarAccess va, Child child) { rawParent.getChild(toRawChildIndex(i)) = va and child = SynthChild(VarAccessSynthKind(this.varAccess(va))) } private predicate stmt(Raw::Ast rawParent, ChildIndex i, Raw::CmdExpr cmdExpr, Child child) { + exists(this.varAccess(cmdExpr.getExpr())) and rawParent.getChild(toRawChildIndex(i)) = cmdExpr and not mustHaveExprChild(rawParent, cmdExpr) and child = SynthChild(ExprStmtKind()) @@ -793,3 +857,31 @@ private module IteratorAccessSynth { } } } + +private module PipelineAccess { + private class PipelineAccess extends Synthesis { + final override predicate child(Raw::Ast parent, ChildIndex i, Child child) { + exists(Raw::ProcessBlock pb | parent = pb | + i = processBlockPipelineVarReadAccess() and + exists(PipelineVariable pipelineVar | + pipelineVar = TVariableSynth(pb.getScriptBlock(), PipelineParamVar()) and + child = SynthChild(VarAccessSynthKind(pipelineVar)) + ) + ) + } + + final override Location getLocation(Ast n) { + exists(ProcessBlock pb | + pb.getPipelineParameterAccess() = n and + result = pb.getLocation() + ) + } + + final override predicate getAnAccess(VarAccessSynth va, Variable v) { + exists(ProcessBlock pb | + pb.getPipelineParameterAccess() = va and + v = pb.getPipelineParameter() + ) + } + } +} 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 ee7c58d4f656..f62e71e58b91 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/TAst.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/TAst.qll @@ -17,8 +17,7 @@ string variableNameInScope(Raw::Ast n, Scope::Range scope) { not scope.getAParameter().(Raw::PipelineByPropertyNameParameter).getName() = result and not result.toLowerCase() = ["_", "this", "false", "true", "null"] and not parameter(_, n, _, _) and - not Raw::isEnvVariableAccess(n, _) and - not Raw::isAutomaticVariableAccess(n, _) + not Raw::isEnvVariableAccess(n, _) or any(Synthesis s).explicitAssignment(n, result, _) or @@ -26,7 +25,7 @@ string variableNameInScope(Raw::Ast n, Scope::Range scope) { ) } -private predicate scopeAssigns(Scope::Range scope, string name, Raw::Ast n) { +predicate scopeAssigns(Scope::Range scope, string name, Raw::Ast n) { (explicitAssignment(n, _) or implicitAssignment(n)) and name = variableNameInScope(n, scope) } diff --git a/powershell/ql/lib/semmle/code/powershell/controlflow/CfgNodes.qll b/powershell/ql/lib/semmle/code/powershell/controlflow/CfgNodes.qll index ef07239ab51e..c8126a68ab97 100644 --- a/powershell/ql/lib/semmle/code/powershell/controlflow/CfgNodes.qll +++ b/powershell/ql/lib/semmle/code/powershell/controlflow/CfgNodes.qll @@ -272,7 +272,13 @@ class NamedBlockCfgNode extends AstCfgNode { StmtNodes::TrapStmtCfgNode getATrapStmt() { result = this.getTrapStmt(_) } } -private class ProcessBlockChildMapping extends NamedBlockChildMapping, ProcessBlock { } +private class ProcessBlockChildMapping extends NamedBlockChildMapping, ProcessBlock { + override predicate relevantChild(Ast child) { + super.relevantChild(child) + or + child = super.getPipelineParameterAccess() + } +} class ProcessBlockCfgNode extends NamedBlockCfgNode { override string getAPrimaryQlClass() { result = "ProcessBlockCfgNode" } @@ -282,6 +288,18 @@ class ProcessBlockCfgNode extends NamedBlockCfgNode { override ProcessBlock getBlock() { result = block } ScriptBlockCfgNode getScriptBlock() { result.getProcessBlock() = this } + + PipelineVariable getPipelineVariable() { + result.getScriptBlock() = this.getScriptBlock().getAstNode() + } + + ExprNodes::VarReadAccessCfgNode getPipelineVariableAccess() { + block.hasCfgChild(block.getPipelineParameterAccess(), this, result) + } + + PipelineIteratorVariable getPipelineIteratorVariable() { + result.getProcessBlock().getScriptBlock() = this.getScriptBlock().getAstNode() + } } private class CatchClauseChildMapping extends NonExprChildMapping, CatchClause { @@ -520,6 +538,13 @@ module ExprNodes { ExprCfgNode getCallee() { e.hasCfgChild(e.getCallee(), this, result) } + ExprCfgNode getPipelineArgument() { + exists(ExprNodes::PipelineCfgNode pipeline, int i | + pipeline.getComponent(i + 1) = this and + result = pipeline.getComponent(i) + ) + } + predicate isStatic() { this.getExpr().isStatic() } } @@ -984,6 +1009,12 @@ module ExprNodes { CallExprCfgNode getCall() { result.getQualifier() = this } } + class PipelineArgumentCfgNode extends ExprCfgNode { + override PipelineArgument e; + + CallExprCfgNode getCall() { result.getPipelineArgument() = this } + } + private class EnvVariableChildMapping extends ExprChildMapping, EnvVariable { override predicate relevantChild(Ast child) { none() } } 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 f67a748068e4..d28828481f56 100644 --- a/powershell/ql/lib/semmle/code/powershell/controlflow/internal/ControlFlowGraphImpl.qll +++ b/powershell/ql/lib/semmle/code/powershell/controlflow/internal/ControlFlowGraphImpl.qll @@ -193,21 +193,21 @@ module Trees { or exists(int i | last(super.getParameter(i), pred, c) and - completionIsNormal(c) and + completionIsNormal(c) + | first(super.getParameter(i + 1), succ) - ) - or - last(super.getParameter(super.getNumberOfParameters() - 1), pred, c) and - completionIsNormal(c) and - ( - first(super.getBeginBlock(), succ) - or - not exists(super.getBeginBlock()) and - first(super.getProcessBlock(), succ) or - not exists(super.getBeginBlock()) and - not exists(super.getProcessBlock()) and - first(super.getEndBlock(), succ) + not exists(super.getParameter(i + 1)) and + ( + first(super.getBeginBlock(), succ) + or + not exists(super.getBeginBlock()) and + first(super.getProcessBlock(), succ) + or + not exists(super.getBeginBlock()) and + not exists(super.getProcessBlock()) and + first(super.getEndBlock(), succ) + ) ) or last(super.getBeginBlock(), pred, c) and @@ -292,9 +292,55 @@ module Trees { final override predicate succEntry(Ast n, Completion c) { n = this and completionIsSimple(c) } } - class NamedBlockTree extends StandardPreOrderTree instanceof NamedBlock { - // TODO: Handle trap - override AstNode getChildNode(int i) { result = super.getStmt(i) } + abstract class NamedBlockTreeBase extends ControlFlowTree instanceof NamedBlock { + final override predicate last(Ast last, Completion c) { + exists(int i | last(super.getStmt(i), last, c) | + completionIsNormal(c) and + not exists(super.getStmt(i + 1)) + or + not completionIsNormal(c) + ) + or + not exists(super.getAStmt()) and + completionIsSimple(c) and + last = this + } + + override predicate succ(Ast pred, Ast succ, Completion c) { + pred = this and + completionIsSimple(c) and + first(super.getStmt(0), succ) + or + exists(int i | + last(super.getStmt(i), pred, c) and + completionIsNormal(c) and + first(super.getStmt(i + 1), succ) + ) + } + + override predicate propagatesAbnormal(Ast child) { child = super.getAStmt() } + } + + class NamedBlockTree extends NamedBlockTreeBase instanceof NamedBlock { + NamedBlockTree() { not this instanceof ProcessBlock } + + final override predicate first(Ast first) { first = this } + + final override predicate propagatesAbnormal(Ast child) { super.propagatesAbnormal(child) } + } + + class ProcessBlockTree extends NamedBlockTreeBase instanceof ProcessBlock { + final override predicate first(Ast first) { first = super.getPipelineParameterAccess() } + + final override predicate succ(Ast pred, Ast succ, Completion c) { + this.first(pred) and + completionIsSimple(c) and + succ = this + or + super.succ(pred, succ, c) + } + + final override predicate propagatesAbnormal(Ast child) { super.propagatesAbnormal(child) } } class AssignStmtTree extends StandardPreOrderTree instanceof AssignStmt { 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 46380b0a3e1b..d5bfa5c7a726 100644 --- a/powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowPrivate.qll +++ b/powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowPrivate.qll @@ -64,15 +64,24 @@ module SsaFlow { result = TNormalParameterNode(p.asParameter()) or result = TThisParameterNode(p.asThis()) + or + result = TPipelineParameterNode(p.asPipelineParameter()) } + /** Gets the SSA node corresponding to the PowerShell node `n`. */ Impl::Node asNode(Node n) { n = TSsaNode(result) or result.(Impl::ExprNode).getExpr() = n.asExpr() or - result.(Impl::ExprNode).getExpr() = - [n.(ProcessNode).getProcessBlock(), n.(ProcessPropertyByNameNode).getProcessBlock()] + exists(CfgNodes::ProcessBlockCfgNode pb, BasicBlock bb, int i | + n.(ProcessNode).getProcessBlock() = pb and + bb.getNode(i) = pb and + result + .(Impl::SsaDefinitionNode) + .getDefinition() + .definesAt(pb.getPipelineIteratorVariable(), bb, i) + ) or result.(Impl::ExprPostUpdateNode).getExpr() = n.(PostUpdateNode).getPreUpdateNode().asExpr() or @@ -115,7 +124,7 @@ module LocalFlow { exists(CfgNodes::ExprCfgNode e | e = nodeFrom.(AstNode).getCfgNode() and isReturned(e) and - e.getScope() = nodeTo.(PreReturNodeImpl).getCfgScope() + e.getScope() = nodeTo.(PreReturnNodeImpl).getCfgScope() ) or exists(CfgNode cfgNode | @@ -135,6 +144,14 @@ module LocalFlow { not blockMayReturnMultipleValues(scriptBlock) and nodeTo.(ReturnNodeImpl).getCfgScope() = scriptBlock.getAstNode() ) + or + exists(CfgNodes::ExprNodes::PipelineArgumentCfgNode e | nodeFrom.asExpr() = e | + // If we are not already tracking as element content + nodeTo = TPrePipelineArgumentNode(e) + or + // If we are already tracking an element content + nodeTo = TPipelineArgumentNode(e) + ) } predicate flowSummaryLocalStep( @@ -180,7 +197,9 @@ private module Cached { TNormalParameterNode(SsaImpl::NormalParameter p) or TThisParameterNode(Method m) or TPipelineByPropertyNameParameterNode(PipelineByPropertyNameParameter p) or - TPipelineParamaterNode(PipelineParameter p) or + TPipelineParameterNode(PipelineParameter p) or + TPrePipelineArgumentNode(CfgNodes::ExprNodes::PipelineArgumentCfgNode n) or + TPipelineArgumentNode(CfgNodes::ExprNodes::PipelineArgumentCfgNode n) or TExprPostUpdateNode(CfgNodes::ExprCfgNode n) { n instanceof CfgNodes::ExprNodes::ArgumentCfgNode or @@ -201,7 +220,7 @@ private module Cached { blockMayReturnMultipleValues(scriptBlock) } or TReturnNodeImpl(CfgScope scope) or - TProcessNode(ProcessBlock process) or + TProcessNode(CfgNodes::ProcessBlockCfgNode process) or TProcessPropertyByNameNode(PipelineByPropertyNameIteratorVariable iter) { isProcessPropertyByNameNode(iter, _) } or @@ -578,10 +597,10 @@ private module ParameterNodes { override string toStringImpl() { result = "this" } } - class PipelineParamaterNode extends ParameterNodeImpl, TPipelineParamaterNode { + class PipelineParameterNode extends ParameterNodeImpl, TPipelineParameterNode { private PipelineParameter parameter; - PipelineParamaterNode() { this = TPipelineParamaterNode(parameter) } + PipelineParameterNode() { this = TPipelineParameterNode(parameter) } override PipelineParameter getParameter() { result = parameter } @@ -671,6 +690,22 @@ abstract class ArgumentNode extends Node { final DataFlowCall getCall() { this.argumentOf(result, _) } } +class PrePipelineArgumentNodeImpl extends NodeImpl, TPrePipelineArgumentNode { + CfgNodes::ExprNodes::PipelineArgumentCfgNode e; + + PrePipelineArgumentNodeImpl() { this = TPrePipelineArgumentNode(e) } + + final override CfgScope getCfgScope() { result = e.getScope() } + + final override Location getLocationImpl() { result = e.getLocation() } + + final override string toStringImpl() { result = "[pre pipeline] " + e.toString() } + + final override predicate nodeIsHidden() { any() } + + CfgNodes::ExprNodes::PipelineArgumentCfgNode getPipelineArgument() { result = e } +} + module ArgumentNodes { class ExplicitArgumentNode extends ArgumentNode { CfgNodes::ExprNodes::ArgumentCfgNode arg; @@ -714,18 +749,23 @@ module ArgumentNodes { } } - private predicate isPipelineInput(CfgNodes::ExprCfgNode input, CfgNodes::ExprCfgNode consumer) { - exists(CfgNodes::ExprNodes::PipelineCfgNode pipeline, int i | - input = pipeline.getComponent(i) and - consumer = pipeline.getComponent(i + 1) - ) - } + class PipelineArgumentNodeImpl extends NodeImpl, TPipelineArgumentNode { + CfgNodes::ExprNodes::PipelineArgumentCfgNode e; - class PipelineArgumentNode extends ArgumentNode, ExprNode { - CfgNodes::ExprCfgNode consumer; + PipelineArgumentNodeImpl() { this = TPipelineArgumentNode(e) } - PipelineArgumentNode() { isPipelineInput(this.getExprNode(), consumer) } + final override CfgScope getCfgScope() { result = e.getScope() } + final override Location getLocationImpl() { result = e.getLocation() } + + final override string toStringImpl() { result = e.toString() } + + final override predicate nodeIsHidden() { none() } + + CfgNodes::ExprNodes::PipelineArgumentCfgNode getPipelineArgument() { result = e } + } + + class PipelineArgumentNode extends ArgumentNode instanceof PipelineArgumentNodeImpl { override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) { this.sourceArgumentOf(call.asCall(), pos) } @@ -733,7 +773,7 @@ module ArgumentNodes { override predicate sourceArgumentOf( CfgNodes::ExprNodes::CallExprCfgNode call, ArgumentPosition pos ) { - call = consumer and + call = super.getPipelineArgument().getCall() and pos.isPipeline() } } @@ -921,6 +961,12 @@ predicate storeStep(Node node1, ContentSet c, Node node2) { node2.(ReturnNodeImpl).getCfgScope() = cfgNode.getScope() ) or + c.isAnyElement() and + exists(CfgNodes::ExprNodes::PipelineArgumentCfgNode arg | + node1 = TPrePipelineArgumentNode(arg) and + node2 = TPipelineArgumentNode(arg) + ) + or FlowSummaryImpl::Private::Steps::summaryStoreStep(node1.(FlowSummaryNode).getSummaryNode(), c, node2.(FlowSummaryNode).getSummaryNode()) } @@ -957,14 +1003,9 @@ predicate readStep(Node node1, ContentSet c, Node node2) { ) or c.isAnyElement() and - exists(SsaImpl::DefinitionExt def, ProcessNode processNode, Variable iterator | - processNode = node1 and iterator = def.getSourceVariable() - | - processNode.getIteratorVariable() = iterator and - SsaImpl::firstRead(def, node2.asExpr()) - or - processNode.getPropertyNameIteratorVariable() = iterator and - node2 = TProcessPropertyByNameNode(def.getSourceVariable()) + exists(CfgNodes::ProcessBlockCfgNode processBlock | + processBlock.getPipelineVariableAccess() = node1.asExpr() and + node2 = TProcessNode(processBlock) ) or exists( @@ -1001,6 +1042,9 @@ predicate clearsContent(Node n, ContentSet c) { or n = TPreReturnNodeImpl(_, false) and c.isAnyElement() + or + n instanceof PrePipelineArgumentNodeImpl and + c.isAnyElement() } /** @@ -1016,7 +1060,7 @@ predicate expectsContent(Node n, ContentSet c) { n = TImplicitWrapNode(_, false) and c.isSingleton(any(Content::UnknownElementContent ec)) or - n instanceof ProcessNode and + n instanceof PipelineArgumentNode and c.isAnyElement() } @@ -1115,11 +1159,11 @@ private class ImplicitWrapNode extends TImplicitWrapNode, NodeImpl { * A node that represents the return value before any array-unwrapping * has been performed. */ -private class PreReturNodeImpl extends TPreReturnNodeImpl, NodeImpl { +private class PreReturnNodeImpl extends TPreReturnNodeImpl, NodeImpl { private CfgNodes::ScriptBlockCfgNode n; private boolean isArray; - PreReturNodeImpl() { this = TPreReturnNodeImpl(n, isArray) } + PreReturnNodeImpl() { this = TPreReturnNodeImpl(n, isArray) } CfgNodes::AstCfgNode getScriptBlock() { result = n } @@ -1148,11 +1192,11 @@ private class ReturnNodeImpl extends TReturnNodeImpl, NodeImpl { } private class ProcessNode extends TProcessNode, NodeImpl { - ProcessBlock process; + CfgNodes::ProcessBlockCfgNode process; ProcessNode() { this = TProcessNode(process) } - override CfgScope getCfgScope() { result = process.getEnclosingScope() } + override CfgScope getCfgScope() { result = process.getScope() } override Location getLocationImpl() { result = process.getLocation() } @@ -1160,13 +1204,11 @@ private class ProcessNode extends TProcessNode, NodeImpl { override predicate nodeIsHidden() { any() } - PipelineIteratorVariable getIteratorVariable() { result.getProcessBlock() = process } - - PipelineByPropertyNameIteratorVariable getPropertyNameIteratorVariable() { - result.getProcessBlock() = process + PipelineIteratorVariable getPipelineIteratorVariable() { + result = process.getPipelineIteratorVariable() } - CfgNodes::ProcessBlockCfgNode getProcessBlock() { result.getAstNode() = process } + CfgNodes::ProcessBlockCfgNode getProcessBlock() { result = process } } private class ProcessPropertyByNameNode extends TProcessPropertyByNameNode, NodeImpl { 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 a1e34e36af34..507ebe7f849a 100644 --- a/powershell/ql/lib/semmle/code/powershell/dataflow/internal/SsaImpl.qll +++ b/powershell/ql/lib/semmle/code/powershell/dataflow/internal/SsaImpl.qll @@ -30,6 +30,13 @@ module SsaInput implements SsaImplCommon::InputSig { uninitializedWrite(bb, i, v) or variableWriteActual(bb, i, v, _) + or + exists(ProcessBlockCfgNode processBlock | + bb.getNode(i) = processBlock and + processBlock.getPipelineIteratorVariable() = v + ) + or + parameterWrite(bb, i, v) ) and certain = true } @@ -54,7 +61,12 @@ module Consistency = Impl::Consistency; /** Holds if `v` is uninitialized at index `i` in entry block `bb`. */ predicate uninitializedWrite(Cfg::EntryBasicBlock bb, int i, Variable v) { - bb.getNode(i).getAstNode() = v + i = -1 and + bb.getANode().getAstNode() = v +} + +predicate parameterWrite(Cfg::EntryBasicBlock bb, int i, Parameter p) { + bb.getNode(i).getAstNode() = p } /** Holds if `v` is read at index `i` in basic block `bb`. */ @@ -288,7 +300,8 @@ class NormalParameter extends Parameter { private newtype TParameterExt = TNormalParameter(NormalParameter p) or - TThisMethodParameter(Method m) + TThisMethodParameter(Method m) or + TPipelineParameter(PipelineParameter p) /** A normal parameter or an implicit `this` parameter. */ class ParameterExt extends TParameterExt { @@ -296,16 +309,30 @@ class ParameterExt extends TParameterExt { Method asThis() { this = TThisMethodParameter(result) } + PipelineParameter asPipelineParameter() { this = TPipelineParameter(result) } + predicate isInitializedBy(WriteDefinition def) { def = getParameterDef(this.asParameter()) or + def = getParameterDef(this.asPipelineParameter()) + or def.(Ssa::ThisDefinition).getSourceVariable().getDeclaringScope() = this.asThis().getBody() } - string toString() { result = [this.asParameter().toString(), this.asThis().toString()] } + string toString() { + result = + [ + this.asParameter().toString(), this.asThis().toString(), + this.asPipelineParameter().toString() + ] + } Location getLocation() { - result = [this.asParameter().getLocation(), this.asThis().getLocation()] + result = + [ + this.asParameter().getLocation(), this.asThis().getLocation(), + this.asPipelineParameter().getLocation() + ] } } diff --git a/powershell/ql/test/library-tests/ast/Statements/statements.expected b/powershell/ql/test/library-tests/ast/Statements/statements.expected index f8994f476941..6f85c09bdd1b 100644 --- a/powershell/ql/test/library-tests/ast/Statements/statements.expected +++ b/powershell/ql/test/library-tests/ast/Statements/statements.expected @@ -22,4 +22,4 @@ | Try.ps1:11:9:13:1 | {...} | | Try.ps1:12:5:12:36 | [Stmt] The finally block is executed. | | UseProcessBlockForPipelineCommand.ps1:1:1:11:1 | def of Get-Number | -| UseProcessBlockForPipelineCommand.ps1:10:5:10:11 | [Stmt] Number | +| UseProcessBlockForPipelineCommand.ps1:10:5:10:11 | (no string representation) | diff --git a/powershell/ql/test/library-tests/ast/parent.expected b/powershell/ql/test/library-tests/ast/parent.expected index 13a4da5ff1c0..7fc8f9f9f727 100644 --- a/powershell/ql/test/library-tests/ast/parent.expected +++ b/powershell/ql/test/library-tests/ast/parent.expected @@ -328,6 +328,7 @@ | Statements/TrapStatement.ps1:1:1:4:1 | def of TrapTest | Statements/TrapStatement.ps1:1:1:6:8 | {...} | | Statements/TrapStatement.ps1:1:1:6:8 | {...} | Statements/TrapStatement.ps1:1:1:6:8 | {...} | | Statements/TrapStatement.ps1:1:1:6:8 | {...} | file://:0:0:0:0 | toplevel function for TrapStatement.ps1 | +| Statements/TrapStatement.ps1:1:19:4:1 | [synth] pipeline | Statements/TrapStatement.ps1:1:19:4:1 | {...} | | Statements/TrapStatement.ps1:1:19:4:1 | {...} | Statements/TrapStatement.ps1:1:1:4:1 | TrapTest | | Statements/TrapStatement.ps1:2:5:2:25 | trap {...} | Statements/TrapStatement.ps1:2:5:3:18 | {...} | | Statements/TrapStatement.ps1:2:5:3:18 | {...} | Statements/TrapStatement.ps1:1:19:4:1 | {...} | @@ -375,14 +376,12 @@ | Statements/UseProcessBlockForPipelineCommand.ps1:1:1:11:1 | def of Get-Number | Statements/UseProcessBlockForPipelineCommand.ps1:1:1:11:1 | {...} | | Statements/UseProcessBlockForPipelineCommand.ps1:1:1:11:1 | {...} | Statements/UseProcessBlockForPipelineCommand.ps1:1:1:11:1 | {...} | | Statements/UseProcessBlockForPipelineCommand.ps1:1:1:11:1 | {...} | file://:0:0:0:0 | toplevel function for UseProcessBlockForPipelineCommand.ps1 | -| Statements/UseProcessBlockForPipelineCommand.ps1:2:1:11:1 | Number | Statements/UseProcessBlockForPipelineCommand.ps1:2:1:11:1 | {...} | | Statements/UseProcessBlockForPipelineCommand.ps1:2:1:11:1 | [synth] pipeline | Statements/UseProcessBlockForPipelineCommand.ps1:2:1:11:1 | {...} | | Statements/UseProcessBlockForPipelineCommand.ps1:2:1:11:1 | {...} | Statements/UseProcessBlockForPipelineCommand.ps1:1:1:11:1 | Get-Number | | Statements/UseProcessBlockForPipelineCommand.ps1:3:5:3:21 | CmdletBinding | Statements/UseProcessBlockForPipelineCommand.ps1:2:1:11:1 | {...} | | Statements/UseProcessBlockForPipelineCommand.ps1:4:5:10:11 | {...} | Statements/UseProcessBlockForPipelineCommand.ps1:2:1:11:1 | {...} | -| Statements/UseProcessBlockForPipelineCommand.ps1:5:9:5:38 | ValueFromPipeline | Statements/UseProcessBlockForPipelineCommand.ps1:2:1:11:1 | Number | +| Statements/UseProcessBlockForPipelineCommand.ps1:5:9:5:38 | ValueFromPipeline | Statements/UseProcessBlockForPipelineCommand.ps1:2:1:11:1 | [synth] pipeline | | Statements/UseProcessBlockForPipelineCommand.ps1:5:20:5:36 | (no string representation) | Statements/UseProcessBlockForPipelineCommand.ps1:5:20:5:36 | ValueFromPipeline | | Statements/UseProcessBlockForPipelineCommand.ps1:5:20:5:36 | ValueFromPipeline | Statements/UseProcessBlockForPipelineCommand.ps1:5:9:5:38 | ValueFromPipeline | -| Statements/UseProcessBlockForPipelineCommand.ps1:6:9:6:13 | int | Statements/UseProcessBlockForPipelineCommand.ps1:2:1:11:1 | Number | -| Statements/UseProcessBlockForPipelineCommand.ps1:10:5:10:11 | Number | Statements/UseProcessBlockForPipelineCommand.ps1:10:5:10:11 | [Stmt] Number | -| Statements/UseProcessBlockForPipelineCommand.ps1:10:5:10:11 | [Stmt] Number | Statements/UseProcessBlockForPipelineCommand.ps1:4:5:10:11 | {...} | +| Statements/UseProcessBlockForPipelineCommand.ps1:6:9:6:13 | int | Statements/UseProcessBlockForPipelineCommand.ps1:2:1:11:1 | [synth] pipeline | +| Statements/UseProcessBlockForPipelineCommand.ps1:10:5:10:11 | (no string representation) | Statements/UseProcessBlockForPipelineCommand.ps1:4:5:10:11 | {...} | diff --git a/powershell/ql/test/library-tests/controlflow/graph/Cfg.expected b/powershell/ql/test/library-tests/controlflow/graph/Cfg.expected index d4be5cad40bf..ea88eea58ae6 100644 --- a/powershell/ql/test/library-tests/controlflow/graph/Cfg.expected +++ b/powershell/ql/test/library-tests/controlflow/graph/Cfg.expected @@ -153,9 +153,10 @@ | conditionals.ps1:97:9:97:17 | return ... | conditionals.ps1:97:16:97:17 | 12 | | | conditionals.ps1:97:16:97:17 | 12 | conditionals.ps1:87:5:98:5 | if (...) {...} else {...} | | | conditionals.ps1:101:1:108:1 | def of test-switch | conditionals.ps1:110:1:121:1 | def of test-switch-default | | +| conditionals.ps1:101:26:108:1 | [synth] pipeline | conditionals.ps1:102:5:107:5 | {...} | | | conditionals.ps1:101:26:108:1 | enter {...} | conditionals.ps1:101:26:108:1 | {...} | | | conditionals.ps1:101:26:108:1 | exit {...} (normal) | conditionals.ps1:101:26:108:1 | exit {...} | | -| conditionals.ps1:101:26:108:1 | n | conditionals.ps1:102:5:107:5 | {...} | | +| conditionals.ps1:101:26:108:1 | n | conditionals.ps1:101:26:108:1 | [synth] pipeline | | | conditionals.ps1:101:26:108:1 | {...} | conditionals.ps1:101:26:108:1 | n | | | conditionals.ps1:102:5:107:5 | switch(...) {...} | conditionals.ps1:102:12:102:13 | n | | | conditionals.ps1:102:5:107:5 | {...} | conditionals.ps1:102:5:107:5 | switch(...) {...} | | @@ -176,9 +177,10 @@ | conditionals.ps1:106:14:106:21 | return ... | conditionals.ps1:106:21:106:21 | 2 | | | conditionals.ps1:106:21:106:21 | 2 | conditionals.ps1:101:26:108:1 | exit {...} (normal) | | | conditionals.ps1:110:1:121:1 | def of test-switch-default | conditionals.ps1:123:1:129:1 | def of test-switch-assign | | +| conditionals.ps1:110:34:121:1 | [synth] pipeline | conditionals.ps1:111:5:120:5 | {...} | | | conditionals.ps1:110:34:121:1 | enter {...} | conditionals.ps1:110:34:121:1 | {...} | | | conditionals.ps1:110:34:121:1 | exit {...} (normal) | conditionals.ps1:110:34:121:1 | exit {...} | | -| conditionals.ps1:110:34:121:1 | n | conditionals.ps1:111:5:120:5 | {...} | | +| conditionals.ps1:110:34:121:1 | n | conditionals.ps1:110:34:121:1 | [synth] pipeline | | | conditionals.ps1:110:34:121:1 | {...} | conditionals.ps1:110:34:121:1 | n | | | conditionals.ps1:111:5:120:5 | switch(...) {...} | conditionals.ps1:111:12:111:13 | n | | | conditionals.ps1:111:5:120:5 | {...} | conditionals.ps1:111:5:120:5 | switch(...) {...} | | @@ -208,9 +210,10 @@ | conditionals.ps1:118:13:118:20 | return ... | conditionals.ps1:118:20:118:20 | 3 | | | conditionals.ps1:118:20:118:20 | 3 | conditionals.ps1:110:34:121:1 | exit {...} (normal) | | | conditionals.ps1:123:1:129:1 | def of test-switch-assign | conditionals.ps1:1:1:129:1 | exit {...} (normal) | | +| conditionals.ps1:123:33:129:1 | [synth] pipeline | conditionals.ps1:124:5:128:5 | {...} | | | conditionals.ps1:123:33:129:1 | enter {...} | conditionals.ps1:123:33:129:1 | {...} | | | conditionals.ps1:123:33:129:1 | exit {...} (normal) | conditionals.ps1:123:33:129:1 | exit {...} | | -| conditionals.ps1:123:33:129:1 | n | conditionals.ps1:124:5:128:5 | {...} | | +| conditionals.ps1:123:33:129:1 | n | conditionals.ps1:123:33:129:1 | [synth] pipeline | | | conditionals.ps1:123:33:129:1 | {...} | conditionals.ps1:123:33:129:1 | n | | | conditionals.ps1:124:5:124:6 | a | conditionals.ps1:123:33:129:1 | exit {...} (normal) | | | conditionals.ps1:124:5:128:5 | ...=... | conditionals.ps1:124:5:124:6 | a | | @@ -227,13 +230,9 @@ | functions.ps1:1:32:9:1 | number2 | functions.ps1:1:32:9:1 | [synth] pipeline | | | functions.ps1:1:32:9:1 | {...} | functions.ps1:1:32:9:1 | number1 | | | functions.ps1:3:5:8:23 | {...} | functions.ps1:8:5:8:23 | [Stmt] ...+... | | -| functions.ps1:3:5:8:23 | {...} | functions.ps1:8:5:8:23 | [Stmt] __pipeline_iterator | | | functions.ps1:8:5:8:12 | number1 | functions.ps1:8:16:8:23 | number2 | | | functions.ps1:8:5:8:23 | ...+... | functions.ps1:1:32:9:1 | exit {...} (normal) | | | functions.ps1:8:5:8:23 | [Stmt] ...+... | functions.ps1:8:5:8:12 | number1 | | -| functions.ps1:8:5:8:23 | [Stmt] ...+... | functions.ps1:46:17:46:18 | __pipeline_iterator | | -| functions.ps1:8:5:8:23 | [Stmt] __pipeline_iterator | functions.ps1:8:5:8:12 | number1 | | -| functions.ps1:8:5:8:23 | [Stmt] __pipeline_iterator | functions.ps1:46:17:46:18 | __pipeline_iterator | | | functions.ps1:8:16:8:23 | number2 | functions.ps1:8:5:8:23 | ...+... | | | functions.ps1:11:1:11:28 | def of foo | functions.ps1:13:1:20:1 | def of Default-Arguments | | | functions.ps1:11:16:11:28 | [synth] pipeline | functions.ps1:11:18:11:26 | {...} | | @@ -253,7 +252,6 @@ | 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] ...+... | | -| functions.ps1:14:5:19:18 | {...} | functions.ps1:19:5:19:18 | [Stmt] __pipeline_iterator | | | functions.ps1:16:24:16:24 | 0 | functions.ps1:13:28:20:1 | name2 | | | functions.ps1:16:24:16:24 | 0 | functions.ps1:17:24:17:29 | name1 | | | functions.ps1:17:24:17:29 | name1 | functions.ps1:17:33:17:33 | 1 | | @@ -262,9 +260,6 @@ | functions.ps1:17:33:17:33 | 1 | functions.ps1:17:24:17:33 | ...+... | | | functions.ps1:19:5:19:18 | ...+... | functions.ps1:13:28:20:1 | exit {...} (normal) | | | functions.ps1:19:5:19:18 | [Stmt] ...+... | functions.ps1:19:13:19:18 | name2 | | -| functions.ps1:19:5:19:18 | [Stmt] ...+... | functions.ps1:46:17:46:18 | __pipeline_iterator | | -| functions.ps1:19:5:19:18 | [Stmt] __pipeline_iterator | functions.ps1:19:13:19:18 | name2 | | -| functions.ps1:19:5:19:18 | [Stmt] __pipeline_iterator | functions.ps1:46:17:46:18 | __pipeline_iterator | | | functions.ps1:19:13:19:18 | name2 | functions.ps1:19:5:19:18 | ...+... | | | functions.ps1:22:1:34:1 | def of Add-Numbers-From-Array | functions.ps1:36:1:52:1 | def of Add-Numbers-From-Pipeline | | | functions.ps1:22:33:34:1 | [synth] pipeline | functions.ps1:24:5:33:8 | {...} | | @@ -276,13 +271,9 @@ | functions.ps1:28:5:28:8 | sum | functions.ps1:28:12:28:12 | 0 | | | functions.ps1:28:5:28:12 | ...=... | functions.ps1:28:5:28:8 | sum | | | functions.ps1:28:12:28:12 | 0 | functions.ps1:29:25:29:32 | numbers | | -| functions.ps1:29:5:32:5 | forach(... in ...) | functions.ps1:33:5:33:8 | [Stmt] __pipeline_iterator | empty | | functions.ps1:29:5:32:5 | forach(... in ...) | functions.ps1:33:5:33:8 | [Stmt] sum | empty | | functions.ps1:29:25:29:32 | numbers | functions.ps1:29:5:32:5 | forach(... in ...) | | -| functions.ps1:33:5:33:8 | [Stmt] __pipeline_iterator | functions.ps1:33:5:33:8 | sum | | -| functions.ps1:33:5:33:8 | [Stmt] __pipeline_iterator | functions.ps1:46:17:46:18 | __pipeline_iterator | | | functions.ps1:33:5:33:8 | [Stmt] sum | functions.ps1:33:5:33:8 | sum | | -| functions.ps1:33:5:33:8 | [Stmt] sum | functions.ps1:46:17:46:18 | __pipeline_iterator | | | functions.ps1:33:5:33:8 | sum | functions.ps1:22:33:34:1 | exit {...} (normal) | | | functions.ps1:36:1:52:1 | def of Add-Numbers-From-Pipeline | functions.ps1:1:1:54:0 | exit {...} (normal) | | | functions.ps1:36:36:52:1 | [synth] pipeline | functions.ps1:41:5:43:5 | {...} | | @@ -293,20 +284,14 @@ | functions.ps1:41:5:43:5 | {...} | functions.ps1:42:9:42:16 | ...=... | | | functions.ps1:42:9:42:12 | sum | functions.ps1:42:16:42:16 | 0 | | | functions.ps1:42:9:42:16 | ...=... | functions.ps1:42:9:42:12 | sum | | -| functions.ps1:42:16:42:16 | 0 | functions.ps1:44:5:47:5 | {...} | | +| functions.ps1:42:16:42:16 | 0 | functions.ps1:44:5:47:5 | [synth] pipeline | | +| functions.ps1:44:5:47:5 | [synth] pipeline | functions.ps1:44:5:47:5 | {...} | | | functions.ps1:44:5:47:5 | {...} | functions.ps1:46:9:46:18 | ...=... | | -| functions.ps1:46:9:46:12 | sum | functions.ps1:44:5:47:5 | {...} | | -| functions.ps1:46:9:46:12 | sum | functions.ps1:48:5:51:5 | {...} | | +| functions.ps1:46:9:46:12 | sum | functions.ps1:46:17:46:18 | __pipeline_iterator | | | functions.ps1:46:9:46:18 | ...=... | functions.ps1:46:9:46:12 | sum | | -| functions.ps1:46:17:46:18 | __pipeline_iterator | functions.ps1:1:32:9:1 | exit {...} (normal) | | -| functions.ps1:46:17:46:18 | __pipeline_iterator | functions.ps1:13:28:20:1 | exit {...} (normal) | | -| functions.ps1:46:17:46:18 | __pipeline_iterator | functions.ps1:22:33:34:1 | exit {...} (normal) | | -| functions.ps1:46:17:46:18 | __pipeline_iterator | functions.ps1:36:36:52:1 | exit {...} (normal) | | -| functions.ps1:48:5:51:5 | {...} | functions.ps1:50:9:50:12 | [Stmt] __pipeline_iterator | | +| functions.ps1:46:17:46:18 | __pipeline_iterator | functions.ps1:44:5:47:5 | [synth] pipeline | | +| functions.ps1:46:17:46:18 | __pipeline_iterator | functions.ps1:48:5:51:5 | {...} | | | functions.ps1:48:5:51:5 | {...} | functions.ps1:50:9:50:12 | [Stmt] sum | | -| functions.ps1:50:9:50:12 | [Stmt] __pipeline_iterator | functions.ps1:46:17:46:18 | __pipeline_iterator | | -| functions.ps1:50:9:50:12 | [Stmt] __pipeline_iterator | functions.ps1:50:9:50:12 | sum | | -| functions.ps1:50:9:50:12 | [Stmt] sum | functions.ps1:46:17:46:18 | __pipeline_iterator | | | functions.ps1:50:9:50:12 | [Stmt] sum | functions.ps1:50:9:50:12 | sum | | | functions.ps1:50:9:50:12 | sum | functions.ps1:36:36:52:1 | exit {...} (normal) | | | global.ps1:1:1:4:1 | {...} | global.ps1:2:5:2:10 | ...=... | | @@ -330,9 +315,10 @@ | loops.ps1:1:1:70:0 | enter {...} | loops.ps1:1:1:70:0 | {...} | | | loops.ps1:1:1:70:0 | exit {...} (normal) | loops.ps1:1:1:70:0 | exit {...} | | | loops.ps1:1:1:70:0 | {...} | loops.ps1:1:1:68:1 | {...} | | +| loops.ps1:1:21:7:1 | [synth] pipeline | loops.ps1:2:5:6:5 | {...} | | | loops.ps1:1:21:7:1 | enter {...} | loops.ps1:1:21:7:1 | {...} | | | loops.ps1:1:21:7:1 | exit {...} (normal) | loops.ps1:1:21:7:1 | exit {...} | | -| loops.ps1:1:21:7:1 | {...} | loops.ps1:2:5:6:5 | {...} | | +| loops.ps1:1:21:7:1 | {...} | loops.ps1:1:21:7:1 | [synth] pipeline | | | loops.ps1:2:5:2:6 | a | loops.ps1:2:10:2:10 | 0 | | | loops.ps1:2:5:2:10 | ...=... | loops.ps1:2:5:2:6 | a | | | loops.ps1:2:5:6:5 | {...} | loops.ps1:2:5:2:10 | ...=... | | @@ -349,9 +335,10 @@ | loops.ps1:5:14:5:19 | ...+... | loops.ps1:4:11:4:12 | a | | | loops.ps1:5:19:5:19 | 1 | loops.ps1:5:14:5:19 | ...+... | | | loops.ps1:9:1:15:1 | def of Test-Break | loops.ps1:17:1:23:1 | def of Test-Continue | | +| loops.ps1:9:21:15:1 | [synth] pipeline | loops.ps1:10:5:14:5 | {...} | | | loops.ps1:9:21:15:1 | enter {...} | loops.ps1:9:21:15:1 | {...} | | | loops.ps1:9:21:15:1 | exit {...} (normal) | loops.ps1:9:21:15:1 | exit {...} | | -| loops.ps1:9:21:15:1 | {...} | loops.ps1:10:5:14:5 | {...} | | +| loops.ps1:9:21:15:1 | {...} | loops.ps1:9:21:15:1 | [synth] pipeline | | | loops.ps1:10:5:10:6 | a | loops.ps1:10:10:10:10 | 0 | | | loops.ps1:10:5:10:10 | ...=... | loops.ps1:10:5:10:6 | a | | | loops.ps1:10:5:14:5 | {...} | loops.ps1:10:5:10:10 | ...=... | | @@ -364,9 +351,10 @@ | loops.ps1:11:22:14:5 | {...} | loops.ps1:12:9:12:13 | break | | | loops.ps1:12:9:12:13 | break | loops.ps1:9:21:15:1 | exit {...} (normal) | break | | loops.ps1:17:1:23:1 | def of Test-Continue | loops.ps1:25:1:31:1 | def of Test-DoWhile | | +| loops.ps1:17:24:23:1 | [synth] pipeline | loops.ps1:18:5:22:5 | {...} | | | loops.ps1:17:24:23:1 | enter {...} | loops.ps1:17:24:23:1 | {...} | | | loops.ps1:17:24:23:1 | exit {...} (normal) | loops.ps1:17:24:23:1 | exit {...} | | -| loops.ps1:17:24:23:1 | {...} | loops.ps1:18:5:22:5 | {...} | | +| loops.ps1:17:24:23:1 | {...} | loops.ps1:17:24:23:1 | [synth] pipeline | | | loops.ps1:18:5:18:6 | a | loops.ps1:18:10:18:10 | 0 | | | loops.ps1:18:5:18:10 | ...=... | loops.ps1:18:5:18:6 | a | | | loops.ps1:18:5:22:5 | {...} | loops.ps1:18:5:18:10 | ...=... | | @@ -379,9 +367,10 @@ | loops.ps1:19:22:22:5 | {...} | loops.ps1:20:9:20:16 | continue | | | loops.ps1:20:9:20:16 | continue | loops.ps1:19:11:19:12 | a | continue | | loops.ps1:25:1:31:1 | def of Test-DoWhile | loops.ps1:33:1:39:1 | def of Test-DoUntil | | +| loops.ps1:25:23:31:1 | [synth] pipeline | loops.ps1:26:5:30:23 | {...} | | | loops.ps1:25:23:31:1 | enter {...} | loops.ps1:25:23:31:1 | {...} | | | loops.ps1:25:23:31:1 | exit {...} (normal) | loops.ps1:25:23:31:1 | exit {...} | | -| loops.ps1:25:23:31:1 | {...} | loops.ps1:26:5:30:23 | {...} | | +| loops.ps1:25:23:31:1 | {...} | loops.ps1:25:23:31:1 | [synth] pipeline | | | loops.ps1:26:5:26:6 | a | loops.ps1:26:10:26:10 | 0 | | | loops.ps1:26:5:26:10 | ...=... | loops.ps1:26:5:26:6 | a | | | loops.ps1:26:5:30:23 | {...} | loops.ps1:26:5:26:10 | ...=... | | @@ -398,9 +387,10 @@ | loops.ps1:30:14:30:22 | ... -le ... | loops.ps1:28:8:30:5 | {...} | true | | loops.ps1:30:21:30:22 | 10 | loops.ps1:30:14:30:22 | ... -le ... | | | loops.ps1:33:1:39:1 | def of Test-DoUntil | loops.ps1:41:1:47:1 | def of Test-For | | +| loops.ps1:33:23:39:1 | [synth] pipeline | loops.ps1:34:5:38:23 | {...} | | | loops.ps1:33:23:39:1 | enter {...} | loops.ps1:33:23:39:1 | {...} | | | loops.ps1:33:23:39:1 | exit {...} (normal) | loops.ps1:33:23:39:1 | exit {...} | | -| loops.ps1:33:23:39:1 | {...} | loops.ps1:34:5:38:23 | {...} | | +| loops.ps1:33:23:39:1 | {...} | loops.ps1:33:23:39:1 | [synth] pipeline | | | loops.ps1:34:5:34:6 | a | loops.ps1:34:10:34:10 | 0 | | | loops.ps1:34:5:34:10 | ...=... | loops.ps1:34:5:34:6 | a | | | loops.ps1:34:5:38:23 | {...} | loops.ps1:34:5:34:10 | ...=... | | @@ -417,9 +407,10 @@ | loops.ps1:38:14:38:22 | ... -ge ... | loops.ps1:36:8:38:5 | {...} | false | | loops.ps1:38:21:38:22 | 10 | loops.ps1:38:14:38:22 | ... -ge ... | | | loops.ps1:41:1:47:1 | def of Test-For | loops.ps1:49:1:56:1 | def of Test-ForEach | | +| loops.ps1:41:19:47:1 | [synth] pipeline | loops.ps1:42:5:46:5 | {...} | | | loops.ps1:41:19:47:1 | enter {...} | loops.ps1:41:19:47:1 | {...} | | | loops.ps1:41:19:47:1 | exit {...} (normal) | loops.ps1:41:19:47:1 | exit {...} | | -| loops.ps1:41:19:47:1 | {...} | loops.ps1:42:5:46:5 | {...} | | +| loops.ps1:41:19:47:1 | {...} | loops.ps1:41:19:47:1 | [synth] pipeline | | | loops.ps1:42:5:42:6 | a | loops.ps1:42:10:42:10 | 0 | | | loops.ps1:42:5:42:10 | ...=... | loops.ps1:42:5:42:6 | a | | | loops.ps1:42:5:46:5 | {...} | loops.ps1:42:5:42:10 | ...=... | | @@ -445,9 +436,10 @@ | loops.ps1:45:14:45:19 | ...+... | loops.ps1:44:29:44:39 | ...=... | | | loops.ps1:45:19:45:19 | 1 | loops.ps1:45:14:45:19 | ...+... | | | loops.ps1:49:1:56:1 | def of Test-ForEach | loops.ps1:58:1:68:1 | def of Test-For-Ever | | +| loops.ps1:49:23:56:1 | [synth] pipeline | loops.ps1:50:5:55:5 | {...} | | | loops.ps1:49:23:56:1 | enter {...} | loops.ps1:49:23:56:1 | {...} | | | loops.ps1:49:23:56:1 | exit {...} (normal) | loops.ps1:49:23:56:1 | exit {...} | | -| loops.ps1:49:23:56:1 | {...} | loops.ps1:50:5:55:5 | {...} | | +| loops.ps1:49:23:56:1 | {...} | loops.ps1:49:23:56:1 | [synth] pipeline | | | loops.ps1:50:5:50:16 | letterArray | loops.ps1:50:20:50:22 | a | | | loops.ps1:50:5:50:34 | ...=... | loops.ps1:50:5:50:16 | letterArray | | | loops.ps1:50:5:55:5 | {...} | loops.ps1:50:5:50:34 | ...=... | | @@ -462,9 +454,10 @@ | loops.ps1:52:5:55:5 | forach(... in ...) | loops.ps1:49:23:56:1 | exit {...} (normal) | empty | | loops.ps1:52:25:52:36 | letterArray | loops.ps1:52:5:55:5 | forach(... in ...) | | | loops.ps1:58:1:68:1 | def of Test-For-Ever | loops.ps1:1:1:70:0 | exit {...} (normal) | | +| loops.ps1:58:24:68:1 | [synth] pipeline | loops.ps1:59:5:67:5 | {...} | | | loops.ps1:58:24:68:1 | enter {...} | loops.ps1:58:24:68:1 | {...} | | | loops.ps1:58:24:68:1 | exit {...} (normal) | loops.ps1:58:24:68:1 | exit {...} | | -| loops.ps1:58:24:68:1 | {...} | loops.ps1:59:5:67:5 | {...} | | +| loops.ps1:58:24:68:1 | {...} | loops.ps1:58:24:68:1 | [synth] pipeline | | | loops.ps1:59:5:59:6 | a | loops.ps1:59:10:59:10 | 0 | | | loops.ps1:59:5:59:10 | ...=... | loops.ps1:59:5:59:6 | a | | | loops.ps1:59:5:67:5 | {...} | loops.ps1:59:5:59:10 | ...=... | | @@ -484,9 +477,10 @@ | try.ps1:1:1:194:1 | exit {...} (normal) | try.ps1:1:1:194:1 | exit {...} | | | try.ps1:1:1:194:1 | {...} | try.ps1:1:1:8:1 | def of test-try-catch | | | try.ps1:1:1:194:1 | {...} | try.ps1:1:1:194:1 | {...} | | +| try.ps1:1:25:8:1 | [synth] pipeline | try.ps1:2:5:7:12 | {...} | | | try.ps1:1:25:8:1 | enter {...} | try.ps1:1:25:8:1 | {...} | | | try.ps1:1:25:8:1 | exit {...} (normal) | try.ps1:1:25:8:1 | exit {...} | | -| try.ps1:1:25:8:1 | {...} | try.ps1:2:5:7:12 | {...} | | +| try.ps1:1:25:8:1 | {...} | try.ps1:1:25:8:1 | [synth] pipeline | | | try.ps1:2:5:6:5 | try {...} | try.ps1:2:9:4:5 | {...} | | | try.ps1:2:5:7:12 | {...} | try.ps1:2:5:6:5 | try {...} | | | try.ps1:2:9:4:5 | {...} | try.ps1:3:9:3:29 | [Stmt] Call to Write-Output | | @@ -497,7 +491,8 @@ | try.ps1:7:5:7:12 | return ... | try.ps1:7:12:7:12 | 1 | | | try.ps1:7:12:7:12 | 1 | try.ps1:1:25:8:1 | exit {...} (normal) | | | try.ps1:10:1:19:1 | def of test-try-with-throw-catch | try.ps1:21:1:30:1 | def of test-try-with-throw-catch-with-throw | | -| try.ps1:10:40:19:1 | b | try.ps1:11:5:18:12 | {...} | | +| try.ps1:10:40:19:1 | [synth] pipeline | try.ps1:11:5:18:12 | {...} | | +| try.ps1:10:40:19:1 | b | try.ps1:10:40:19:1 | [synth] pipeline | | | try.ps1:10:40:19:1 | enter {...} | try.ps1:10:40:19:1 | {...} | | | try.ps1:10:40:19:1 | exit {...} (normal) | try.ps1:10:40:19:1 | exit {...} | | | try.ps1:10:40:19:1 | {...} | try.ps1:10:40:19:1 | b | | @@ -514,7 +509,8 @@ | try.ps1:18:5:18:12 | return ... | try.ps1:18:12:18:12 | 1 | | | try.ps1:18:12:18:12 | 1 | try.ps1:10:40:19:1 | exit {...} (normal) | | | try.ps1:21:1:30:1 | def of test-try-with-throw-catch-with-throw | try.ps1:32:1:41:1 | def of test-try-with-throw-catch-with-rethrow | | -| try.ps1:21:51:30:1 | b | try.ps1:22:5:29:12 | {...} | | +| try.ps1:21:51:30:1 | [synth] pipeline | try.ps1:22:5:29:12 | {...} | | +| try.ps1:21:51:30:1 | b | try.ps1:21:51:30:1 | [synth] pipeline | | | try.ps1:21:51:30:1 | enter {...} | try.ps1:21:51:30:1 | {...} | | | try.ps1:21:51:30:1 | exit {...} (normal) | try.ps1:21:51:30:1 | exit {...} | | | try.ps1:21:51:30:1 | {...} | try.ps1:21:51:30:1 | b | | @@ -531,7 +527,8 @@ | try.ps1:29:5:29:12 | return ... | try.ps1:29:12:29:12 | 1 | | | try.ps1:29:12:29:12 | 1 | try.ps1:21:51:30:1 | exit {...} (normal) | | | try.ps1:32:1:41:1 | def of test-try-with-throw-catch-with-rethrow | try.ps1:43:1:50:1 | def of test-try-catch-specific-1 | | -| try.ps1:32:53:41:1 | b | try.ps1:33:5:40:12 | {...} | | +| try.ps1:32:53:41:1 | [synth] pipeline | try.ps1:33:5:40:12 | {...} | | +| try.ps1:32:53:41:1 | b | try.ps1:32:53:41:1 | [synth] pipeline | | | try.ps1:32:53:41:1 | enter {...} | try.ps1:32:53:41:1 | {...} | | | try.ps1:32:53:41:1 | exit {...} (normal) | try.ps1:32:53:41:1 | exit {...} | | | try.ps1:32:53:41:1 | {...} | try.ps1:32:53:41:1 | b | | @@ -548,9 +545,10 @@ | try.ps1:40:5:40:12 | return ... | try.ps1:40:12:40:12 | 1 | | | try.ps1:40:12:40:12 | 1 | try.ps1:32:53:41:1 | exit {...} (normal) | | | try.ps1:43:1:50:1 | def of test-try-catch-specific-1 | try.ps1:52:1:59:1 | def of test-try-catch-specific-1 | | +| try.ps1:43:36:50:1 | [synth] pipeline | try.ps1:44:5:49:12 | {...} | | | try.ps1:43:36:50:1 | enter {...} | try.ps1:43:36:50:1 | {...} | | | try.ps1:43:36:50:1 | exit {...} (normal) | try.ps1:43:36:50:1 | exit {...} | | -| try.ps1:43:36:50:1 | {...} | try.ps1:44:5:49:12 | {...} | | +| try.ps1:43:36:50:1 | {...} | try.ps1:43:36:50:1 | [synth] pipeline | | | try.ps1:44:5:48:5 | try {...} | try.ps1:44:9:46:5 | {...} | | | try.ps1:44:5:49:12 | {...} | try.ps1:44:5:48:5 | try {...} | | | try.ps1:44:9:46:5 | {...} | try.ps1:45:9:45:29 | [Stmt] Call to Write-Output | | @@ -561,9 +559,10 @@ | try.ps1:49:5:49:12 | return ... | try.ps1:49:12:49:12 | 1 | | | try.ps1:49:12:49:12 | 1 | try.ps1:43:36:50:1 | exit {...} (normal) | | | try.ps1:52:1:59:1 | def of test-try-catch-specific-1 | try.ps1:61:1:70:1 | def of test-try-two-catch-specific-1 | | +| try.ps1:52:36:59:1 | [synth] pipeline | try.ps1:53:5:58:12 | {...} | | | try.ps1:52:36:59:1 | enter {...} | try.ps1:52:36:59:1 | {...} | | | try.ps1:52:36:59:1 | exit {...} (normal) | try.ps1:52:36:59:1 | exit {...} | | -| try.ps1:52:36:59:1 | {...} | try.ps1:53:5:58:12 | {...} | | +| try.ps1:52:36:59:1 | {...} | try.ps1:52:36:59:1 | [synth] pipeline | | | try.ps1:53:5:57:5 | try {...} | try.ps1:53:9:55:5 | {...} | | | try.ps1:53:5:58:12 | {...} | try.ps1:53:5:57:5 | try {...} | | | try.ps1:53:9:55:5 | {...} | try.ps1:54:9:54:29 | [Stmt] Call to Write-Output | | @@ -574,9 +573,10 @@ | try.ps1:58:5:58:12 | return ... | try.ps1:58:12:58:12 | 1 | | | try.ps1:58:12:58:12 | 1 | try.ps1:52:36:59:1 | exit {...} (normal) | | | try.ps1:61:1:70:1 | def of test-try-two-catch-specific-1 | try.ps1:72:1:79:1 | def of test-try-catch-specific-2 | | +| try.ps1:61:40:70:1 | [synth] pipeline | try.ps1:62:5:69:12 | {...} | | | try.ps1:61:40:70:1 | enter {...} | try.ps1:61:40:70:1 | {...} | | | try.ps1:61:40:70:1 | exit {...} (normal) | try.ps1:61:40:70:1 | exit {...} | | -| try.ps1:61:40:70:1 | {...} | try.ps1:62:5:69:12 | {...} | | +| try.ps1:61:40:70:1 | {...} | try.ps1:61:40:70:1 | [synth] pipeline | | | try.ps1:62:5:68:5 | try {...} | try.ps1:62:9:64:5 | {...} | | | try.ps1:62:5:69:12 | {...} | try.ps1:62:5:68:5 | try {...} | | | try.ps1:62:9:64:5 | {...} | try.ps1:63:9:63:29 | [Stmt] Call to Write-Output | | @@ -587,9 +587,10 @@ | try.ps1:69:5:69:12 | return ... | try.ps1:69:12:69:12 | 2 | | | try.ps1:69:12:69:12 | 2 | try.ps1:61:40:70:1 | exit {...} (normal) | | | try.ps1:72:1:79:1 | def of test-try-catch-specific-2 | try.ps1:81:1:90:1 | def of test-try-two-catch-specific-2 | | +| try.ps1:72:36:79:1 | [synth] pipeline | try.ps1:73:5:78:12 | {...} | | | try.ps1:72:36:79:1 | enter {...} | try.ps1:72:36:79:1 | {...} | | | try.ps1:72:36:79:1 | exit {...} (normal) | try.ps1:72:36:79:1 | exit {...} | | -| try.ps1:72:36:79:1 | {...} | try.ps1:73:5:78:12 | {...} | | +| try.ps1:72:36:79:1 | {...} | try.ps1:72:36:79:1 | [synth] pipeline | | | try.ps1:73:5:77:5 | try {...} | try.ps1:73:9:75:5 | {...} | | | try.ps1:73:5:78:12 | {...} | try.ps1:73:5:77:5 | try {...} | | | try.ps1:73:9:75:5 | {...} | try.ps1:74:9:74:29 | [Stmt] Call to Write-Output | | @@ -600,9 +601,10 @@ | try.ps1:78:5:78:12 | return ... | try.ps1:78:12:78:12 | 1 | | | try.ps1:78:12:78:12 | 1 | try.ps1:72:36:79:1 | exit {...} (normal) | | | try.ps1:81:1:90:1 | def of test-try-two-catch-specific-2 | try.ps1:92:1:103:1 | def of test-try-three-catch-specific-2 | | +| try.ps1:81:40:90:1 | [synth] pipeline | try.ps1:82:5:89:12 | {...} | | | try.ps1:81:40:90:1 | enter {...} | try.ps1:81:40:90:1 | {...} | | | try.ps1:81:40:90:1 | exit {...} (normal) | try.ps1:81:40:90:1 | exit {...} | | -| try.ps1:81:40:90:1 | {...} | try.ps1:82:5:89:12 | {...} | | +| try.ps1:81:40:90:1 | {...} | try.ps1:81:40:90:1 | [synth] pipeline | | | try.ps1:82:5:88:5 | try {...} | try.ps1:82:9:84:5 | {...} | | | try.ps1:82:5:89:12 | {...} | try.ps1:82:5:88:5 | try {...} | | | try.ps1:82:9:84:5 | {...} | try.ps1:83:9:83:29 | [Stmt] Call to Write-Output | | @@ -613,9 +615,10 @@ | try.ps1:89:5:89:12 | return ... | try.ps1:89:12:89:12 | 2 | | | try.ps1:89:12:89:12 | 2 | try.ps1:81:40:90:1 | exit {...} (normal) | | | try.ps1:92:1:103:1 | def of test-try-three-catch-specific-2 | try.ps1:105:1:114:1 | def of test-try-catch-finally | | +| try.ps1:92:42:103:1 | [synth] pipeline | try.ps1:93:5:102:12 | {...} | | | try.ps1:92:42:103:1 | enter {...} | try.ps1:92:42:103:1 | {...} | | | try.ps1:92:42:103:1 | exit {...} (normal) | try.ps1:92:42:103:1 | exit {...} | | -| try.ps1:92:42:103:1 | {...} | try.ps1:93:5:102:12 | {...} | | +| try.ps1:92:42:103:1 | {...} | try.ps1:92:42:103:1 | [synth] pipeline | | | try.ps1:93:5:101:5 | try {...} | try.ps1:93:9:95:5 | {...} | | | try.ps1:93:5:102:12 | {...} | try.ps1:93:5:101:5 | try {...} | | | try.ps1:93:9:95:5 | {...} | try.ps1:94:9:94:29 | [Stmt] Call to Write-Output | | @@ -626,9 +629,10 @@ | try.ps1:102:5:102:12 | return ... | try.ps1:102:12:102:12 | 3 | | | try.ps1:102:12:102:12 | 3 | try.ps1:92:42:103:1 | exit {...} (normal) | | | try.ps1:105:1:114:1 | def of test-try-catch-finally | try.ps1:116:1:123:1 | def of test-try-finally | | +| try.ps1:105:33:114:1 | [synth] pipeline | try.ps1:106:5:113:12 | {...} | | | try.ps1:105:33:114:1 | enter {...} | try.ps1:105:33:114:1 | {...} | | | try.ps1:105:33:114:1 | exit {...} (normal) | try.ps1:105:33:114:1 | exit {...} | | -| try.ps1:105:33:114:1 | {...} | try.ps1:106:5:113:12 | {...} | | +| try.ps1:105:33:114:1 | {...} | try.ps1:105:33:114:1 | [synth] pipeline | | | try.ps1:106:5:112:5 | try {...} | try.ps1:106:9:108:5 | {...} | | | try.ps1:106:5:113:12 | {...} | try.ps1:106:5:112:5 | try {...} | | | try.ps1:106:9:108:5 | {...} | try.ps1:107:9:107:29 | [Stmt] Call to Write-Output | | @@ -644,9 +648,10 @@ | try.ps1:113:5:113:12 | return ... | try.ps1:113:12:113:12 | 1 | | | try.ps1:113:12:113:12 | 1 | try.ps1:105:33:114:1 | exit {...} (normal) | | | try.ps1:116:1:123:1 | def of test-try-finally | try.ps1:125:1:134:1 | def of test-try-finally-catch-specific-1 | | +| try.ps1:116:27:123:1 | [synth] pipeline | try.ps1:117:5:122:12 | {...} | | | try.ps1:116:27:123:1 | enter {...} | try.ps1:116:27:123:1 | {...} | | | try.ps1:116:27:123:1 | exit {...} (normal) | try.ps1:116:27:123:1 | exit {...} | | -| try.ps1:116:27:123:1 | {...} | try.ps1:117:5:122:12 | {...} | | +| try.ps1:116:27:123:1 | {...} | try.ps1:116:27:123:1 | [synth] pipeline | | | try.ps1:117:5:121:5 | try {...} | try.ps1:117:9:119:5 | {...} | | | try.ps1:117:5:122:12 | {...} | try.ps1:117:5:121:5 | try {...} | | | try.ps1:117:9:119:5 | {...} | try.ps1:118:9:118:29 | [Stmt] Call to Write-Output | | @@ -662,9 +667,10 @@ | try.ps1:122:5:122:12 | return ... | try.ps1:122:12:122:12 | 1 | | | try.ps1:122:12:122:12 | 1 | try.ps1:116:27:123:1 | exit {...} (normal) | | | try.ps1:125:1:134:1 | def of test-try-finally-catch-specific-1 | try.ps1:136:1:147:1 | def of test-nested-try-inner-finally | | +| try.ps1:125:44:134:1 | [synth] pipeline | try.ps1:126:5:133:12 | {...} | | | try.ps1:125:44:134:1 | enter {...} | try.ps1:125:44:134:1 | {...} | | | try.ps1:125:44:134:1 | exit {...} (normal) | try.ps1:125:44:134:1 | exit {...} | | -| try.ps1:125:44:134:1 | {...} | try.ps1:126:5:133:12 | {...} | | +| try.ps1:125:44:134:1 | {...} | try.ps1:125:44:134:1 | [synth] pipeline | | | try.ps1:126:5:132:5 | try {...} | try.ps1:126:9:128:5 | {...} | | | try.ps1:126:5:133:12 | {...} | try.ps1:126:5:132:5 | try {...} | | | try.ps1:126:9:128:5 | {...} | try.ps1:127:9:127:29 | [Stmt] Call to Write-Output | | @@ -680,9 +686,10 @@ | try.ps1:133:5:133:12 | return ... | try.ps1:133:12:133:12 | 1 | | | try.ps1:133:12:133:12 | 1 | try.ps1:125:44:134:1 | exit {...} (normal) | | | try.ps1:136:1:147:1 | def of test-nested-try-inner-finally | try.ps1:149:1:162:1 | def of test-nested-try-inner-finally | | +| try.ps1:136:40:147:1 | [synth] pipeline | try.ps1:137:5:146:12 | {...} | | | try.ps1:136:40:147:1 | enter {...} | try.ps1:136:40:147:1 | {...} | | | try.ps1:136:40:147:1 | exit {...} (normal) | try.ps1:136:40:147:1 | exit {...} | | -| try.ps1:136:40:147:1 | {...} | try.ps1:137:5:146:12 | {...} | | +| try.ps1:136:40:147:1 | {...} | try.ps1:136:40:147:1 | [synth] pipeline | | | try.ps1:137:5:145:5 | try {...} | try.ps1:137:9:143:5 | {...} | | | try.ps1:137:5:146:12 | {...} | try.ps1:137:5:145:5 | try {...} | | | try.ps1:137:9:143:5 | {...} | try.ps1:138:9:142:9 | try {...} | | @@ -695,9 +702,10 @@ | try.ps1:146:5:146:12 | return ... | try.ps1:146:12:146:12 | 1 | | | try.ps1:146:12:146:12 | 1 | try.ps1:136:40:147:1 | exit {...} (normal) | | | try.ps1:149:1:162:1 | def of test-nested-try-inner-finally | try.ps1:164:1:177:1 | def of test-nested-try-outer-finally | | +| try.ps1:149:40:162:1 | [synth] pipeline | try.ps1:150:5:161:12 | {...} | | | try.ps1:149:40:162:1 | enter {...} | try.ps1:149:40:162:1 | {...} | | | try.ps1:149:40:162:1 | exit {...} (normal) | try.ps1:149:40:162:1 | exit {...} | | -| try.ps1:149:40:162:1 | {...} | try.ps1:150:5:161:12 | {...} | | +| try.ps1:149:40:162:1 | {...} | try.ps1:149:40:162:1 | [synth] pipeline | | | try.ps1:150:5:160:5 | try {...} | try.ps1:150:9:158:5 | {...} | | | try.ps1:150:5:161:12 | {...} | try.ps1:150:5:160:5 | try {...} | | | try.ps1:150:9:158:5 | {...} | try.ps1:151:9:157:9 | try {...} | | @@ -715,9 +723,10 @@ | try.ps1:161:5:161:12 | return ... | try.ps1:161:12:161:12 | 1 | | | try.ps1:161:12:161:12 | 1 | try.ps1:149:40:162:1 | exit {...} (normal) | | | try.ps1:164:1:177:1 | def of test-nested-try-outer-finally | try.ps1:179:1:194:1 | def of test-nested-try-inner-outer-finally | | +| try.ps1:164:40:177:1 | [synth] pipeline | try.ps1:165:5:176:12 | {...} | | | try.ps1:164:40:177:1 | enter {...} | try.ps1:164:40:177:1 | {...} | | | try.ps1:164:40:177:1 | exit {...} (normal) | try.ps1:164:40:177:1 | exit {...} | | -| try.ps1:164:40:177:1 | {...} | try.ps1:165:5:176:12 | {...} | | +| try.ps1:164:40:177:1 | {...} | try.ps1:164:40:177:1 | [synth] pipeline | | | try.ps1:165:5:175:5 | try {...} | try.ps1:165:9:171:5 | {...} | | | try.ps1:165:5:176:12 | {...} | try.ps1:165:5:175:5 | try {...} | | | try.ps1:165:9:171:5 | {...} | try.ps1:166:9:170:9 | try {...} | | @@ -735,9 +744,10 @@ | try.ps1:176:5:176:12 | return ... | try.ps1:176:12:176:12 | 1 | | | try.ps1:176:12:176:12 | 1 | try.ps1:164:40:177:1 | exit {...} (normal) | | | try.ps1:179:1:194:1 | def of test-nested-try-inner-outer-finally | try.ps1:1:1:194:1 | exit {...} (normal) | | +| try.ps1:179:46:194:1 | [synth] pipeline | try.ps1:180:5:193:12 | {...} | | | try.ps1:179:46:194:1 | enter {...} | try.ps1:179:46:194:1 | {...} | | | try.ps1:179:46:194:1 | exit {...} (normal) | try.ps1:179:46:194:1 | exit {...} | | -| try.ps1:179:46:194:1 | {...} | try.ps1:180:5:193:12 | {...} | | +| try.ps1:179:46:194:1 | {...} | try.ps1:179:46:194:1 | [synth] pipeline | | | try.ps1:180:5:192:5 | try {...} | try.ps1:180:9:188:5 | {...} | | | try.ps1:180:5:193:12 | {...} | try.ps1:180:5:192:5 | try {...} | | | try.ps1:180:9:188:5 | {...} | try.ps1:181:9:187:9 | try {...} | | diff --git a/powershell/ql/test/library-tests/controlflow/graph/consistency.expected b/powershell/ql/test/library-tests/controlflow/graph/consistency.expected index 33994ab4888b..6f6c4e8dca39 100644 --- a/powershell/ql/test/library-tests/controlflow/graph/consistency.expected +++ b/powershell/ql/test/library-tests/controlflow/graph/consistency.expected @@ -4,10 +4,6 @@ breakInvariant3 breakInvariant4 breakInvariant5 multipleSuccessors -| functions.ps1:8:5:8:23 | [Stmt] ...+... | successor | functions.ps1:8:5:8:12 | number1 | -| 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 | @@ -16,20 +12,8 @@ multipleSuccessors | 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 | | functions.ps1:17:24:17:33 | ...+... | successor | functions.ps1:13:28:20:1 | name0 | -| functions.ps1:19:5:19:18 | [Stmt] ...+... | successor | functions.ps1:19:13:19:18 | name2 | -| functions.ps1:19:5:19:18 | [Stmt] ...+... | successor | functions.ps1:46:17:46:18 | __pipeline_iterator | -| functions.ps1:19:5:19:18 | [Stmt] __pipeline_iterator | successor | functions.ps1:19:13:19:18 | name2 | -| functions.ps1:19:5:19:18 | [Stmt] __pipeline_iterator | successor | functions.ps1:46:17:46:18 | __pipeline_iterator | -| functions.ps1:33:5:33:8 | [Stmt] __pipeline_iterator | successor | functions.ps1:33:5:33:8 | sum | -| functions.ps1:33:5:33:8 | [Stmt] __pipeline_iterator | successor | functions.ps1:46:17:46:18 | __pipeline_iterator | -| functions.ps1:33:5:33:8 | [Stmt] sum | successor | functions.ps1:33:5:33:8 | sum | -| functions.ps1:33:5:33:8 | [Stmt] sum | successor | functions.ps1:46:17:46:18 | __pipeline_iterator | -| functions.ps1:46:9:46:12 | sum | successor | functions.ps1:44:5:47:5 | {...} | -| functions.ps1:46:9:46:12 | sum | successor | functions.ps1:48:5:51:5 | {...} | -| functions.ps1:50:9:50:12 | [Stmt] __pipeline_iterator | successor | functions.ps1:46:17:46:18 | __pipeline_iterator | -| functions.ps1:50:9:50:12 | [Stmt] __pipeline_iterator | successor | functions.ps1:50:9:50:12 | sum | -| functions.ps1:50:9:50:12 | [Stmt] sum | successor | functions.ps1:46:17:46:18 | __pipeline_iterator | -| functions.ps1:50:9:50:12 | [Stmt] sum | successor | functions.ps1:50:9:50:12 | sum | +| functions.ps1:46:17:46:18 | __pipeline_iterator | successor | functions.ps1:44:5:47:5 | [synth] pipeline | +| functions.ps1:46:17:46:18 | __pipeline_iterator | successor | functions.ps1:48:5:51:5 | {...} | | loops.ps1:45:14:45:19 | ...+... | successor | loops.ps1:44:18:44:19 | i | | loops.ps1:45:14:45:19 | ...+... | successor | loops.ps1:44:29:44:39 | ...=... | simpleAndNormalSuccessors @@ -37,12 +21,4 @@ deadEnd nonUniqueSplitKind nonUniqueListOrder multipleToString -| functions.ps1:8:5:8:23 | [Stmt] ...+... | [Stmt] ...+...,[Stmt] __pipeline_iterator | -| functions.ps1:8:5:8:23 | [Stmt] __pipeline_iterator | [Stmt] ...+...,[Stmt] __pipeline_iterator | -| functions.ps1:19:5:19:18 | [Stmt] ...+... | [Stmt] ...+...,[Stmt] __pipeline_iterator | -| functions.ps1:19:5:19:18 | [Stmt] __pipeline_iterator | [Stmt] ...+...,[Stmt] __pipeline_iterator | -| functions.ps1:33:5:33:8 | [Stmt] __pipeline_iterator | [Stmt] __pipeline_iterator,[Stmt] sum | -| functions.ps1:33:5:33:8 | [Stmt] sum | [Stmt] __pipeline_iterator,[Stmt] sum | -| functions.ps1:50:9:50:12 | [Stmt] __pipeline_iterator | [Stmt] __pipeline_iterator,[Stmt] sum | -| functions.ps1:50:9:50:12 | [Stmt] sum | [Stmt] __pipeline_iterator,[Stmt] sum | scopeNoFirst diff --git a/powershell/ql/test/library-tests/dataflow/local/flow.expected b/powershell/ql/test/library-tests/dataflow/local/flow.expected index e7aa288529cb..c436626f9186 100644 --- a/powershell/ql/test/library-tests/dataflow/local/flow.expected +++ b/powershell/ql/test/library-tests/dataflow/local/flow.expected @@ -1,9 +1,9 @@ | 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:24:22 | implicit unwrapping of {...} | test.ps1:1:1:24:22 | return value for {...} | +| test.ps1:1:1:24:22 | pre-return value for {...} | test.ps1:1:1:24:22 | 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: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:2:1:2:8 | Call to Sink | test.ps1:1:1:24:22 | pre-return value for {...} | +| test.ps1:2:1:2:8 | Call to Sink | test.ps1:1:1:24:22 | 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 | phi | test.ps1:8:6:8:8 | a2 | @@ -11,27 +11,31 @@ | 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: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:8:1:8:8 | Call to Sink | test.ps1:1:1:24:22 | pre-return value for {...} | +| test.ps1:8:1:8:8 | Call to Sink | test.ps1:1:1:24:22 | 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: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:1:11:7 | Call to Sink | test.ps1:1:1:24:22 | pre-return value for {...} | +| test.ps1:11:1:11:7 | Call to Sink | test.ps1:1:1:24:22 | 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: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:1:14:7 | Call to Sink | test.ps1:1:1:24:22 | pre-return value for {...} | +| test.ps1:14:1:14:7 | Call to Sink | test.ps1:1:1:24:22 | 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: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:17:1:17:7 | Call to Sink | test.ps1:1:1:24:22 | pre-return value for {...} | +| test.ps1:17:1:17:7 | Call to Sink | test.ps1:1:1:24:22 | 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: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:1:21:27 | Call to Sink | test.ps1:1:1:24:22 | pre-return value for {...} | +| test.ps1:21:1:21:27 | Call to Sink | test.ps1:1:1:24:22 | pre-return value for {...} | +| test.ps1:23:1:23:6 | input | test.ps1:24:17:24:22 | input | +| test.ps1:23:10:23:32 | Call to Read-Host | test.ps1:23:1:23:6 | input | +| test.ps1:24:1:24:22 | Call to Sink | test.ps1:1:1:24:22 | pre-return value for {...} | +| test.ps1:24:1:24:22 | Call to Sink | test.ps1:1:1:24:22 | 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 381f685afbdf..7e6eeb95740a 100644 --- a/powershell/ql/test/library-tests/dataflow/local/taint.expected +++ b/powershell/ql/test/library-tests/dataflow/local/taint.expected @@ -1,10 +1,10 @@ | 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:1:24:22 | implicit unwrapping of {...} | test.ps1:1:1:24:22 | return value for {...} | +| test.ps1:1:1:24:22 | pre-return value for {...} | test.ps1:1:1:24:22 | implicit unwrapping of {...} | +| test.ps1:1:1:24:22 | pre-return value for {...} | test.ps1:1:1:24:22 | 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: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:2:1:2:8 | Call to Sink | test.ps1:1:1:24:22 | pre-return value for {...} | +| test.ps1:2:1:2:8 | Call to Sink | test.ps1:1:1:24:22 | 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 | phi | test.ps1:8:6:8:8 | a2 | @@ -12,30 +12,34 @@ | 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: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:8:1:8:8 | Call to Sink | test.ps1:1:1:24:22 | pre-return value for {...} | +| test.ps1:8:1:8:8 | Call to Sink | test.ps1:1:1:24:22 | 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: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:1:11:7 | Call to Sink | test.ps1:1:1:24:22 | pre-return value for {...} | +| test.ps1:11:1:11:7 | Call to Sink | test.ps1:1:1:24:22 | 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: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:1:14:7 | Call to Sink | test.ps1:1:1:24:22 | pre-return value for {...} | +| test.ps1:14:1:14:7 | Call to Sink | test.ps1:1:1:24:22 | 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: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:17:1:17:7 | Call to Sink | test.ps1:1:1:24:22 | pre-return value for {...} | +| test.ps1:17:1:17:7 | Call to Sink | test.ps1:1:1:24:22 | 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: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:1:21:27 | Call to Sink | test.ps1:1:1:24:22 | pre-return value for {...} | +| test.ps1:21:1:21:27 | Call to Sink | test.ps1:1:1:24:22 | pre-return value for {...} | | test.ps1:21:25:21:26 | f | test.ps1:21:6:21:27 | here is a string: $f | +| test.ps1:23:1:23:6 | input | test.ps1:24:17:24:22 | input | +| test.ps1:23:10:23:32 | Call to Read-Host | test.ps1:23:1:23:6 | input | +| test.ps1:24:1:24:22 | Call to Sink | test.ps1:1:1:24:22 | pre-return value for {...} | +| test.ps1:24:1:24:22 | Call to Sink | test.ps1:1:1:24:22 | pre-return value for {...} | diff --git a/powershell/ql/test/library-tests/dataflow/local/test.ps1 b/powershell/ql/test/library-tests/dataflow/local/test.ps1 index 4e18ffb1f11a..ae64ad05b4fb 100644 --- a/powershell/ql/test/library-tests/dataflow/local/test.ps1 +++ b/powershell/ql/test/library-tests/dataflow/local/test.ps1 @@ -18,4 +18,7 @@ Sink $e $f = Source -Sink "here is a string: $f" \ No newline at end of file +Sink "here is a string: $f" + +$input = Read-Host "enter input" +Sink -UserInput $input \ No newline at end of file diff --git a/powershell/ql/test/library-tests/dataflow/pipeline/test.expected b/powershell/ql/test/library-tests/dataflow/pipeline/test.expected index bbea92282028..5e3b383e7cc9 100644 --- a/powershell/ql/test/library-tests/dataflow/pipeline/test.expected +++ b/powershell/ql/test/library-tests/dataflow/pipeline/test.expected @@ -1,17 +1,87 @@ models edges +| test.ps1:2:10:2:19 | Call to Source | test.ps1:5:5:5:6 | x | provenance | | +| test.ps1:3:10:3:19 | Call to Source | test.ps1:6:5:6:6 | y | provenance | | +| test.ps1:4:10:4:19 | Call to Source | test.ps1:6:9:6:10 | z | provenance | | +| test.ps1:5:5:5:6 | x | test.ps1:17:1:17:7 | Call to produce [element] | provenance | | +| test.ps1:6:5:6:6 | y | test.ps1:17:1:17:7 | Call to produce [element] | provenance | | +| test.ps1:6:9:6:10 | z | test.ps1:17:1:17:7 | Call to produce [element] | provenance | | +| test.ps1:9:29:15:1 | [synth] pipeline [element 0] | test.ps1:12:5:14:5 | [synth] pipeline [element 0] | provenance | | +| test.ps1:9:29:15:1 | [synth] pipeline [element 1] | test.ps1:12:5:14:5 | [synth] pipeline [element 1] | provenance | | +| test.ps1:9:29:15:1 | [synth] pipeline [element] | test.ps1:12:5:14:5 | [synth] pipeline [element] | provenance | | +| test.ps1:12:5:14:5 | [synth] pipeline [element 0] | test.ps1:13:9:13:15 | __pipeline_iterator | provenance | | +| test.ps1:12:5:14:5 | [synth] pipeline [element 1] | test.ps1:13:9:13:15 | __pipeline_iterator | provenance | | +| test.ps1:12:5:14:5 | [synth] pipeline [element] | test.ps1:13:9:13:15 | __pipeline_iterator | provenance | | +| test.ps1:17:1:17:7 | Call to produce [element] | test.ps1:9:29:15:1 | [synth] pipeline [element] | provenance | | +| test.ps1:17:1:17:7 | Call to produce [element] | test.ps1:17:1:17:7 | Call to produce [element] | provenance | | +| test.ps1:19:6:19:15 | Call to Source | test.ps1:21:1:21:2 | x | provenance | | +| test.ps1:20:6:20:15 | Call to Source | test.ps1:21:5:21:6 | y | provenance | | +| test.ps1:21:1:21:2 | x | test.ps1:21:1:21:6 | ...,... [element 0] | provenance | | +| test.ps1:21:1:21:6 | ...,... [element 0] | test.ps1:9:29:15:1 | [synth] pipeline [element 0] | provenance | | +| test.ps1:21:1:21:6 | ...,... [element 0] | test.ps1:21:1:21:6 | ...,... [element 0] | provenance | | +| test.ps1:21:1:21:6 | ...,... [element 1] | test.ps1:9:29:15:1 | [synth] pipeline [element 1] | provenance | | +| test.ps1:21:1:21:6 | ...,... [element 1] | test.ps1:21:1:21:6 | ...,... [element 1] | provenance | | +| test.ps1:21:5:21:6 | y | test.ps1:21:1:21:6 | ...,... [element 1] | provenance | | +| test.ps1:23:38:27:1 | [synth] pipeline [element 0] | test.ps1:24:5:26:5 | [synth] pipeline [element 0] | provenance | | +| test.ps1:23:38:27:1 | [synth] pipeline [element 1] | test.ps1:24:5:26:5 | [synth] pipeline [element 1] | provenance | | +| test.ps1:24:5:26:5 | [synth] pipeline [element 0] | test.ps1:25:9:25:15 | __pipeline_iterator | provenance | | +| test.ps1:24:5:26:5 | [synth] pipeline [element 1] | test.ps1:25:9:25:15 | __pipeline_iterator | provenance | | +| test.ps1:29:6:29:15 | Call to Source | test.ps1:31:1:31:2 | x | provenance | | +| test.ps1:30:6:30:15 | Call to Source | test.ps1:31:5:31:6 | y | provenance | | +| test.ps1:31:1:31:2 | x | test.ps1:31:1:31:6 | ...,... [element 0] | provenance | | +| test.ps1:31:1:31:6 | ...,... [element 0] | test.ps1:23:38:27:1 | [synth] pipeline [element 0] | provenance | | +| test.ps1:31:1:31:6 | ...,... [element 0] | test.ps1:31:1:31:6 | ...,... [element 0] | provenance | | +| test.ps1:31:1:31:6 | ...,... [element 1] | test.ps1:23:38:27:1 | [synth] pipeline [element 1] | provenance | | +| test.ps1:31:1:31:6 | ...,... [element 1] | test.ps1:31:1:31:6 | ...,... [element 1] | provenance | | +| test.ps1:31:5:31:6 | y | test.ps1:31:1:31:6 | ...,... [element 1] | provenance | | nodes +| test.ps1:2:10:2:19 | Call to Source | semmle.label | Call to Source | +| test.ps1:3:10:3:19 | Call to Source | semmle.label | Call to Source | +| test.ps1:4:10:4:19 | Call to Source | semmle.label | Call to Source | +| test.ps1:5:5:5:6 | x | semmle.label | x | +| test.ps1:6:5:6:6 | y | semmle.label | y | +| test.ps1:6:9:6:10 | z | semmle.label | z | +| test.ps1:9:29:15:1 | [synth] pipeline [element 0] | semmle.label | [synth] pipeline [element 0] | +| test.ps1:9:29:15:1 | [synth] pipeline [element 1] | semmle.label | [synth] pipeline [element 1] | +| test.ps1:9:29:15:1 | [synth] pipeline [element] | semmle.label | [synth] pipeline [element] | +| test.ps1:12:5:14:5 | [synth] pipeline [element 0] | semmle.label | [synth] pipeline [element 0] | +| test.ps1:12:5:14:5 | [synth] pipeline [element 1] | semmle.label | [synth] pipeline [element 1] | +| test.ps1:12:5:14:5 | [synth] pipeline [element] | semmle.label | [synth] pipeline [element] | +| test.ps1:13:9:13:15 | __pipeline_iterator | semmle.label | __pipeline_iterator | +| test.ps1:17:1:17:7 | Call to produce [element] | semmle.label | Call to produce [element] | +| test.ps1:17:1:17:7 | Call to produce [element] | semmle.label | Call to produce [element] | +| test.ps1:19:6:19:15 | Call to Source | semmle.label | Call to Source | +| test.ps1:20:6:20:15 | Call to Source | semmle.label | Call to Source | +| test.ps1:21:1:21:2 | x | semmle.label | x | +| test.ps1:21:1:21:6 | ...,... [element 0] | semmle.label | ...,... [element 0] | +| test.ps1:21:1:21:6 | ...,... [element 0] | semmle.label | ...,... [element 0] | +| test.ps1:21:1:21:6 | ...,... [element 1] | semmle.label | ...,... [element 1] | +| test.ps1:21:1:21:6 | ...,... [element 1] | semmle.label | ...,... [element 1] | +| test.ps1:21:5:21:6 | y | semmle.label | y | +| test.ps1:23:38:27:1 | [synth] pipeline [element 0] | semmle.label | [synth] pipeline [element 0] | +| test.ps1:23:38:27:1 | [synth] pipeline [element 1] | semmle.label | [synth] pipeline [element 1] | +| test.ps1:24:5:26:5 | [synth] pipeline [element 0] | semmle.label | [synth] pipeline [element 0] | +| test.ps1:24:5:26:5 | [synth] pipeline [element 1] | semmle.label | [synth] pipeline [element 1] | +| test.ps1:25:9:25:15 | __pipeline_iterator | semmle.label | __pipeline_iterator | +| test.ps1:29:6:29:15 | Call to Source | semmle.label | Call to Source | +| test.ps1:30:6:30:15 | Call to Source | semmle.label | Call to Source | +| test.ps1:31:1:31:2 | x | semmle.label | x | +| test.ps1:31:1:31:6 | ...,... [element 0] | semmle.label | ...,... [element 0] | +| test.ps1:31:1:31:6 | ...,... [element 0] | semmle.label | ...,... [element 0] | +| test.ps1:31:1:31:6 | ...,... [element 1] | semmle.label | ...,... [element 1] | +| test.ps1:31:1:31:6 | ...,... [element 1] | semmle.label | ...,... [element 1] | +| test.ps1:31:5:31:6 | y | semmle.label | y | subpaths testFailures -| test.ps1:13:17:13:94 | # $ hasValueFlow=1 hasValueFlow=2 hasValueFlow=3 hasValueFlow=4 hasValueFlow=5 | Missing result: hasValueFlow=1 | -| test.ps1:13:17:13:94 | # $ hasValueFlow=1 hasValueFlow=2 hasValueFlow=3 hasValueFlow=4 hasValueFlow=5 | Missing result: hasValueFlow=2 | -| test.ps1:13:17:13:94 | # $ hasValueFlow=1 hasValueFlow=2 hasValueFlow=3 hasValueFlow=4 hasValueFlow=5 | Missing result: hasValueFlow=3 | -| test.ps1:13:17:13:94 | # $ hasValueFlow=1 hasValueFlow=2 hasValueFlow=3 hasValueFlow=4 hasValueFlow=5 | Missing result: hasValueFlow=4 | -| test.ps1:13:17:13:94 | # $ hasValueFlow=1 hasValueFlow=2 hasValueFlow=3 hasValueFlow=4 hasValueFlow=5 | Missing result: hasValueFlow=5 | -| test.ps1:25:17:25:49 | # $ hasValueFlow=6 hasValueFlow=7 | Missing result: hasValueFlow=6 | -| test.ps1:25:17:25:49 | # $ hasValueFlow=6 hasValueFlow=7 | Missing result: hasValueFlow=7 | | test.ps1:36:13:36:30 | # $ hasValueFlow=8 | Missing result: hasValueFlow=8 | | test.ps1:46:17:46:66 | # $ hasValueFlow=9 hasValueFlow=10 hasValueFlow=11 | Missing result: hasValueFlow=9 | | test.ps1:46:17:46:66 | # $ hasValueFlow=9 hasValueFlow=10 hasValueFlow=11 | Missing result: hasValueFlow=10 | | test.ps1:46:17:46:66 | # $ hasValueFlow=9 hasValueFlow=10 hasValueFlow=11 | Missing result: hasValueFlow=11 | #select +| test.ps1:13:9:13:15 | __pipeline_iterator | test.ps1:2:10:2:19 | Call to Source | test.ps1:13:9:13:15 | __pipeline_iterator | $@ | test.ps1:2:10:2:19 | Call to Source | Call to Source | +| test.ps1:13:9:13:15 | __pipeline_iterator | test.ps1:3:10:3:19 | Call to Source | test.ps1:13:9:13:15 | __pipeline_iterator | $@ | test.ps1:3:10:3:19 | Call to Source | Call to Source | +| test.ps1:13:9:13:15 | __pipeline_iterator | test.ps1:4:10:4:19 | Call to Source | test.ps1:13:9:13:15 | __pipeline_iterator | $@ | test.ps1:4:10:4:19 | Call to Source | Call to Source | +| test.ps1:13:9:13:15 | __pipeline_iterator | test.ps1:19:6:19:15 | Call to Source | test.ps1:13:9:13:15 | __pipeline_iterator | $@ | test.ps1:19:6:19:15 | Call to Source | Call to Source | +| test.ps1:13:9:13:15 | __pipeline_iterator | test.ps1:20:6:20:15 | Call to Source | test.ps1:13:9:13:15 | __pipeline_iterator | $@ | test.ps1:20:6:20:15 | Call to Source | Call to Source | +| test.ps1:25:9:25:15 | __pipeline_iterator | test.ps1:29:6:29:15 | Call to Source | test.ps1:25:9:25:15 | __pipeline_iterator | $@ | test.ps1:29:6:29:15 | Call to Source | Call to Source | +| test.ps1:25:9:25:15 | __pipeline_iterator | test.ps1:30:6:30:15 | Call to Source | test.ps1:25:9:25:15 | __pipeline_iterator | $@ | test.ps1:30:6:30:15 | Call to Source | Call to Source | diff --git a/powershell/ql/test/library-tests/ssa/ssa.expected b/powershell/ql/test/library-tests/ssa/ssa.expected index 1cfa0788bbc6..b7615522d8ed 100644 --- a/powershell/ql/test/library-tests/ssa/ssa.expected +++ b/powershell/ql/test/library-tests/ssa/ssa.expected @@ -1,6 +1,6 @@ | explicit.ps1:5:5:5:6 | a | explicit.ps1:5:5:5:6 | a | | explicit.ps1:6:5:6:6 | b | explicit.ps1:6:5:6:6 | b | -| parameters.ps1:1:45:3:1 | n1 | parameters.ps1:1:45:3:1 | n1 | -| parameters.ps1:1:45:3:1 | n2 | parameters.ps1:1:45:3:1 | n2 | -| parameters.ps1:5:22:11:1 | a | parameters.ps1:5:22:11:1 | a | -| parameters.ps1:5:22:11:1 | b | parameters.ps1:5:22:11:1 | b | +| parameters.ps1:1:45:3:1 | n1 | parameters.ps1:1:45:3:1 | n1 | +| parameters.ps1:1:45:3:1 | n2 | parameters.ps1:1:45:3:1 | n2 | +| parameters.ps1:5:22:11:1 | a | parameters.ps1:5:22:11:1 | a | +| parameters.ps1:5:22:11:1 | b | parameters.ps1:5:22:11:1 | b |