Skip to content

Commit 171f5ca

Browse files
committed
PS: Inside a process block the name of a pipeline parameter actually refers to the individual elements in the pipeline. Add a synthesized variable access that represents this.
1 parent 9f4d1c6 commit 171f5ca

File tree

1 file changed

+118
-0
lines changed
  • powershell/ql/lib/semmle/code/powershell/ast/internal

1 file changed

+118
-0
lines changed

powershell/ql/lib/semmle/code/powershell/ast/internal/Synthesis.qll

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -652,3 +652,121 @@ private module LiteralSynth {
652652
}
653653
}
654654
}
655+
656+
/**
657+
* Synthesize variable accesses for pipeline iterators inside a process block.
658+
*/
659+
private module IteratorAccessSynth {
660+
private class PipelineOrPipelineByPropertyNameIteratorVariable extends VariableSynth {
661+
PipelineOrPipelineByPropertyNameIteratorVariable() {
662+
this instanceof PipelineIteratorVariable
663+
or
664+
this instanceof PipelineByPropertyNameIteratorVariable
665+
}
666+
667+
string getPropertyName() {
668+
result = this.(PipelineByPropertyNameIteratorVariable).getPropertyName()
669+
}
670+
671+
predicate isPipelineIterator() { this instanceof PipelineIteratorVariable }
672+
}
673+
674+
bindingset[pb, v]
675+
private string getAPipelineIteratorName(
676+
Raw::ProcessBlock pb, PipelineOrPipelineByPropertyNameIteratorVariable v
677+
) {
678+
v.isPipelineIterator() and
679+
(
680+
result = "_"
681+
or
682+
// or
683+
// result = "psitem" // TODO: This is also an automatic variable
684+
result = pb.getScriptBlock().getParamBlock().getPipelineParameter().getName().toLowerCase()
685+
)
686+
or
687+
// TODO: We could join on something other than the string if we wanted (i.e., the raw parameter).
688+
v.getPropertyName().toLowerCase() = result and
689+
result =
690+
pb.getScriptBlock()
691+
.getParamBlock()
692+
.getAPipelineByPropertyNameParameter()
693+
.getName()
694+
.toLowerCase()
695+
}
696+
697+
private class IteratorAccessSynth extends Synthesis {
698+
private predicate expr(Raw::Ast rawParent, ChildIndex i, Raw::VarAccess va, Child child) {
699+
rawParent.getChild(toRawChildIndex(i)) = va and
700+
child = SynthChild(VarAccessSynthKind(this.varAccess(va)))
701+
}
702+
703+
private predicate stmt(Raw::Ast rawParent, ChildIndex i, Raw::CmdExpr cmdExpr, Child child) {
704+
rawParent.getChild(toRawChildIndex(i)) = cmdExpr and
705+
not mustHaveExprChild(rawParent, cmdExpr) and
706+
child = SynthChild(ExprStmtKind())
707+
}
708+
709+
private PipelineOrPipelineByPropertyNameIteratorVariable varAccess(Raw::VarAccess va) {
710+
exists(Raw::ProcessBlock pb |
711+
pb = va.getParent+() and
712+
result = TVariableSynth(pb, _) and
713+
va.getUserPath().toLowerCase() = getAPipelineIteratorName(pb, result)
714+
)
715+
}
716+
717+
override predicate child(Raw::Ast parent, ChildIndex i, Child child) {
718+
this.expr(parent, i, _, child)
719+
or
720+
this.stmt(parent, i, _, child)
721+
or
722+
exists(Raw::ProcessBlock pb | parent = pb |
723+
i = PipelineIteratorVar() and
724+
child = SynthChild(VarSynthKind(PipelineIteratorKind()))
725+
or
726+
exists(Raw::Parameter p |
727+
p = pb.getScriptBlock().getParamBlock().getAPipelineByPropertyNameParameter() and
728+
child = SynthChild(VarSynthKind(PipelineByPropertyNameIteratorKind(p.getName()))) and
729+
i = PipelineByPropertyNameIteratorVar(p)
730+
)
731+
)
732+
}
733+
734+
override predicate exprStmtExpr(ExprStmt e, Expr expr) {
735+
exists(Raw::Ast p, Raw::VarAccess va, Raw::CmdExpr cmdExpr, ChildIndex i1, ChildIndex i2 |
736+
this.stmt(p, i1, _, _) and
737+
this.expr(cmdExpr, i2, va, _) and
738+
e = TExprStmtSynth(p, i1) and
739+
expr = TVarAccessSynth(cmdExpr, i2, this.varAccess(va))
740+
)
741+
}
742+
743+
final override Expr getResultAstImpl(Raw::Ast r) {
744+
exists(Raw::Ast parent, ChildIndex i | this.expr(parent, i, r, _) |
745+
result = TVarAccessSynth(parent, i, this.varAccess(r))
746+
)
747+
}
748+
749+
override predicate variableSynthName(VariableSynth v, string name) {
750+
v = TVariableSynth(_, PipelineIteratorVar()) and
751+
name = "__pipeline_iterator"
752+
or
753+
exists(Raw::PipelineByPropertyNameParameter p |
754+
v = TVariableSynth(_, PipelineByPropertyNameIteratorVar(p)) and
755+
name = "__pipeline_iterator for " + p.getName()
756+
)
757+
}
758+
759+
final override Location getLocation(Ast n) {
760+
exists(Raw::Ast parent, ChildIndex i, Raw::CmdExpr cmdExpr |
761+
this.stmt(parent, i, cmdExpr, _) and
762+
n = TExprStmtSynth(parent, i) and
763+
result = cmdExpr.getLocation()
764+
)
765+
or
766+
exists(Raw::Ast parent |
767+
n = TVariableSynth(parent, _) and
768+
result = parent.getLocation()
769+
)
770+
}
771+
}
772+
}

0 commit comments

Comments
 (0)