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 df29eb7f516d..4acc6683d767 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/ChildIndex.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/ChildIndex.qll @@ -33,11 +33,14 @@ newtype ChildIndex = } or ThisVar() or PipelineParamVar() or - // PipelineByPropertNameVar(Raw::PipelineByPropertyNameParameter p) or + PipelineByPropertyNameVar(Raw::PipelineByPropertyNameParameter p) or PipelineIteratorVar() or PipelineByPropertyNameIteratorVar(Raw::PipelineByPropertyNameParameter p) or RealVar(string name) { name = variableNameInScope(_, _) } or - ProcessBlockPipelineVarReadAccess() + ProcessBlockPipelineVarReadAccess() or + ProcessBlockPipelineByPropertyNameVarReadAccess(string name) { + name = any(Raw::PipelineByPropertyNameParameter p).getName() + } int synthPipelineParameterChildIndex(Raw::ScriptBlock sb) { // If there is a parameter block, but no pipeline parameter @@ -340,3 +343,7 @@ ChildIndex whileStmtCond() { result = RawChildIndex(Raw::WhileStmtCond()) } ChildIndex whileStmtBody() { result = RawChildIndex(Raw::WhileStmtBody()) } ChildIndex processBlockPipelineVarReadAccess() { result = ProcessBlockPipelineVarReadAccess() } + +ChildIndex processBlockPipelineByPropertyNameVarReadAccess(string name) { + result = ProcessBlockPipelineByPropertyNameVarReadAccess(name) +} 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 10da368db65e..5e721df9de14 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/NamedBlock.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/NamedBlock.qll @@ -58,7 +58,20 @@ class ProcessBlock extends NamedBlock { synthChild(getRawAst(this), processBlockPipelineVarReadAccess(), result) } + PipelineByPropertyNameParameter getPipelineByPropertyNameParameter(string name) { + result = scriptBlock.getAParameter() and + result.getPropertyName() = name + } + PipelineByPropertyNameParameter getAPipelineByPropertyNameParameter() { - result = scriptBlock.getEnclosingFunction().getAParameter() + result = this.getPipelineByPropertyNameParameter(_) + } + + VarReadAccess getPipelineByPropertyNameParameterAccess(string name) { + synthChild(getRawAst(this), processBlockPipelineByPropertyNameVarReadAccess(name), result) + } + + VarReadAccess getAPipelineByPropertyNameParameterAccess() { + result = this.getPipelineByPropertyNameParameterAccess(_) } } 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 30356666b25f..2fee3dd99d6a 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/Synthesis.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Synthesis.qll @@ -615,7 +615,7 @@ private module LiteralSynth { /** * Holds if `va` is an access to the automatic variable named `name`. - * + * * Unlike `Raw::isAutomaticVariableAccess`, this predicate also checks for * shadowing. */ @@ -770,6 +770,13 @@ private module IteratorAccessSynth { or va.getUserPath().toLowerCase() = pb.getScriptBlock().getParamBlock().getPipelineParameter().getName().toLowerCase() + or + va.getUserPath().toLowerCase() = + pb.getScriptBlock() + .getParamBlock() + .getAPipelineByPropertyNameParameter() + .getName() + .toLowerCase() ) } @@ -867,12 +874,19 @@ private module PipelineAccess { pipelineVar = TVariableSynth(pb.getScriptBlock(), PipelineParamVar()) and child = SynthChild(VarAccessSynthKind(pipelineVar)) ) + or + exists(PipelineByPropertyNameVariable pipelineVar, Raw::PipelineByPropertyNameParameter p | + i = processBlockPipelineByPropertyNameVarReadAccess(p.getName()) and + getResultAst(p) = pipelineVar and + child = SynthChild(VarAccessSynthKind(pipelineVar)) + ) ) } final override Location getLocation(Ast n) { exists(ProcessBlock pb | - pb.getPipelineParameterAccess() = n and + pb.getPipelineParameterAccess() = n or pb.getAPipelineByPropertyNameParameterAccess() = n + | result = pb.getLocation() ) } @@ -881,6 +895,23 @@ private module PipelineAccess { exists(ProcessBlock pb | pb.getPipelineParameterAccess() = va and v = pb.getPipelineParameter() + or + exists(string name | + pb.getPipelineByPropertyNameParameterAccess(name) = va and + v = pb.getPipelineByPropertyNameParameter(name) + ) + ) + } + } +} + +private module ImplicitAssignmentInForEach { + private class ForEachAssignment extends Synthesis { + override predicate implicitAssignment(Raw::Ast dest, string name) { + exists(Raw::ForEachStmt forEach, Raw::VarAccess va | + va = forEach.getVarAccess() and + va = dest and + va.getUserPath() = name ) } } diff --git a/powershell/ql/lib/semmle/code/powershell/ast/internal/Variable.qll b/powershell/ql/lib/semmle/code/powershell/ast/internal/Variable.qll index c843a4ac52a7..c1d0a53edfbb 100644 --- a/powershell/ql/lib/semmle/code/powershell/ast/internal/Variable.qll +++ b/powershell/ql/lib/semmle/code/powershell/ast/internal/Variable.qll @@ -45,7 +45,9 @@ module Private { class ParameterImpl extends VariableSynth { ParameterImpl() { - i instanceof FunParam or i instanceof PipelineParamVar or i instanceof ThisVar + i instanceof FunParam or + i instanceof PipelineParamVar or + i instanceof ThisVar } } @@ -59,6 +61,14 @@ module Private { ScriptBlock getScriptBlock() { this = TVariableSynth(getRawAst(result), _) } } + class PipelineByPropertyNameVariableImpl extends ParameterImpl { + PipelineByPropertyNameVariableImpl() { + getRawAst(this) instanceof Raw::PipelineByPropertyNameParameter + } + + ScriptBlock getScriptBlock() { this = TVariableSynth(getRawAst(result), _) } + } + class PipelineIteratorVariableImpl extends VariableSynth { override PipelineIteratorVar i; @@ -171,6 +181,11 @@ module Public { ScriptBlock getScriptBlock() { result = super.getScriptBlock() } } + class PipelineByPropertyNameVariable extends Variable instanceof PipelineByPropertyNameVariableImpl + { + ScriptBlock getScriptBlock() { result = super.getScriptBlock() } + } + class PipelineIteratorVariable extends Variable instanceof PipelineIteratorVariableImpl { ProcessBlock getProcessBlock() { result = super.getProcessBlock() } } diff --git a/powershell/ql/lib/semmle/code/powershell/controlflow/CfgNodes.qll b/powershell/ql/lib/semmle/code/powershell/controlflow/CfgNodes.qll index c8126a68ab97..58ca40b5e714 100644 --- a/powershell/ql/lib/semmle/code/powershell/controlflow/CfgNodes.qll +++ b/powershell/ql/lib/semmle/code/powershell/controlflow/CfgNodes.qll @@ -277,6 +277,8 @@ private class ProcessBlockChildMapping extends NamedBlockChildMapping, ProcessBl super.relevantChild(child) or child = super.getPipelineParameterAccess() + or + child = super.getAPipelineByPropertyNameParameterAccess() } } @@ -300,6 +302,23 @@ class ProcessBlockCfgNode extends NamedBlockCfgNode { PipelineIteratorVariable getPipelineIteratorVariable() { result.getProcessBlock().getScriptBlock() = this.getScriptBlock().getAstNode() } + + PipelineByPropertyNameIteratorVariable getPipelineBypropertyNameIteratorVariable(string name) { + result.getPropertyName() = name and + result.getProcessBlock().getScriptBlock() = this.getScriptBlock().getAstNode() + } + + PipelineByPropertyNameIteratorVariable getAPipelineBypropertyNameIteratorVariable() { + result = this.getPipelineBypropertyNameIteratorVariable(_) + } + + ExprNodes::VarReadAccessCfgNode getPipelineByPropertyNameParameterAccess(string name) { + block.hasCfgChild(block.getPipelineByPropertyNameParameterAccess(name), this, result) + } + + ExprNodes::VarReadAccessCfgNode getAPipelineByPropertyNameParameterAccess() { + result = this.getPipelineByPropertyNameParameterAccess(_) + } } private class CatchClauseChildMapping extends NonExprChildMapping, CatchClause { diff --git a/powershell/ql/lib/semmle/code/powershell/controlflow/internal/Completion.qll b/powershell/ql/lib/semmle/code/powershell/controlflow/internal/Completion.qll index 68b602dfd93e..d551b674fbad 100644 --- a/powershell/ql/lib/semmle/code/powershell/controlflow/internal/Completion.qll +++ b/powershell/ql/lib/semmle/code/powershell/controlflow/internal/Completion.qll @@ -188,7 +188,11 @@ private predicate inMatchingContext(Ast n) { * Holds if a normal completion of `cfe` must be an emptiness completion. Thats is, * whether `cfe` determines whether to execute the body of a `foreach` statement. */ -private predicate mustHaveEmptinessCompletion(Ast n) { n instanceof ForEachStmt } +private predicate mustHaveEmptinessCompletion(Ast n) { + n instanceof ForEachStmt + or + any(CfgImpl::Trees::ProcessBlockTree pbtree).lastEmptinessCheck(n) +} /** * A completion that represents normal evaluation of a statement or an 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 d28828481f56..e9c5c4862e4d 100644 --- a/powershell/ql/lib/semmle/code/powershell/controlflow/internal/ControlFlowGraphImpl.qll +++ b/powershell/ql/lib/semmle/code/powershell/controlflow/internal/ControlFlowGraphImpl.qll @@ -221,13 +221,7 @@ module Trees { or last(super.getProcessBlock(), pred, c) and completionIsNormal(c) and - ( - // If we process multiple items we will loop back to the process block - first(super.getProcessBlock(), succ) - or - // Once we're done process all items we will go to the end block - first(super.getEndBlock(), succ) - ) + first(super.getEndBlock(), succ) } final override predicate propagatesAbnormal(AstNode child) { @@ -292,25 +286,17 @@ module Trees { final override predicate succEntry(Ast n, Completion c) { n = this and completionIsSimple(c) } } - abstract class NamedBlockTreeBase extends ControlFlowTree instanceof NamedBlock { - final override predicate last(Ast last, Completion c) { + abstract class NamedBlockTreeBase extends PreOrderTree instanceof NamedBlock { + 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 @@ -324,20 +310,85 @@ module Trees { class NamedBlockTree extends NamedBlockTreeBase instanceof NamedBlock { NamedBlockTree() { not this instanceof ProcessBlock } - final override predicate first(Ast first) { first = this } + final override predicate last(Ast last, Completion c) { + super.last(last, c) + or + not exists(super.getAStmt()) and + completionIsSimple(c) and + last = this + } + + final override predicate succ(Ast pred, Ast succ, Completion c) { + pred = this and + completionIsSimple(c) and + first(super.getStmt(0), succ) + or + super.succ(pred, succ, c) + } final override predicate propagatesAbnormal(Ast child) { super.propagatesAbnormal(child) } } + private VarAccess getRankedPipelineByPropertyNameVariable(ProcessBlock pb, int i) { + result = + rank[i + 1](string name | | pb.getPipelineByPropertyNameParameterAccess(name) order by name) + } + class ProcessBlockTree extends NamedBlockTreeBase instanceof ProcessBlock { - final override predicate first(Ast first) { first = super.getPipelineParameterAccess() } + predicate lastEmptinessCheck(AstNode last) { + last = super.getPipelineParameterAccess() and + not exists(super.getAPipelineByPropertyNameParameterAccess()) + or + exists(int i | + last = getRankedPipelineByPropertyNameVariable(this, i) and + not exists(getRankedPipelineByPropertyNameVariable(this, i + 1)) + ) + } + + private predicate succEmptinessCheck(AstNode pred, AstNode succ, Completion c) { + last(super.getPipelineParameterAccess(), pred, c) and + first(getRankedPipelineByPropertyNameVariable(this, 0), succ) + or + exists(int i | + last(getRankedPipelineByPropertyNameVariable(this, i), pred, c) and + first(getRankedPipelineByPropertyNameVariable(this, i + 1), succ) + ) + } + + private predicate firstEmptinessCheck(AstNode first) { + first(super.getPipelineParameterAccess(), first) + } + + final override predicate last(AstNode last, Completion c) { + // Emptiness test exits with no more elements + this.lastEmptinessCheck(last) and + c.(EmptinessCompletion).isEmpty() + or + super.last(last, c) + } final override predicate succ(Ast pred, Ast succ, Completion c) { - this.first(pred) and - completionIsSimple(c) and - succ = this + // Evaluate the pipeline access + pred = this and + this.firstEmptinessCheck(succ) and + completionIsSimple(c) + or + this.succEmptinessCheck(pred, succ, c) + or + this.lastEmptinessCheck(pred) and + c = any(EmptinessCompletion ec | not ec.isEmpty()) and + first(super.getStmt(0), succ) or super.succ(pred, succ, c) + or + // Body to emptiness test + exists(Ast last0 | + super.last(last0, _) and + last(last0, pred, c) and + // TODO: I don't think this correctly models the semantics inside process blocks + c.continuesLoop() + ) and + this.firstEmptinessCheck(succ) } final override predicate propagatesAbnormal(Ast child) { super.propagatesAbnormal(child) } diff --git a/powershell/ql/lib/semmle/code/powershell/dataflow/Ssa.qll b/powershell/ql/lib/semmle/code/powershell/dataflow/Ssa.qll index 212936b3643d..0d1b37283265 100644 --- a/powershell/ql/lib/semmle/code/powershell/dataflow/Ssa.qll +++ b/powershell/ql/lib/semmle/code/powershell/dataflow/Ssa.qll @@ -158,7 +158,7 @@ module Ssa { not exists(this.getSplitString()) and prefix = "" | - result = prefix + "phi" + result = prefix + "phi (" + this.getSourceVariable() + ")" ) } 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 f408d2ed44a4..a2437f884010 100644 --- a/powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowPrivate.qll +++ b/powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowPrivate.qll @@ -66,6 +66,8 @@ module SsaFlow { result = TThisParameterNode(p.asThis()) or result = TPipelineParameterNode(p.asPipelineParameter()) + or + result = TPipelineByPropertyNameParameterNode(p.asPipelineByPropertyNameParameter()) } /** Gets the SSA node corresponding to the PowerShell node `n`. */ @@ -83,6 +85,16 @@ module SsaFlow { .definesAt(pb.getPipelineIteratorVariable(), bb, i) ) or + exists( + BasicBlock bb, int i, PipelineByPropertyNameParameter p, ProcessPropertyByNameNode pbNode + | + pbNode = n and + pbNode.hasRead() and + pbNode.getParameter() = p and + bb.getNode(i) = pbNode.getProcessBlock() and + result.(Impl::SsaDefinitionNode).getDefinition().definesAt(p.getIteratorVariable(), bb, i) + ) + or result.(Impl::ExprPostUpdateNode).getExpr() = n.(PostUpdateNode).getPreUpdateNode().asExpr() or n = toParameterNode(result.(Impl::ParameterNode).getParameter()) @@ -145,13 +157,16 @@ module LocalFlow { 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) + nodeTo.(PreProcessPropertyByNameNode).getAccess() = nodeFrom.asExpr() + or + exists(PreProcessPropertyByNameNode pbNode | + pbNode = nodeFrom and + nodeTo = TProcessPropertyByNameNode(pbNode.getAccess().getVariable(), false) ) + or + nodeTo.(PreProcessNode).getProcessBlock().getPipelineVariableAccess() = nodeFrom.asExpr() + or + nodeTo.(ProcessNode).getProcessBlock() = nodeFrom.(PreProcessNode).getProcessBlock() } predicate flowSummaryLocalStep( @@ -179,12 +194,6 @@ module VariableCapture { // TODO } -private predicate isProcessPropertyByNameNode( - PipelineByPropertyNameIteratorVariable iter, ProcessBlock pb -) { - pb = iter.getProcessBlock() -} - /** A collection of cached types and predicates to be evaluated in the same stage. */ cached private module Cached { @@ -198,8 +207,6 @@ private module Cached { TThisParameterNode(Method m) or TPipelineByPropertyNameParameterNode(PipelineByPropertyNameParameter 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 @@ -220,9 +227,13 @@ private module Cached { blockMayReturnMultipleValues(scriptBlock) } or TReturnNodeImpl(CfgScope scope) or + TPreProcessNode(CfgNodes::ProcessBlockCfgNode process) or TProcessNode(CfgNodes::ProcessBlockCfgNode process) or - TProcessPropertyByNameNode(PipelineByPropertyNameIteratorVariable iter) { - isProcessPropertyByNameNode(iter, _) + TPreProcessPropertyByNameNode(CfgNodes::ExprNodes::VarReadAccessCfgNode va) { + any(CfgNodes::ProcessBlockCfgNode pb).getAPipelineByPropertyNameParameterAccess() = va + } or + TProcessPropertyByNameNode(PipelineByPropertyNameParameter p, Boolean hasRead) { + p.getDeclaringScope() = any(ProcessBlock pb).getScriptBlock() } or TScriptBlockNode(ScriptBlock scriptBlock) or TForbiddenRecursionGuard() { @@ -333,15 +344,13 @@ private module Cached { cached newtype TContentSet = - TSingletonContent(Content c) or - TAnyElementContent() or - TKnownOrUnknownElementContent(Content::KnownElementContent c) - - private predicate trackKnownValue(ConstantValue cv) { - exists(cv.asString()) - or - cv.asInt() = [0 .. 10] - } + TSingletonContentSet(Content c) or + TAnyElementContentSet() or + TAnyPositionalContentSet() or + TKnownOrUnknownKeyContentSet(Content::KnownKeyContent c) or + TKnownOrUnknownPositionalContentSet(Content::KnownPositionalContent c) or + TUnknownPositionalElementContentSet() or + TUnknownKeyContentSet() cached newtype TContent = @@ -350,20 +359,41 @@ private module Cached { or name = any(MemberExpr me).getMemberName() } or - TKnownElementContent(ConstantValue cv) { trackKnownValue(cv) } or - TUnknownElementContent() + // A known map key + TKnownKeyContent(ConstantValue cv) { exists(cv.asString()) } or + // A known array index + TKnownPositionalContent(ConstantValue cv) { cv.asInt() = [0 .. 10] } or + // An unknown key + TUnknownKeyContent() or + // An unknown positional element + TUnknownPositionalContent() or + // A unknown position or key - and we dont even know what kind it is + TUnknownKeyOrPositionContent() cached newtype TContentApprox = + // A field TNonElementContentApprox(Content c) { not c instanceof Content::ElementContent } or - TUnknownElementContentApprox() or - TKnownIntegerElementContentApprox() or - TKnownElementContentApprox(string approx) { approx = approxKnownElementIndex(_) } + // An unknown key + TUnkownKeyContentApprox() or + // A known map key + TKnownKeyContentApprox(string approx) { approx = approxKnownElementIndex(_) } or + // A known positional element + TKnownPositionalContentApprox() or + // An unknown positional element + TUnknownPositionalContentApprox() or + TUnknownContentApprox() cached newtype TDataFlowType = TUnknownDataFlowType() } +class TKnownElementContent = TKnownKeyContent or TKnownPositionalContent; + +class TKnownKindContent = TUnknownPositionalContent or TUnknownKeyContent; + +class TUnknownElementContent = TKnownKindContent or TUnknownKeyOrPositionContent; + class TElementContent = TKnownElementContent or TUnknownElementContent; /** Gets a string for approximating known element indices. */ @@ -623,10 +653,10 @@ private module ParameterNodes { PipelineByPropertyNameParameterNode() { this = TPipelineByPropertyNameParameterNode(parameter) } - override PipelineParameter getParameter() { result = parameter } + override PipelineByPropertyNameParameter getParameter() { result = parameter } override predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) { - pos.isPipeline() and // what about when it is applied as a normal parameter? + pos.isPipeline() and c.asCfgScope() = parameter.getEnclosingScope() } @@ -690,22 +720,6 @@ 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; @@ -749,23 +763,15 @@ module ArgumentNodes { } } - class PipelineArgumentNodeImpl extends NodeImpl, TPipelineArgumentNode { - CfgNodes::ExprNodes::PipelineArgumentCfgNode e; - - PipelineArgumentNodeImpl() { this = TPipelineArgumentNode(e) } - - 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() } + class PipelineArgumentNode extends ArgumentNode instanceof ExprNode { + PipelineArgumentNode() { + this.getExprNode() instanceof CfgNodes::ExprNodes::PipelineArgumentCfgNode + } - CfgNodes::ExprNodes::PipelineArgumentCfgNode getPipelineArgument() { result = e } - } + CfgNodes::ExprNodes::PipelineArgumentCfgNode getPipelineArgument() { + result = super.getExprNode() + } - class PipelineArgumentNode extends ArgumentNode instanceof PipelineArgumentNodeImpl { override predicate argumentOf(DataFlowCall call, ArgumentPosition pos) { this.sourceArgumentOf(call.asCall(), pos) } @@ -773,7 +779,7 @@ module ArgumentNodes { override predicate sourceArgumentOf( CfgNodes::ExprNodes::CallExprCfgNode call, ArgumentPosition pos ) { - call = super.getPipelineArgument().getCall() and + call = this.getPipelineArgument().getCall() and pos.isPipeline() } } @@ -923,7 +929,7 @@ predicate storeStep(Node node1, ContentSet c, Node node2) { e.getValue() = ec.getIndex() ) or - not exists(e.getValue().asInt()) and + not exists(Content::KnownElementContent ec | ec.getIndex() = e.getValue()) and c.isAnyElement() ) or @@ -931,7 +937,7 @@ predicate storeStep(Node node1, ContentSet c, Node node2) { e = node1.asExpr() and not arrayExprStore(node1, _, _, e) and node2.asExpr().(CfgNodes::ExprNodes::ArrayLiteralCfgNode).getExpr(index) = e and - c.isKnownOrUnknownElement(ec) and + c.isKnownOrUnknownPositional(ec) and index = ec.getIndex().asInt() ) or @@ -939,32 +945,32 @@ predicate storeStep(Node node1, ContentSet c, Node node2) { node2.asExpr().(CfgNodes::ExprNodes::HashTableExprCfgNode).getValueFromKey(key) = node1.asExpr() | exists(Content::KnownElementContent ec | - c.isKnownOrUnknownElement(ec) and - ec.getIndex() = key.getValue() + c.isKnownOrUnknownKeyContent(ec) and + key.getValue() = ec.getIndex() ) or - not exists(key.getValue()) and - c.isAnyElement() + not exists(Content::KnownKeyContent ec | ec.getIndex() = key.getValue()) and + c.isUnknownKeyContent() ) or arrayExprStore(node1, c, node2, _) or - c.isAnyElement() and + c.isUnknownPositionalContent() and exists(CfgNode cfgNode | node1 = TPreReturnNodeImpl(cfgNode, false) and node2.(ReturnNodeImpl).getCfgScope() = cfgNode.getScope() ) or - c.isAnyElement() and + c.isUnknownPositionalContent() and exists(CfgNode cfgNode | node1 = TImplicitWrapNode(cfgNode, true) and node2.(ReturnNodeImpl).getCfgScope() = cfgNode.getScope() ) or - c.isAnyElement() and - exists(CfgNodes::ExprNodes::PipelineArgumentCfgNode arg | - node1 = TPrePipelineArgumentNode(arg) and - node2 = TPipelineArgumentNode(arg) + c.isUnknownPositionalContent() and + exists(CfgNodes::ProcessBlockCfgNode process | + node1 = TPreProcessNode(process) and + node2 = TProcessNode(process) ) or FlowSummaryImpl::Private::Steps::summaryStoreStep(node1.(FlowSummaryNode).getSummaryNode(), c, @@ -992,7 +998,7 @@ predicate readStep(Node node1, ContentSet c, Node node2) { e.getValue() = ec.getIndex() ) or - not exists(e.getValue()) and + not exists(Content::KnownElementContent ec | ec.getIndex() = e.getValue()) and c.isAnyElement() ) or @@ -1002,27 +1008,24 @@ predicate readStep(Node node1, ContentSet c, Node node2) { c.isSingleton(any(Content::KnownElementContent ec | exists(ec.getIndex().asInt()))) ) or - c.isAnyElement() and + c.isAnyPositional() and exists(CfgNodes::ProcessBlockCfgNode processBlock | processBlock.getPipelineVariableAccess() = node1.asExpr() and node2 = TProcessNode(processBlock) ) or - exists( - Content::KnownElementContent ec, PipelineByPropertyNameParameter p, SsaImpl::DefinitionExt def - | - c.isSingleton(ec) and - p.getIteratorVariable() = node1.(ProcessPropertyByNameNode).getVariable() and - p.getName() = ec.getIndex().asString() and - def.getSourceVariable() = p.getIteratorVariable() and - SsaImpl::firstRead(def, node2.asExpr()) + c.isAnyPositional() and + exists(CfgNodes::ProcessBlockCfgNode pb, CfgNodes::ExprNodes::VarReadAccessCfgNode va | + va = pb.getAPipelineByPropertyNameParameterAccess() and + node1.asExpr() = va and + node2 = TProcessPropertyByNameNode(va.getVariable(), false) ) or - exists(Content::KnownElementContent ec, SsaImpl::DefinitionExt def | - c.isSingleton(ec) and - node1.(PipelineByPropertyNameParameterNode).getPropertyName() = ec.getIndex().asString() and - def = SsaImpl::getParameterDef(node1.(PipelineByPropertyNameParameterNode).getParameter()) and - SsaImpl::firstRead(def, node2.asExpr()) + exists(PipelineByPropertyNameParameter p, Content::KnownElementContent ec | + c.isKnownOrUnknownElement(ec) and + ec.getIndex().asString() = p.getPropertyName() and + node1 = TProcessPropertyByNameNode(p, false) and + node2 = TProcessPropertyByNameNode(p, true) ) or FlowSummaryImpl::Private::Steps::summaryReadStep(node1.(FlowSummaryNode).getSummaryNode(), c, @@ -1043,8 +1046,11 @@ predicate clearsContent(Node n, ContentSet c) { n = TPreReturnNodeImpl(_, false) and c.isAnyElement() or - n instanceof PrePipelineArgumentNodeImpl and - c.isAnyElement() + c.isAnyPositional() and + n instanceof PreProcessPropertyByNameNode + or + c.isAnyPositional() and + n instanceof PreProcessNode } /** @@ -1059,9 +1065,6 @@ predicate expectsContent(Node n, ContentSet c) { or n = TImplicitWrapNode(_, false) and c.isSingleton(any(Content::UnknownElementContent ec)) - or - n instanceof PipelineArgumentNode and - c.isAnyElement() } class DataFlowType extends TDataFlowType { @@ -1191,6 +1194,22 @@ private class ReturnNodeImpl extends TReturnNodeImpl, NodeImpl { override predicate nodeIsHidden() { any() } } +private class PreProcessNode extends TPreProcessNode, NodeImpl { + CfgNodes::ProcessBlockCfgNode process; + + PreProcessNode() { this = TPreProcessNode(process) } + + override CfgScope getCfgScope() { result = process.getScope() } + + override Location getLocationImpl() { result = process.getLocation() } + + override string toStringImpl() { result = "pre-process node for " + process.toString() } + + override predicate nodeIsHidden() { any() } + + CfgNodes::ProcessBlockCfgNode getProcessBlock() { result = process } +} + private class ProcessNode extends TProcessNode, NodeImpl { CfgNodes::ProcessBlockCfgNode process; @@ -1211,26 +1230,53 @@ private class ProcessNode extends TProcessNode, NodeImpl { CfgNodes::ProcessBlockCfgNode getProcessBlock() { result = process } } -private class ProcessPropertyByNameNode extends TProcessPropertyByNameNode, NodeImpl { - private PipelineByPropertyNameIteratorVariable iter; +private class PreProcessPropertyByNameNode extends TPreProcessPropertyByNameNode, NodeImpl { + private CfgNodes::ExprNodes::VarReadAccessCfgNode va; - ProcessPropertyByNameNode() { this = TProcessPropertyByNameNode(iter) } + PreProcessPropertyByNameNode() { this = TPreProcessPropertyByNameNode(va) } - PipelineByPropertyNameIteratorVariable getVariable() { result = iter } + CfgNodes::ExprNodes::VarReadAccessCfgNode getAccess() { result = va } - override CfgScope getCfgScope() { result = iter.getDeclaringScope() } + override CfgScope getCfgScope() { result = va.getScope() } - override Location getLocationImpl() { result = iter.getLocation() } + override Location getLocationImpl() { result = this.getProcessBlock().getLocation() } - override string toStringImpl() { result = "process node for " + iter.toString() } + override string toStringImpl() { result = "pre-process node for " + va.toString() } override predicate nodeIsHidden() { any() } CfgNodes::ProcessBlockCfgNode getProcessBlock() { - isProcessPropertyByNameNode(iter, result.getAstNode()) + result.getAPipelineByPropertyNameParameterAccess() = va } } +private class ProcessPropertyByNameNode extends TProcessPropertyByNameNode, NodeImpl { + private PipelineByPropertyNameParameter p; + private boolean hasRead; + + ProcessPropertyByNameNode() { this = TProcessPropertyByNameNode(p, hasRead) } + + PipelineByPropertyNameParameter getParameter() { result = p } + + override CfgScope getCfgScope() { result = p.getDeclaringScope() } + + override Location getLocationImpl() { result = this.getProcessBlock().getLocation() } + + override string toStringImpl() { + hasRead = false and + result = "process node for " + p.toString() + or + hasRead = true and + result = "[has read] process node for " + p.toString() + } + + override predicate nodeIsHidden() { any() } + + CfgNodes::ProcessBlockCfgNode getProcessBlock() { result.getScope().getAParameter() = p } + + predicate hasRead() { hasRead = true } +} + class ScriptBlockNode extends TScriptBlockNode, NodeImpl { private ScriptBlock scriptBlock; @@ -1338,18 +1384,38 @@ class ContentApprox extends TContentApprox { /** Gets an approximated value for content `c`. */ ContentApprox getContentApprox(Content c) { - c instanceof Content::UnknownElementContent and - result = TUnknownElementContentApprox() + c instanceof Content::KnownPositionalContent and + result = TKnownPositionalContentApprox() or - exists(c.(Content::KnownElementContent).getIndex().asInt()) and - result = TKnownIntegerElementContentApprox() - or - result = - TKnownElementContentApprox(approxKnownElementIndex(c.(Content::KnownElementContent).getIndex())) + result = TKnownKeyContentApprox(approxKnownElementIndex(c.(Content::KnownKeyContent).getIndex())) or result = TNonElementContentApprox(c) + or + c instanceof Content::UnknownKeyContent and + result = TUnkownKeyContentApprox() + or + c instanceof Content::UnknownPositionalContent and + result = TUnknownPositionalContentApprox() + or + c instanceof Content::UnknownKeyOrPositionContent and + result = TUnknownContentApprox() } +// TFieldContent(string name) { +// name = any(PropertyMember member).getName() +// or +// name = any(MemberExpr me).getMemberName() +// } or +// // A known map key +// TKnownKeyContent(ConstantValue cv) { exists(cv.asString()) } or +// // A known array index +// TKnownPositionalContent(ConstantValue cv) { cv.asInt() = [0 .. 10] } or +// // An unknown key +// TUnknownKeyContent() or +// // An unknown positional element +// TUnknownPositionalContent() or +// // A unknown position or key - and we dont even know what kind it is +// TUnknownKeyOrPositionContent() /** * A unit class for adding additional jump steps. * diff --git a/powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowPublic.qll b/powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowPublic.qll index 7848fb6e2a7d..28cfd4ed3040 100644 --- a/powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowPublic.qll +++ b/powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowPublic.qll @@ -255,21 +255,43 @@ module Content { /** An element in a collection, for example an element in an array or in a hash. */ class ElementContent extends Content, TElementContent { } - /** An element in a collection at a known index. */ - class KnownElementContent extends ElementContent, TKnownElementContent { - private ConstantValue cv; - - KnownElementContent() { this = TKnownElementContent(cv) } + abstract class KnownElementContent extends ElementContent, TKnownElementContent { + ConstantValue cv; /** Gets the index in the collection. */ - ConstantValue getIndex() { result = cv } + final ConstantValue getIndex() { result = cv } override string toString() { result = "element " + cv } } - /** An element in a collection at an unknown index. */ - class UnknownElementContent extends ElementContent, TUnknownElementContent { - override string toString() { result = "element" } + /** An element in a collection at a known index. */ + class KnownKeyContent extends KnownElementContent, TKnownKeyContent { + KnownKeyContent() { this = TKnownKeyContent(cv) } + } + + /** An element in a collection at a known index. */ + class KnownPositionalContent extends KnownElementContent, TKnownPositionalContent { + KnownPositionalContent() { this = TKnownPositionalContent(cv) } + } + + class UnknownElementContent extends ElementContent, TUnknownElementContent { } + + class UnknownKeyContent extends UnknownElementContent, TUnknownKeyContent { + UnknownKeyContent() { this = TUnknownKeyContent() } + + override string toString() { result = "unknown map key" } + } + + class UnknownPositionalContent extends UnknownElementContent, TUnknownPositionalContent { + UnknownPositionalContent() { this = TUnknownPositionalContent() } + + override string toString() { result = "unknown index" } + } + + class UnknownKeyOrPositionContent extends UnknownElementContent, TUnknownKeyOrPositionContent { + UnknownKeyOrPositionContent() { this = TUnknownKeyOrPositionContent() } + + override string toString() { result = "unknown" } } /** A field of an object. */ @@ -285,20 +307,18 @@ module Content { } /** Gets the element content corresponding to constant value `cv`. */ - ElementContent getElementContent(ConstantValue cv) { - result = TKnownElementContent(cv) + KnownElementContent getKnownElementContent(ConstantValue cv) { + result = TKnownPositionalContent(cv) or - not exists(TKnownElementContent(cv)) and - result = TUnknownElementContent() + result = TKnownKeyContent(cv) } /** * Gets the constant value of `e`, which corresponds to a valid known - * element index. Unlike calling simply `e.getConstantValue()`, this - * excludes negative array indices. + * element index. */ ConstantValue getKnownElementIndex(Expr e) { - result = getElementContent(e.getValue()).(KnownElementContent).getIndex() + result = getKnownElementContent(e.getValue()).getIndex() } } @@ -310,19 +330,31 @@ module Content { */ class ContentSet extends TContentSet { /** Holds if this content set is the singleton `{c}`. */ - predicate isSingleton(Content c) { this = TSingletonContent(c) } + predicate isSingleton(Content c) { this = TSingletonContentSet(c) } - /** Holds if this content set represents all `ElementContent`s. */ - predicate isAnyElement() { this = TAnyElementContent() } + predicate isKnownOrUnknownKeyContent(Content::KnownKeyContent c) { + this = TKnownOrUnknownKeyContentSet(c) + } + + predicate isKnownOrUnknownPositional(Content::KnownPositionalContent c) { + this = TKnownOrUnknownPositionalContentSet(c) + } - /** - * Holds if this content set represents a specific known element index, or an - * unknown element index. - */ predicate isKnownOrUnknownElement(Content::KnownElementContent c) { - this = TKnownOrUnknownElementContent(c) + this.isKnownOrUnknownKeyContent(c) + or + this.isKnownOrUnknownPositional(c) } + predicate isUnknownPositionalContent() { this = TUnknownPositionalElementContentSet() } + + predicate isUnknownKeyContent() { this = TUnknownKeyContentSet() } + + predicate isAnyElement() { this = TAnyElementContentSet() } + + predicate isAnyPositional() { this = TAnyPositionalContentSet() } + + // predicate isPipelineContentSet() { this = TPipelineContentSet() } /** Gets a textual representation of this content set. */ string toString() { exists(Content c | @@ -330,15 +362,25 @@ class ContentSet extends TContentSet { result = c.toString() ) or - this.isAnyElement() and - result = "any element" - or exists(Content::KnownElementContent c | this.isKnownOrUnknownElement(c) and - result = c + " or unknown" + result = c.toString() + " or unknown" ) + or + this.isUnknownPositionalContent() and + result = "unknown positional" + or + this.isUnknownKeyContent() and + result = "unknown key" + or + this.isAnyPositional() and + result = "any positional" + or + this.isAnyElement() and + result = "any element" } + /** Gets a content that may be stored into when storing into this set. */ Content getAStoreContent() { this.isSingleton(result) or @@ -346,20 +388,25 @@ class ContentSet extends TContentSet { // from `a` to `a[unknown]` (which can read any element), gets translated into // a reverse store step that store only into `?` this.isAnyElement() and - result = TUnknownElementContent() + result = TUnknownKeyOrPositionContent() or // For reverse stores, `a[1][0] = x`, it is important that the read-step // from `a` to `a[1]` (which can read both elements stored at exactly index `1` // and elements stored at unknown index), gets translated into a reverse store // step that store only into `1` this.isKnownOrUnknownElement(result) - } - - pragma[nomagic] - private Content getAnElementReadContent() { - exists(Content::KnownElementContent c | this.isKnownOrUnknownElement(c) | - result = c or - result = TUnknownElementContent() + or + this.isUnknownPositionalContent() and + result = TUnknownPositionalContent() + or + this.isUnknownKeyContent() and + result = TUnknownKeyContent() + or + this.isAnyPositional() and + ( + result instanceof Content::KnownPositionalContent + or + result = TUnknownPositionalContent() ) } @@ -370,7 +417,36 @@ class ContentSet extends TContentSet { this.isAnyElement() and result instanceof Content::ElementContent or - result = this.getAnElementReadContent() + exists(Content::KnownElementContent c | + this.isKnownOrUnknownKeyContent(c) and + ( + result = c + or + result = TUnknownKeyContent() + or + result = TUnknownKeyOrPositionContent() + ) + or + this.isKnownOrUnknownPositional(c) and + ( + result = c or + result = TUnknownPositionalContent() or + result = TUnknownKeyOrPositionContent() + ) + ) + or + this.isUnknownPositionalContent() and + result = TUnknownPositionalContent() + or + this.isUnknownKeyContent() and + result = TUnknownKeyContent() + or + this.isAnyPositional() and + ( + result instanceof Content::KnownPositionalContent + or + result = TUnknownPositionalContent() + ) } } diff --git a/powershell/ql/lib/semmle/code/powershell/dataflow/internal/FlowSummaryImpl.qll b/powershell/ql/lib/semmle/code/powershell/dataflow/internal/FlowSummaryImpl.qll index b5f8d7beeacd..93cffe4a250b 100644 --- a/powershell/ql/lib/semmle/code/powershell/dataflow/internal/FlowSummaryImpl.qll +++ b/powershell/ql/lib/semmle/code/powershell/dataflow/internal/FlowSummaryImpl.qll @@ -52,22 +52,24 @@ module Input implements InputSig { or variableWriteActual(bb, i, v, _) or - exists(ProcessBlockCfgNode processBlock | - bb.getNode(i) = processBlock and + exists(ProcessBlockCfgNode processBlock | bb.getNode(i) = processBlock | processBlock.getPipelineIteratorVariable() = v + or + processBlock.getAPipelineBypropertyNameIteratorVariable() = v ) or parameterWrite(bb, i, v) @@ -301,7 +302,8 @@ class NormalParameter extends Parameter { private newtype TParameterExt = TNormalParameter(NormalParameter p) or TThisMethodParameter(Method m) or - TPipelineParameter(PipelineParameter p) + TPipelineParameter(PipelineParameter p) or + TPipelineByPropertyNameParameter(PipelineByPropertyNameParameter p) /** A normal parameter or an implicit `this` parameter. */ class ParameterExt extends TParameterExt { @@ -311,11 +313,17 @@ class ParameterExt extends TParameterExt { PipelineParameter asPipelineParameter() { this = TPipelineParameter(result) } + PipelineByPropertyNameParameter asPipelineByPropertyNameParameter() { + this = TPipelineByPropertyNameParameter(result) + } + predicate isInitializedBy(WriteDefinition def) { def = getParameterDef(this.asParameter()) or def = getParameterDef(this.asPipelineParameter()) or + def = getParameterDef(this.asPipelineByPropertyNameParameter()) + or def.(Ssa::ThisDefinition).getSourceVariable().getDeclaringScope() = this.asThis().getBody() } @@ -323,7 +331,7 @@ class ParameterExt extends TParameterExt { result = [ this.asParameter().toString(), this.asThis().toString(), - this.asPipelineParameter().toString() + this.asPipelineParameter().toString(), this.asPipelineByPropertyNameParameter().toString() ] } @@ -331,7 +339,8 @@ class ParameterExt extends TParameterExt { result = [ this.asParameter().getLocation(), this.asThis().getLocation(), - this.asPipelineParameter().getLocation() + this.asPipelineParameter().getLocation(), + this.asPipelineByPropertyNameParameter().getLocation() ] } } diff --git a/powershell/ql/test/library-tests/controlflow/graph/Cfg.expected b/powershell/ql/test/library-tests/controlflow/graph/Cfg.expected index ea88eea58ae6..51cfda6735d2 100644 --- a/powershell/ql/test/library-tests/controlflow/graph/Cfg.expected +++ b/powershell/ql/test/library-tests/controlflow/graph/Cfg.expected @@ -271,8 +271,14 @@ | 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:29:14:29:20 | number | non-empty | | functions.ps1:29:5:32:5 | forach(... in ...) | functions.ps1:33:5:33:8 | [Stmt] sum | empty | +| functions.ps1:29:14:29:20 | number | functions.ps1:29:35:32:5 | {...} | | | functions.ps1:29:25:29:32 | numbers | functions.ps1:29:5:32:5 | forach(... in ...) | | +| functions.ps1:29:35:32:5 | {...} | functions.ps1:31:9:31:23 | ...=... | | +| functions.ps1:31:9:31:12 | sum | functions.ps1:31:17:31:23 | number | | +| functions.ps1:31:9:31:23 | ...=... | functions.ps1:31:9:31:12 | sum | | +| functions.ps1:31:17:31:23 | number | functions.ps1:29:5:32:5 | forach(... in ...) | | | functions.ps1:33:5:33:8 | [Stmt] sum | functions.ps1:33:5:33:8 | sum | | | 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) | | @@ -284,9 +290,10 @@ | 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 | [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:42:16:42:16 | 0 | functions.ps1:44:5:47:5 | {...} | | +| functions.ps1:44:5:47:5 | [synth] pipeline | functions.ps1:46:9:46:18 | ...=... | non-empty | +| functions.ps1:44:5:47:5 | [synth] pipeline | functions.ps1:48:5:51:5 | {...} | empty | +| functions.ps1:44:5:47:5 | {...} | functions.ps1:44:5:47:5 | [synth] pipeline | | | 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:44:5:47:5 | [synth] pipeline | | @@ -452,7 +459,15 @@ | loops.ps1:51:5:51:10 | ...=... | loops.ps1:51:5:51:6 | a | | | loops.ps1:51:10:51:10 | 0 | loops.ps1:52:25:52:36 | letterArray | | | loops.ps1:52:5:55:5 | forach(... in ...) | loops.ps1:49:23:56:1 | exit {...} (normal) | empty | +| loops.ps1:52:5:55:5 | forach(... in ...) | loops.ps1:52:14:52:20 | letter | non-empty | +| loops.ps1:52:14:52:20 | letter | loops.ps1:53:5:55:5 | {...} | | | loops.ps1:52:25:52:36 | letterArray | loops.ps1:52:5:55:5 | forach(... in ...) | | +| loops.ps1:53:5:55:5 | {...} | loops.ps1:54:9:54:19 | ...=... | | +| loops.ps1:54:9:54:10 | a | loops.ps1:54:14:54:15 | a | | +| loops.ps1:54:9:54:19 | ...=... | loops.ps1:54:9:54:10 | a | | +| loops.ps1:54:14:54:15 | a | loops.ps1:54:19:54:19 | 1 | | +| loops.ps1:54:14:54:19 | ...+... | loops.ps1:52:5:55:5 | forach(... in ...) | | +| loops.ps1:54:19:54:19 | 1 | loops.ps1:54:14:54:19 | ...+... | | | 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 | {...} | | diff --git a/powershell/ql/test/library-tests/dataflow/fields/test.expected b/powershell/ql/test/library-tests/dataflow/fields/test.expected index 0908f093abc0..0f9350477142 100644 --- a/powershell/ql/test/library-tests/dataflow/fields/test.expected +++ b/powershell/ql/test/library-tests/dataflow/fields/test.expected @@ -6,33 +6,33 @@ edges | test.ps1:10:1:10:5 | [post] arr1 [element 3] | test.ps1:11:6:11:10 | arr1 [element 3] | provenance | | | test.ps1:10:12:10:21 | Call to Source | test.ps1:10:1:10:5 | [post] arr1 [element 3] | provenance | | | test.ps1:11:6:11:10 | arr1 [element 3] | test.ps1:11:6:11:13 | ...[...] | provenance | | -| test.ps1:14:1:14:5 | [post] arr2 [element] | test.ps1:15:6:15:10 | arr2 [element] | provenance | | -| test.ps1:14:19:14:28 | Call to Source | test.ps1:14:1:14:5 | [post] arr2 [element] | provenance | | -| test.ps1:15:6:15:10 | arr2 [element] | test.ps1:15:6:15:13 | ...[...] | provenance | | +| test.ps1:14:1:14:5 | [post] arr2 [unknown] | test.ps1:15:6:15:10 | arr2 [unknown] | provenance | | +| test.ps1:14:19:14:28 | Call to Source | test.ps1:14:1:14:5 | [post] arr2 [unknown] | provenance | | +| test.ps1:15:6:15:10 | arr2 [unknown] | test.ps1:15:6:15:13 | ...[...] | provenance | | | test.ps1:17:1:17:5 | [post] arr3 [element 3] | test.ps1:18:6:18:10 | arr3 [element 3] | provenance | | | test.ps1:17:12:17:21 | Call to Source | test.ps1:17:1:17:5 | [post] arr3 [element 3] | provenance | | | test.ps1:18:6:18:10 | arr3 [element 3] | test.ps1:18:6:18:20 | ...[...] | provenance | | -| test.ps1:20:1:20:5 | [post] arr4 [element] | test.ps1:21:6:21:10 | arr4 [element] | provenance | | -| test.ps1:20:20:20:29 | Call to Source | test.ps1:20:1:20:5 | [post] arr4 [element] | provenance | | -| test.ps1:21:6:21:10 | arr4 [element] | test.ps1:21:6:21:21 | ...[...] | provenance | | -| test.ps1:23:1:23:5 | [post] arr5 [element, element 1] | test.ps1:24:6:24:10 | arr5 [element, element 1] | provenance | | -| test.ps1:23:1:23:16 | [post] ...[...] [element 1] | test.ps1:23:1:23:5 | [post] arr5 [element, element 1] | provenance | | +| test.ps1:20:1:20:5 | [post] arr4 [unknown] | test.ps1:21:6:21:10 | arr4 [unknown] | provenance | | +| test.ps1:20:20:20:29 | Call to Source | test.ps1:20:1:20:5 | [post] arr4 [unknown] | provenance | | +| test.ps1:21:6:21:10 | arr4 [unknown] | test.ps1:21:6:21:21 | ...[...] | provenance | | +| test.ps1:23:1:23:5 | [post] arr5 [unknown, element 1] | test.ps1:24:6:24:10 | arr5 [unknown, element 1] | provenance | | +| test.ps1:23:1:23:16 | [post] ...[...] [element 1] | test.ps1:23:1:23:5 | [post] arr5 [unknown, element 1] | provenance | | | test.ps1:23:23:23:32 | Call to Source | test.ps1:23:1:23:16 | [post] ...[...] [element 1] | provenance | | -| test.ps1:24:6:24:10 | arr5 [element, element 1] | test.ps1:24:6:24:21 | ...[...] [element 1] | provenance | | +| test.ps1:24:6:24:10 | arr5 [unknown, element 1] | test.ps1:24:6:24:21 | ...[...] [element 1] | provenance | | | test.ps1:24:6:24:21 | ...[...] [element 1] | test.ps1:24:6:24:24 | ...[...] | provenance | | -| test.ps1:27:1:27:5 | [post] arr6 [element 1, element] | test.ps1:28:6:28:10 | arr6 [element 1, element] | provenance | | -| test.ps1:27:1:27:8 | [post] ...[...] [element] | test.ps1:27:1:27:5 | [post] arr6 [element 1, element] | provenance | | -| test.ps1:27:23:27:32 | Call to Source | test.ps1:27:1:27:8 | [post] ...[...] [element] | provenance | | -| test.ps1:28:6:28:10 | arr6 [element 1, element] | test.ps1:28:6:28:13 | ...[...] [element] | provenance | | -| test.ps1:28:6:28:13 | ...[...] [element] | test.ps1:28:6:28:24 | ...[...] | provenance | | -| test.ps1:31:1:31:5 | [post] arr7 [element, element] | test.ps1:32:6:32:10 | arr7 [element, element] | provenance | | -| test.ps1:31:1:31:5 | [post] arr7 [element, element] | test.ps1:33:6:33:10 | arr7 [element, element] | provenance | | -| test.ps1:31:1:31:16 | [post] ...[...] [element] | test.ps1:31:1:31:5 | [post] arr7 [element, element] | provenance | | -| test.ps1:31:31:31:40 | Call to Source | test.ps1:31:1:31:16 | [post] ...[...] [element] | provenance | | -| test.ps1:32:6:32:10 | arr7 [element, element] | test.ps1:32:6:32:13 | ...[...] [element] | provenance | | -| test.ps1:32:6:32:13 | ...[...] [element] | test.ps1:32:6:32:16 | ...[...] | provenance | | -| test.ps1:33:6:33:10 | arr7 [element, element] | test.ps1:33:6:33:21 | ...[...] [element] | provenance | | -| test.ps1:33:6:33:21 | ...[...] [element] | test.ps1:33:6:33:32 | ...[...] | provenance | | +| test.ps1:27:1:27:5 | [post] arr6 [element 1, unknown] | test.ps1:28:6:28:10 | arr6 [element 1, unknown] | provenance | | +| test.ps1:27:1:27:8 | [post] ...[...] [unknown] | test.ps1:27:1:27:5 | [post] arr6 [element 1, unknown] | provenance | | +| test.ps1:27:23:27:32 | Call to Source | test.ps1:27:1:27:8 | [post] ...[...] [unknown] | provenance | | +| test.ps1:28:6:28:10 | arr6 [element 1, unknown] | test.ps1:28:6:28:13 | ...[...] [unknown] | provenance | | +| test.ps1:28:6:28:13 | ...[...] [unknown] | test.ps1:28:6:28:24 | ...[...] | provenance | | +| test.ps1:31:1:31:5 | [post] arr7 [unknown, unknown] | test.ps1:32:6:32:10 | arr7 [unknown, unknown] | provenance | | +| test.ps1:31:1:31:5 | [post] arr7 [unknown, unknown] | test.ps1:33:6:33:10 | arr7 [unknown, unknown] | provenance | | +| test.ps1:31:1:31:16 | [post] ...[...] [unknown] | test.ps1:31:1:31:5 | [post] arr7 [unknown, unknown] | provenance | | +| test.ps1:31:31:31:40 | Call to Source | test.ps1:31:1:31:16 | [post] ...[...] [unknown] | provenance | | +| test.ps1:32:6:32:10 | arr7 [unknown, unknown] | test.ps1:32:6:32:13 | ...[...] [unknown] | provenance | | +| test.ps1:32:6:32:13 | ...[...] [unknown] | test.ps1:32:6:32:16 | ...[...] | provenance | | +| test.ps1:33:6:33:10 | arr7 [unknown, unknown] | test.ps1:33:6:33:21 | ...[...] [unknown] | provenance | | +| test.ps1:33:6:33:21 | ...[...] [unknown] | test.ps1:33:6:33:32 | ...[...] | provenance | | | test.ps1:35:6:35:16 | Call to Source | test.ps1:37:15:37:16 | x | provenance | | | test.ps1:37:9:37:16 | ...,... [element 2] | test.ps1:40:6:40:10 | arr8 [element 2] | provenance | | | test.ps1:37:9:37:16 | ...,... [element 2] | test.ps1:41:6:41:10 | arr8 [element 2] | provenance | | @@ -53,15 +53,15 @@ edges | test.ps1:66:10:66:20 | Call to Source | test.ps1:69:5:69:6 | x | provenance | | | test.ps1:67:10:67:20 | Call to Source | test.ps1:70:5:70:6 | y | provenance | | | test.ps1:68:10:68:20 | Call to Source | test.ps1:70:9:70:10 | z | provenance | | -| test.ps1:69:5:69:6 | x | test.ps1:73:6:73:12 | Call to produce [element] | provenance | | -| test.ps1:70:5:70:6 | y | test.ps1:73:6:73:12 | Call to produce [element] | provenance | | -| test.ps1:70:9:70:10 | z | test.ps1:73:6:73:12 | Call to produce [element] | provenance | | -| test.ps1:73:6:73:12 | Call to produce [element] | test.ps1:74:6:74:7 | x [element] | provenance | | -| test.ps1:73:6:73:12 | Call to produce [element] | test.ps1:75:6:75:7 | x [element] | provenance | | -| test.ps1:73:6:73:12 | Call to produce [element] | test.ps1:76:6:76:7 | x [element] | provenance | | -| test.ps1:74:6:74:7 | x [element] | test.ps1:74:6:74:10 | ...[...] | provenance | | -| test.ps1:75:6:75:7 | x [element] | test.ps1:75:6:75:10 | ...[...] | provenance | | -| test.ps1:76:6:76:7 | x [element] | test.ps1:76:6:76:10 | ...[...] | provenance | | +| test.ps1:69:5:69:6 | x | test.ps1:73:6:73:12 | Call to produce [unknown index] | provenance | | +| test.ps1:70:5:70:6 | y | test.ps1:73:6:73:12 | Call to produce [unknown index] | provenance | | +| test.ps1:70:9:70:10 | z | test.ps1:73:6:73:12 | Call to produce [unknown index] | provenance | | +| test.ps1:73:6:73:12 | Call to produce [unknown index] | test.ps1:74:6:74:7 | x [unknown index] | provenance | | +| test.ps1:73:6:73:12 | Call to produce [unknown index] | test.ps1:75:6:75:7 | x [unknown index] | provenance | | +| test.ps1:73:6:73:12 | Call to produce [unknown index] | test.ps1:76:6:76:7 | x [unknown index] | provenance | | +| test.ps1:74:6:74:7 | x [unknown index] | test.ps1:74:6:74:10 | ...[...] | provenance | | +| test.ps1:75:6:75:7 | x [unknown index] | test.ps1:75:6:75:10 | ...[...] | provenance | | +| test.ps1:76:6:76:7 | x [unknown index] | test.ps1:76:6:76:10 | ...[...] | provenance | | | test.ps1:78:9:81:1 | ${...} [element a] | test.ps1:83:6:83:10 | hash [element a] | provenance | | | test.ps1:78:9:81:1 | ${...} [element a] | test.ps1:87:6:87:10 | hash [element a] | provenance | | | test.ps1:79:7:79:17 | Call to Source | test.ps1:78:9:81:1 | ${...} [element a] | provenance | | @@ -79,38 +79,38 @@ nodes | test.ps1:10:12:10:21 | Call to Source | semmle.label | Call to Source | | test.ps1:11:6:11:10 | arr1 [element 3] | semmle.label | arr1 [element 3] | | test.ps1:11:6:11:13 | ...[...] | semmle.label | ...[...] | -| test.ps1:14:1:14:5 | [post] arr2 [element] | semmle.label | [post] arr2 [element] | +| test.ps1:14:1:14:5 | [post] arr2 [unknown] | semmle.label | [post] arr2 [unknown] | | test.ps1:14:19:14:28 | Call to Source | semmle.label | Call to Source | -| test.ps1:15:6:15:10 | arr2 [element] | semmle.label | arr2 [element] | +| test.ps1:15:6:15:10 | arr2 [unknown] | semmle.label | arr2 [unknown] | | test.ps1:15:6:15:13 | ...[...] | semmle.label | ...[...] | | test.ps1:17:1:17:5 | [post] arr3 [element 3] | semmle.label | [post] arr3 [element 3] | | test.ps1:17:12:17:21 | Call to Source | semmle.label | Call to Source | | test.ps1:18:6:18:10 | arr3 [element 3] | semmle.label | arr3 [element 3] | | test.ps1:18:6:18:20 | ...[...] | semmle.label | ...[...] | -| test.ps1:20:1:20:5 | [post] arr4 [element] | semmle.label | [post] arr4 [element] | +| test.ps1:20:1:20:5 | [post] arr4 [unknown] | semmle.label | [post] arr4 [unknown] | | test.ps1:20:20:20:29 | Call to Source | semmle.label | Call to Source | -| test.ps1:21:6:21:10 | arr4 [element] | semmle.label | arr4 [element] | +| test.ps1:21:6:21:10 | arr4 [unknown] | semmle.label | arr4 [unknown] | | test.ps1:21:6:21:21 | ...[...] | semmle.label | ...[...] | -| test.ps1:23:1:23:5 | [post] arr5 [element, element 1] | semmle.label | [post] arr5 [element, element 1] | +| test.ps1:23:1:23:5 | [post] arr5 [unknown, element 1] | semmle.label | [post] arr5 [unknown, element 1] | | test.ps1:23:1:23:16 | [post] ...[...] [element 1] | semmle.label | [post] ...[...] [element 1] | | test.ps1:23:23:23:32 | Call to Source | semmle.label | Call to Source | -| test.ps1:24:6:24:10 | arr5 [element, element 1] | semmle.label | arr5 [element, element 1] | +| test.ps1:24:6:24:10 | arr5 [unknown, element 1] | semmle.label | arr5 [unknown, element 1] | | test.ps1:24:6:24:21 | ...[...] [element 1] | semmle.label | ...[...] [element 1] | | test.ps1:24:6:24:24 | ...[...] | semmle.label | ...[...] | -| test.ps1:27:1:27:5 | [post] arr6 [element 1, element] | semmle.label | [post] arr6 [element 1, element] | -| test.ps1:27:1:27:8 | [post] ...[...] [element] | semmle.label | [post] ...[...] [element] | +| test.ps1:27:1:27:5 | [post] arr6 [element 1, unknown] | semmle.label | [post] arr6 [element 1, unknown] | +| test.ps1:27:1:27:8 | [post] ...[...] [unknown] | semmle.label | [post] ...[...] [unknown] | | test.ps1:27:23:27:32 | Call to Source | semmle.label | Call to Source | -| test.ps1:28:6:28:10 | arr6 [element 1, element] | semmle.label | arr6 [element 1, element] | -| test.ps1:28:6:28:13 | ...[...] [element] | semmle.label | ...[...] [element] | +| test.ps1:28:6:28:10 | arr6 [element 1, unknown] | semmle.label | arr6 [element 1, unknown] | +| test.ps1:28:6:28:13 | ...[...] [unknown] | semmle.label | ...[...] [unknown] | | test.ps1:28:6:28:24 | ...[...] | semmle.label | ...[...] | -| test.ps1:31:1:31:5 | [post] arr7 [element, element] | semmle.label | [post] arr7 [element, element] | -| test.ps1:31:1:31:16 | [post] ...[...] [element] | semmle.label | [post] ...[...] [element] | +| test.ps1:31:1:31:5 | [post] arr7 [unknown, unknown] | semmle.label | [post] arr7 [unknown, unknown] | +| test.ps1:31:1:31:16 | [post] ...[...] [unknown] | semmle.label | [post] ...[...] [unknown] | | test.ps1:31:31:31:40 | Call to Source | semmle.label | Call to Source | -| test.ps1:32:6:32:10 | arr7 [element, element] | semmle.label | arr7 [element, element] | -| test.ps1:32:6:32:13 | ...[...] [element] | semmle.label | ...[...] [element] | +| test.ps1:32:6:32:10 | arr7 [unknown, unknown] | semmle.label | arr7 [unknown, unknown] | +| test.ps1:32:6:32:13 | ...[...] [unknown] | semmle.label | ...[...] [unknown] | | test.ps1:32:6:32:16 | ...[...] | semmle.label | ...[...] | -| test.ps1:33:6:33:10 | arr7 [element, element] | semmle.label | arr7 [element, element] | -| test.ps1:33:6:33:21 | ...[...] [element] | semmle.label | ...[...] [element] | +| test.ps1:33:6:33:10 | arr7 [unknown, unknown] | semmle.label | arr7 [unknown, unknown] | +| test.ps1:33:6:33:21 | ...[...] [unknown] | semmle.label | ...[...] [unknown] | | test.ps1:33:6:33:32 | ...[...] | semmle.label | ...[...] | | test.ps1:35:6:35:16 | Call to Source | semmle.label | Call to Source | | test.ps1:37:9:37:16 | ...,... [element 2] | semmle.label | ...,... [element 2] | @@ -138,12 +138,12 @@ nodes | test.ps1:69:5:69:6 | x | semmle.label | x | | test.ps1:70:5:70:6 | y | semmle.label | y | | test.ps1:70:9:70:10 | z | semmle.label | z | -| test.ps1:73:6:73:12 | Call to produce [element] | semmle.label | Call to produce [element] | -| test.ps1:74:6:74:7 | x [element] | semmle.label | x [element] | +| test.ps1:73:6:73:12 | Call to produce [unknown index] | semmle.label | Call to produce [unknown index] | +| test.ps1:74:6:74:7 | x [unknown index] | semmle.label | x [unknown index] | | test.ps1:74:6:74:10 | ...[...] | semmle.label | ...[...] | -| test.ps1:75:6:75:7 | x [element] | semmle.label | x [element] | +| test.ps1:75:6:75:7 | x [unknown index] | semmle.label | x [unknown index] | | test.ps1:75:6:75:10 | ...[...] | semmle.label | ...[...] | -| test.ps1:76:6:76:7 | x [element] | semmle.label | x [element] | +| test.ps1:76:6:76:7 | x [unknown index] | semmle.label | x [unknown index] | | test.ps1:76:6:76:10 | ...[...] | semmle.label | ...[...] | | test.ps1:78:9:81:1 | ${...} [element a] | semmle.label | ${...} [element a] | | test.ps1:79:7:79:17 | Call to Source | semmle.label | Call to Source | diff --git a/powershell/ql/test/library-tests/dataflow/local/flow.expected b/powershell/ql/test/library-tests/dataflow/local/flow.expected index c436626f9186..b5b5ec1a1263 100644 --- a/powershell/ql/test/library-tests/dataflow/local/flow.expected +++ b/powershell/ql/test/library-tests/dataflow/local/flow.expected @@ -6,11 +6,11 @@ | 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 | +| test.ps1:5:1:7:1 | phi (a2) | test.ps1:8:6:8:8 | a2 | | test.ps1:5:4:5:5 | b | test.ps1:10:14:10:15 | b | -| test.ps1:6:5:6:7 | a2 | test.ps1:6:11:6:16 | [input] phi | +| test.ps1:6:5:6:7 | a2 | test.ps1:6:11:6:16 | [input] phi (a2) | | 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:6:11:6:16 | [input] phi (a2) | test.ps1:5:1:7:1 | phi (a2) | | 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 | diff --git a/powershell/ql/test/library-tests/dataflow/local/taint.expected b/powershell/ql/test/library-tests/dataflow/local/taint.expected index 7e6eeb95740a..cc15a9b83d17 100644 --- a/powershell/ql/test/library-tests/dataflow/local/taint.expected +++ b/powershell/ql/test/library-tests/dataflow/local/taint.expected @@ -7,11 +7,11 @@ | 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 | +| test.ps1:5:1:7:1 | phi (a2) | test.ps1:8:6:8:8 | a2 | | test.ps1:5:4:5:5 | b | test.ps1:10:14:10:15 | b | -| test.ps1:6:5:6:7 | a2 | test.ps1:6:11:6:16 | [input] phi | +| test.ps1:6:5:6:7 | a2 | test.ps1:6:11:6:16 | [input] phi (a2) | | 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:6:11:6:16 | [input] phi (a2) | test.ps1:5:1:7:1 | phi (a2) | | 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 | diff --git a/powershell/ql/test/library-tests/dataflow/pipeline/test.expected b/powershell/ql/test/library-tests/dataflow/pipeline/test.expected index 5e3b383e7cc9..b94675c879d6 100644 --- a/powershell/ql/test/library-tests/dataflow/pipeline/test.expected +++ b/powershell/ql/test/library-tests/dataflow/pipeline/test.expected @@ -3,24 +3,21 @@ 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:5:5:5:6 | x | test.ps1:17:1:17:7 | Call to produce [unknown index] | provenance | | +| test.ps1:6:5:6:6 | y | test.ps1:17:1:17:7 | Call to produce [unknown index] | provenance | | +| test.ps1:6:9:6:10 | z | test.ps1:17:1:17:7 | Call to produce [unknown index] | 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:9:29:15:1 | [synth] pipeline [unknown index] | test.ps1:12:5:14:5 | [synth] pipeline [unknown index] | 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:12:5:14:5 | [synth] pipeline [unknown index] | test.ps1:13:9:13:15 | __pipeline_iterator | provenance | | +| test.ps1:17:1:17:7 | Call to produce [unknown index] | test.ps1:9:29:15:1 | [synth] pipeline [unknown index] | 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 | | @@ -30,10 +27,26 @@ edges | 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 | | +| test.ps1:42:60:48:1 | x [element 0, element x] | test.ps1:45:5:47:5 | x [element 0, element x] | provenance | | +| test.ps1:42:60:48:1 | x [element 1, element x] | test.ps1:45:5:47:5 | x [element 1, element x] | provenance | | +| test.ps1:42:60:48:1 | x [element 2, element x] | test.ps1:45:5:47:5 | x [element 2, element x] | provenance | | +| test.ps1:45:5:47:5 | x [element 0, element x] | test.ps1:46:9:46:15 | __pipeline_iterator for x | provenance | | +| test.ps1:45:5:47:5 | x [element 1, element x] | test.ps1:46:9:46:15 | __pipeline_iterator for x | provenance | | +| test.ps1:45:5:47:5 | x [element 2, element x] | test.ps1:46:9:46:15 | __pipeline_iterator for x | provenance | | +| test.ps1:50:1:50:33 | [...]... [element x] | test.ps1:50:1:50:105 | ...,... [element 0, element x] | provenance | | +| test.ps1:50:1:50:105 | ...,... [element 0, element x] | test.ps1:42:60:48:1 | x [element 0, element x] | provenance | | +| test.ps1:50:1:50:105 | ...,... [element 1, element x] | test.ps1:42:60:48:1 | x [element 1, element x] | provenance | | +| test.ps1:50:1:50:105 | ...,... [element 2, element x] | test.ps1:42:60:48:1 | x [element 2, element x] | provenance | | +| test.ps1:50:17:50:33 | ${...} [element x] | test.ps1:50:1:50:33 | [...]... [element x] | provenance | | +| test.ps1:50:23:50:32 | Call to Source | test.ps1:50:17:50:33 | ${...} [element x] | provenance | | +| test.ps1:50:36:50:69 | [...]... [element x] | test.ps1:50:1:50:105 | ...,... [element 1, element x] | provenance | | +| test.ps1:50:52:50:69 | ${...} [element x] | test.ps1:50:36:50:69 | [...]... [element x] | provenance | | +| test.ps1:50:58:50:68 | Call to Source | test.ps1:50:52:50:69 | ${...} [element x] | provenance | | +| test.ps1:50:72:50:105 | [...]... [element x] | test.ps1:50:1:50:105 | ...,... [element 2, element x] | provenance | | +| test.ps1:50:88:50:105 | ${...} [element x] | test.ps1:50:72:50:105 | [...]... [element x] | provenance | | +| test.ps1:50:94:50:104 | Call to Source | test.ps1:50:88:50:105 | ${...} [element x] | 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 | @@ -43,19 +56,16 @@ nodes | 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:9:29:15:1 | [synth] pipeline [unknown index] | semmle.label | [synth] pipeline [unknown index] | | 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:12:5:14:5 | [synth] pipeline [unknown index] | semmle.label | [synth] pipeline [unknown index] | | 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:17:1:17:7 | Call to produce [unknown index] | semmle.label | Call to produce [unknown index] | | 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] | @@ -67,16 +77,29 @@ nodes | 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 | +| test.ps1:42:60:48:1 | x [element 0, element x] | semmle.label | x [element 0, element x] | +| test.ps1:42:60:48:1 | x [element 1, element x] | semmle.label | x [element 1, element x] | +| test.ps1:42:60:48:1 | x [element 2, element x] | semmle.label | x [element 2, element x] | +| test.ps1:45:5:47:5 | x [element 0, element x] | semmle.label | x [element 0, element x] | +| test.ps1:45:5:47:5 | x [element 1, element x] | semmle.label | x [element 1, element x] | +| test.ps1:45:5:47:5 | x [element 2, element x] | semmle.label | x [element 2, element x] | +| test.ps1:46:9:46:15 | __pipeline_iterator for x | semmle.label | __pipeline_iterator for x | +| test.ps1:50:1:50:33 | [...]... [element x] | semmle.label | [...]... [element x] | +| test.ps1:50:1:50:105 | ...,... [element 0, element x] | semmle.label | ...,... [element 0, element x] | +| test.ps1:50:1:50:105 | ...,... [element 1, element x] | semmle.label | ...,... [element 1, element x] | +| test.ps1:50:1:50:105 | ...,... [element 2, element x] | semmle.label | ...,... [element 2, element x] | +| test.ps1:50:17:50:33 | ${...} [element x] | semmle.label | ${...} [element x] | +| test.ps1:50:23:50:32 | Call to Source | semmle.label | Call to Source | +| test.ps1:50:36:50:69 | [...]... [element x] | semmle.label | [...]... [element x] | +| test.ps1:50:52:50:69 | ${...} [element x] | semmle.label | ${...} [element x] | +| test.ps1:50:58:50:68 | Call to Source | semmle.label | Call to Source | +| test.ps1:50:72:50:105 | [...]... [element x] | semmle.label | [...]... [element x] | +| test.ps1:50:88:50:105 | ${...} [element x] | semmle.label | ${...} [element x] | +| test.ps1:50:94:50:104 | Call to Source | semmle.label | Call to Source | subpaths testFailures -| 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 | @@ -85,3 +108,6 @@ testFailures | 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 | +| test.ps1:46:9:46:15 | __pipeline_iterator for x | test.ps1:50:23:50:32 | Call to Source | test.ps1:46:9:46:15 | __pipeline_iterator for x | $@ | test.ps1:50:23:50:32 | Call to Source | Call to Source | +| test.ps1:46:9:46:15 | __pipeline_iterator for x | test.ps1:50:58:50:68 | Call to Source | test.ps1:46:9:46:15 | __pipeline_iterator for x | $@ | test.ps1:50:58:50:68 | Call to Source | Call to Source | +| test.ps1:46:9:46:15 | __pipeline_iterator for x | test.ps1:50:94:50:104 | Call to Source | test.ps1:46:9:46:15 | __pipeline_iterator for x | $@ | test.ps1:50:94:50:104 | Call to Source | Call to Source | diff --git a/powershell/ql/test/library-tests/dataflow/pipeline/test.ps1 b/powershell/ql/test/library-tests/dataflow/pipeline/test.ps1 index d93bf1ba477e..8a55796e8726 100644 --- a/powershell/ql/test/library-tests/dataflow/pipeline/test.ps1 +++ b/powershell/ql/test/library-tests/dataflow/pipeline/test.ps1 @@ -33,7 +33,7 @@ $x, $y | consumeWithProcessAnonymous function consumeValueFromPipelineByPropertyNameWithoutProcess { Param([Parameter(ValueFromPipelineByPropertyName)] $x) - Sink $x # $ hasValueFlow=8 + Sink $x # $ MISSING: hasValueFlow=8 } $x = Source "8" diff --git a/powershell/ql/test/library-tests/dataflow/returns/test.expected b/powershell/ql/test/library-tests/dataflow/returns/test.expected index cfd34b3abcdd..6de78912cc4f 100644 --- a/powershell/ql/test/library-tests/dataflow/returns/test.expected +++ b/powershell/ql/test/library-tests/dataflow/returns/test.expected @@ -2,37 +2,37 @@ models edges | test.ps1:2:5:2:14 | Call to Source | test.ps1:5:6:5:19 | Call to callSourceOnce | provenance | | | test.ps1:5:6:5:19 | Call to callSourceOnce | test.ps1:6:6:6:7 | x | provenance | | -| test.ps1:9:5:9:14 | Call to Source | test.ps1:13:6:13:20 | Call to callSourceTwice [element] | provenance | | -| test.ps1:10:5:10:14 | Call to Source | test.ps1:13:6:13:20 | Call to callSourceTwice [element] | provenance | | -| test.ps1:13:6:13:20 | Call to callSourceTwice [element] | test.ps1:15:6:15:7 | x [element] | provenance | | -| test.ps1:13:6:13:20 | Call to callSourceTwice [element] | test.ps1:16:6:16:7 | x [element] | provenance | | -| test.ps1:15:6:15:7 | x [element] | test.ps1:15:6:15:10 | ...[...] | provenance | | -| test.ps1:16:6:16:7 | x [element] | test.ps1:16:6:16:10 | ...[...] | provenance | | +| test.ps1:9:5:9:14 | Call to Source | test.ps1:13:6:13:20 | Call to callSourceTwice [unknown index] | provenance | | +| test.ps1:10:5:10:14 | Call to Source | test.ps1:13:6:13:20 | Call to callSourceTwice [unknown index] | provenance | | +| test.ps1:13:6:13:20 | Call to callSourceTwice [unknown index] | test.ps1:15:6:15:7 | x [unknown index] | provenance | | +| test.ps1:13:6:13:20 | Call to callSourceTwice [unknown index] | test.ps1:16:6:16:7 | x [unknown index] | provenance | | +| test.ps1:15:6:15:7 | x [unknown index] | test.ps1:15:6:15:10 | ...[...] | provenance | | +| test.ps1:16:6:16:7 | x [unknown index] | test.ps1:16:6:16:10 | ...[...] | provenance | | | test.ps1:19:12:19:21 | Call to Source | test.ps1:22:6:22:18 | Call to returnSource1 | provenance | | | test.ps1:22:6:22:18 | Call to returnSource1 | test.ps1:23:6:23:7 | x | provenance | | | test.ps1:26:10:26:19 | Call to Source | test.ps1:27:5:27:6 | x | provenance | | -| test.ps1:27:5:27:6 | x | test.ps1:32:6:32:18 | Call to returnSource2 [element] | provenance | | +| test.ps1:27:5:27:6 | x | test.ps1:32:6:32:18 | Call to returnSource2 [unknown index] | provenance | | | test.ps1:28:10:28:19 | Call to Source | test.ps1:29:12:29:13 | y | provenance | | -| test.ps1:29:12:29:13 | y | test.ps1:32:6:32:18 | Call to returnSource2 [element] | provenance | | -| test.ps1:32:6:32:18 | Call to returnSource2 [element] | test.ps1:33:6:33:7 | x [element] | provenance | | -| test.ps1:32:6:32:18 | Call to returnSource2 [element] | test.ps1:34:6:34:7 | x [element] | provenance | | -| test.ps1:33:6:33:7 | x [element] | test.ps1:33:6:33:10 | ...[...] | provenance | | -| test.ps1:34:6:34:7 | x [element] | test.ps1:34:6:34:10 | ...[...] | provenance | | -| test.ps1:38:9:38:18 | Call to Source | test.ps1:42:6:42:21 | Call to callSourceInLoop [element] | provenance | | -| test.ps1:42:6:42:21 | Call to callSourceInLoop [element] | test.ps1:43:6:43:7 | x [element] | provenance | | -| test.ps1:42:6:42:21 | Call to callSourceInLoop [element] | test.ps1:44:6:44:7 | x [element] | provenance | | -| test.ps1:43:6:43:7 | x [element] | test.ps1:43:6:43:10 | ...[...] | provenance | | -| test.ps1:44:6:44:7 | x [element] | test.ps1:44:6:44:10 | ...[...] | provenance | | +| test.ps1:29:12:29:13 | y | test.ps1:32:6:32:18 | Call to returnSource2 [unknown index] | provenance | | +| test.ps1:32:6:32:18 | Call to returnSource2 [unknown index] | test.ps1:33:6:33:7 | x [unknown index] | provenance | | +| test.ps1:32:6:32:18 | Call to returnSource2 [unknown index] | test.ps1:34:6:34:7 | x [unknown index] | provenance | | +| test.ps1:33:6:33:7 | x [unknown index] | test.ps1:33:6:33:10 | ...[...] | provenance | | +| test.ps1:34:6:34:7 | x [unknown index] | test.ps1:34:6:34:10 | ...[...] | provenance | | +| test.ps1:38:9:38:18 | Call to Source | test.ps1:42:6:42:21 | Call to callSourceInLoop [unknown index] | provenance | | +| test.ps1:42:6:42:21 | Call to callSourceInLoop [unknown index] | test.ps1:43:6:43:7 | x [unknown index] | provenance | | +| test.ps1:42:6:42:21 | Call to callSourceInLoop [unknown index] | test.ps1:44:6:44:7 | x [unknown index] | provenance | | +| test.ps1:43:6:43:7 | x [unknown index] | test.ps1:43:6:43:10 | ...[...] | provenance | | +| test.ps1:44:6:44:7 | x [unknown index] | test.ps1:44:6:44:10 | ...[...] | provenance | | nodes | test.ps1:2:5:2:14 | Call to Source | semmle.label | Call to Source | | test.ps1:5:6:5:19 | Call to callSourceOnce | semmle.label | Call to callSourceOnce | | test.ps1:6:6:6:7 | x | semmle.label | x | | test.ps1:9:5:9:14 | Call to Source | semmle.label | Call to Source | | test.ps1:10:5:10:14 | Call to Source | semmle.label | Call to Source | -| test.ps1:13:6:13:20 | Call to callSourceTwice [element] | semmle.label | Call to callSourceTwice [element] | -| test.ps1:15:6:15:7 | x [element] | semmle.label | x [element] | +| test.ps1:13:6:13:20 | Call to callSourceTwice [unknown index] | semmle.label | Call to callSourceTwice [unknown index] | +| test.ps1:15:6:15:7 | x [unknown index] | semmle.label | x [unknown index] | | test.ps1:15:6:15:10 | ...[...] | semmle.label | ...[...] | -| test.ps1:16:6:16:7 | x [element] | semmle.label | x [element] | +| test.ps1:16:6:16:7 | x [unknown index] | semmle.label | x [unknown index] | | test.ps1:16:6:16:10 | ...[...] | semmle.label | ...[...] | | test.ps1:19:12:19:21 | Call to Source | semmle.label | Call to Source | | test.ps1:22:6:22:18 | Call to returnSource1 | semmle.label | Call to returnSource1 | @@ -41,16 +41,16 @@ nodes | test.ps1:27:5:27:6 | x | semmle.label | x | | test.ps1:28:10:28:19 | Call to Source | semmle.label | Call to Source | | test.ps1:29:12:29:13 | y | semmle.label | y | -| test.ps1:32:6:32:18 | Call to returnSource2 [element] | semmle.label | Call to returnSource2 [element] | -| test.ps1:33:6:33:7 | x [element] | semmle.label | x [element] | +| test.ps1:32:6:32:18 | Call to returnSource2 [unknown index] | semmle.label | Call to returnSource2 [unknown index] | +| test.ps1:33:6:33:7 | x [unknown index] | semmle.label | x [unknown index] | | test.ps1:33:6:33:10 | ...[...] | semmle.label | ...[...] | -| test.ps1:34:6:34:7 | x [element] | semmle.label | x [element] | +| test.ps1:34:6:34:7 | x [unknown index] | semmle.label | x [unknown index] | | test.ps1:34:6:34:10 | ...[...] | semmle.label | ...[...] | | test.ps1:38:9:38:18 | Call to Source | semmle.label | Call to Source | -| test.ps1:42:6:42:21 | Call to callSourceInLoop [element] | semmle.label | Call to callSourceInLoop [element] | -| test.ps1:43:6:43:7 | x [element] | semmle.label | x [element] | +| test.ps1:42:6:42:21 | Call to callSourceInLoop [unknown index] | semmle.label | Call to callSourceInLoop [unknown index] | +| test.ps1:43:6:43:7 | x [unknown index] | semmle.label | x [unknown index] | | test.ps1:43:6:43:10 | ...[...] | semmle.label | ...[...] | -| test.ps1:44:6:44:7 | x [element] | semmle.label | x [element] | +| test.ps1:44:6:44:7 | x [unknown index] | semmle.label | x [unknown index] | | test.ps1:44:6:44:10 | ...[...] | semmle.label | ...[...] | subpaths testFailures