Skip to content

Commit 88f638d

Browse files
committed
PS: Fix more pipeline flow.
1 parent ee4104b commit 88f638d

File tree

10 files changed

+262
-59
lines changed

10 files changed

+262
-59
lines changed

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

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ class CallExpr extends Expr, TCallExpr {
2828
/** Gets the qualifier of this call, if any. */
2929
Expr getQualifier() { none() }
3030

31+
Expr getPipelineArgument() {
32+
exists(Pipeline p, int i | this = p.getComponent(i + 1) and result = p.getComponent(i))
33+
}
34+
3135
final override string toString() { result = "Call to " + this.getName() }
3236

3337
predicate isStatic() { none() }
@@ -52,3 +56,11 @@ class Qualifier extends Expr {
5256

5357
CallExpr getCall() { result = call }
5458
}
59+
60+
class PipelineArgument extends Expr {
61+
CallExpr call;
62+
63+
PipelineArgument() { this = call.getPipelineArgument() }
64+
65+
CallExpr getCall() { result = call }
66+
}

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

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,14 +36,23 @@ newtype ChildIndex =
3636
// PipelineByPropertNameVar(Raw::PipelineByPropertyNameParameter p) or
3737
PipelineIteratorVar() or
3838
PipelineByPropertyNameIteratorVar(Raw::PipelineByPropertyNameParameter p) or
39-
RealVar(string name) { name = variableNameInScope(_, _) }
39+
RealVar(string name) { name = variableNameInScope(_, _) } or
40+
ProcessBlockPipelineVarReadAccess()
4041

4142
int synthPipelineParameterChildIndex(Raw::ScriptBlock sb) {
43+
// If there is a parameter block, but no pipeline parameter
4244
exists(Raw::ParamBlock pb |
4345
pb = sb.getParamBlock() and
4446
not pb.getAParameter() instanceof Raw::PipelineParameter and
4547
result = pb.getNumParameters()
4648
)
49+
or
50+
// There is no parameter block
51+
not exists(sb.getParamBlock()) and
52+
exists(Raw::FunctionDefinitionStmt funDefStmt |
53+
funDefStmt.getBody() = sb and
54+
result = funDefStmt.getNumParameters()
55+
)
4756
}
4857

4958
string stringOfChildIndex(ChildIndex i) {
@@ -105,6 +114,9 @@ string stringOfChildIndex(ChildIndex i) {
105114
or
106115
i = FunctionBody() and
107116
result = "FunctionBody"
117+
or
118+
i = ProcessBlockPipelineVarReadAccess() and
119+
result = "ProcessBlockPipelineVarReadAccess"
108120
}
109121

110122
Raw::ChildIndex toRawChildIndex(ChildIndex i) { i = RawChildIndex(result) }
@@ -326,3 +338,5 @@ ChildIndex usingExprExpr() { result = RawChildIndex(Raw::UsingExprExpr()) }
326338
ChildIndex whileStmtCond() { result = RawChildIndex(Raw::WhileStmtCond()) }
327339

328340
ChildIndex whileStmtBody() { result = RawChildIndex(Raw::WhileStmtBody()) }
341+
342+
ChildIndex processBlockPipelineVarReadAccess() { result = ProcessBlockPipelineVarReadAccess() }

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

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,14 @@ class ProcessBlock extends NamedBlock {
5050
result = this.getEnclosingFunction().getPipelineParameter()
5151
}
5252

53+
PipelineIteratorVariable getPipelineIteratorVariable() {
54+
result = TVariableSynth(getRawAst(this), PipelineIteratorVar())
55+
}
56+
57+
VarReadAccess getPipelineParameterAccess() {
58+
synthChild(getRawAst(this), processBlockPipelineVarReadAccess(), result)
59+
}
60+
5361
PipelineByPropertyNameParameter getAPipelineByPropertyNameParameter() {
5462
result = scriptBlock.getEnclosingFunction().getAParameter()
5563
}

powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/Function.qll

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ class FunctionDefinitionStmt extends @function_definition, Stmt {
1111

1212
Parameter getAParameter() { result = this.getParameter(_) }
1313

14+
int getNumParameters() { result = count(this.getParameter(_)) }
15+
1416
override Ast getChild(ChildIndex i) {
1517
i = FunDefStmtBody() and result = this.getBody()
1618
or

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

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -728,6 +728,7 @@ private module IteratorAccessSynth {
728728
}
729729

730730
private predicate stmt(Raw::Ast rawParent, ChildIndex i, Raw::CmdExpr cmdExpr, Child child) {
731+
exists(this.varAccess(cmdExpr.getExpr())) and
731732
rawParent.getChild(toRawChildIndex(i)) = cmdExpr and
732733
not mustHaveExprChild(rawParent, cmdExpr) and
733734
child = SynthChild(ExprStmtKind())
@@ -805,3 +806,31 @@ private module IteratorAccessSynth {
805806
}
806807
}
807808
}
809+
810+
private module PipelineAccess {
811+
private class PipelineAccess extends Synthesis {
812+
final override predicate child(Raw::Ast parent, ChildIndex i, Child child) {
813+
exists(Raw::ProcessBlock pb | parent = pb |
814+
i = processBlockPipelineVarReadAccess() and
815+
exists(PipelineVariable pipelineVar |
816+
pipelineVar = TVariableSynth(pb.getScriptBlock(), PipelineParamVar()) and
817+
child = SynthChild(VarAccessSynthKind(pipelineVar))
818+
)
819+
)
820+
}
821+
822+
final override Location getLocation(Ast n) {
823+
exists(ProcessBlock pb |
824+
pb.getPipelineParameterAccess() = n and
825+
result = pb.getLocation()
826+
)
827+
}
828+
829+
final override predicate getAnAccess(VarAccessSynth va, Variable v) {
830+
exists(ProcessBlock pb |
831+
pb.getPipelineParameterAccess() = va and
832+
v = pb.getPipelineParameter()
833+
)
834+
}
835+
}
836+
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ module Private {
100100

101101
final override Variable getVariableImpl() { access(va, result) }
102102

103-
final override string toString() { result = "access to " + va.getUserPath() }
103+
final override string toString() { result = va.getUserPath() }
104104
}
105105

106106
class VarAccessSynth extends VarAccessImpl, TVarAccessSynth {
@@ -111,7 +111,7 @@ module Private {
111111

112112
final override Variable getVariableImpl() { any(Synthesis s).getAnAccess(this, result) }
113113

114-
final override string toString() { result = "access to " + this.getVariableImpl().getName() }
114+
final override string toString() { result = this.getVariableImpl().getName() }
115115

116116
final override Location getLocation() { result = parent.getLocation() }
117117
}

powershell/ql/lib/semmle/code/powershell/controlflow/CfgNodes.qll

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,13 @@ class NamedBlockCfgNode extends AstCfgNode {
272272
StmtNodes::TrapStmtCfgNode getATrapStmt() { result = this.getTrapStmt(_) }
273273
}
274274

275-
private class ProcessBlockChildMapping extends NamedBlockChildMapping, ProcessBlock { }
275+
private class ProcessBlockChildMapping extends NamedBlockChildMapping, ProcessBlock {
276+
override predicate relevantChild(Ast child) {
277+
super.relevantChild(child)
278+
or
279+
child = super.getPipelineParameterAccess()
280+
}
281+
}
276282

277283
class ProcessBlockCfgNode extends NamedBlockCfgNode {
278284
override string getAPrimaryQlClass() { result = "ProcessBlockCfgNode" }
@@ -287,6 +293,10 @@ class ProcessBlockCfgNode extends NamedBlockCfgNode {
287293
result.getScriptBlock() = this.getScriptBlock().getAstNode()
288294
}
289295

296+
ExprNodes::VarReadAccessCfgNode getPipelineVariableAccess() {
297+
block.hasCfgChild(block.getPipelineParameterAccess(), this, result)
298+
}
299+
290300
PipelineIteratorVariable getPipelineIteratorVariable() {
291301
result.getProcessBlock().getScriptBlock() = this.getScriptBlock().getAstNode()
292302
}
@@ -528,6 +538,13 @@ module ExprNodes {
528538

529539
ExprCfgNode getCallee() { e.hasCfgChild(e.getCallee(), this, result) }
530540

541+
ExprCfgNode getPipelineArgument() {
542+
exists(ExprNodes::PipelineCfgNode pipeline, int i |
543+
pipeline.getComponent(i + 1) = this and
544+
result = pipeline.getComponent(i)
545+
)
546+
}
547+
531548
predicate isStatic() { this.getExpr().isStatic() }
532549
}
533550

@@ -992,6 +1009,12 @@ module ExprNodes {
9921009
CallExprCfgNode getCall() { result.getQualifier() = this }
9931010
}
9941011

1012+
class PipelineArgumentCfgNode extends ExprCfgNode {
1013+
override PipelineArgument e;
1014+
1015+
CallExprCfgNode getCall() { result.getPipelineArgument() = this }
1016+
}
1017+
9951018
private class EnvVariableChildMapping extends ExprChildMapping, EnvVariable {
9961019
override predicate relevantChild(Ast child) { none() }
9971020
}

powershell/ql/lib/semmle/code/powershell/controlflow/internal/ControlFlowGraphImpl.qll

Lines changed: 62 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -193,21 +193,21 @@ module Trees {
193193
or
194194
exists(int i |
195195
last(super.getParameter(i), pred, c) and
196-
completionIsNormal(c) and
196+
completionIsNormal(c)
197+
|
197198
first(super.getParameter(i + 1), succ)
198-
)
199-
or
200-
last(super.getParameter(super.getNumberOfParameters() - 1), pred, c) and
201-
completionIsNormal(c) and
202-
(
203-
first(super.getBeginBlock(), succ)
204-
or
205-
not exists(super.getBeginBlock()) and
206-
first(super.getProcessBlock(), succ)
207199
or
208-
not exists(super.getBeginBlock()) and
209-
not exists(super.getProcessBlock()) and
210-
first(super.getEndBlock(), succ)
200+
not exists(super.getParameter(i + 1)) and
201+
(
202+
first(super.getBeginBlock(), succ)
203+
or
204+
not exists(super.getBeginBlock()) and
205+
first(super.getProcessBlock(), succ)
206+
or
207+
not exists(super.getBeginBlock()) and
208+
not exists(super.getProcessBlock()) and
209+
first(super.getEndBlock(), succ)
210+
)
211211
)
212212
or
213213
last(super.getBeginBlock(), pred, c) and
@@ -292,9 +292,55 @@ module Trees {
292292
final override predicate succEntry(Ast n, Completion c) { n = this and completionIsSimple(c) }
293293
}
294294

295-
class NamedBlockTree extends StandardPreOrderTree instanceof NamedBlock {
296-
// TODO: Handle trap
297-
override AstNode getChildNode(int i) { result = super.getStmt(i) }
295+
abstract class NamedBlockTreeBase extends ControlFlowTree instanceof NamedBlock {
296+
final override predicate last(Ast last, Completion c) {
297+
exists(int i | last(super.getStmt(i), last, c) |
298+
completionIsNormal(c) and
299+
not exists(super.getStmt(i + 1))
300+
or
301+
not completionIsNormal(c)
302+
)
303+
or
304+
not exists(super.getAStmt()) and
305+
completionIsSimple(c) and
306+
last = this
307+
}
308+
309+
override predicate succ(Ast pred, Ast succ, Completion c) {
310+
pred = this and
311+
completionIsSimple(c) and
312+
first(super.getStmt(0), succ)
313+
or
314+
exists(int i |
315+
last(super.getStmt(i), pred, c) and
316+
completionIsNormal(c) and
317+
first(super.getStmt(i + 1), succ)
318+
)
319+
}
320+
321+
override predicate propagatesAbnormal(Ast child) { child = super.getAStmt() }
322+
}
323+
324+
class NamedBlockTree extends NamedBlockTreeBase instanceof NamedBlock {
325+
NamedBlockTree() { not this instanceof ProcessBlock }
326+
327+
final override predicate first(Ast first) { first = this }
328+
329+
final override predicate propagatesAbnormal(Ast child) { super.propagatesAbnormal(child) }
330+
}
331+
332+
class ProcessBlockTree extends NamedBlockTreeBase instanceof ProcessBlock {
333+
final override predicate first(Ast first) { first = super.getPipelineParameterAccess() }
334+
335+
final override predicate succ(Ast pred, Ast succ, Completion c) {
336+
this.first(pred) and
337+
completionIsSimple(c) and
338+
succ = this
339+
or
340+
super.succ(pred, succ, c)
341+
}
342+
343+
final override predicate propagatesAbnormal(Ast child) { super.propagatesAbnormal(child) }
298344
}
299345

300346
class AssignStmtTree extends StandardPreOrderTree instanceof AssignStmt {

0 commit comments

Comments
 (0)