Skip to content

Commit efee104

Browse files
committed
PS: Generalize the current ReturnContainer computation.
1 parent eb0f094 commit efee104

File tree

3 files changed

+128
-74
lines changed

3 files changed

+128
-74
lines changed

powershell/ql/lib/semmle/code/powershell/StatementBlock.qll

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,12 @@
11
import powershell
2+
private import semmle.code.powershell.internal.AstEscape::Private
3+
4+
private module ReturnContainerInterpreter implements InterpretAstInputSig {
5+
class T = Ast;
6+
7+
pragma[inline]
8+
T interpret(Ast a) { result = a }
9+
}
210

311
class StmtBlock extends @statement_block, Ast {
412
override SourceLocation getLocation() { statement_block_location(this, result) }
@@ -16,4 +24,9 @@ class StmtBlock extends @statement_block, Ast {
1624
TrapStmt getATrapStmt() { result = this.getTrapStmt(_) }
1725

1826
override string toString() { result = "{...}" }
27+
28+
/** Gets an element that may escape this `StmtBlock`. */
29+
Ast getAnElement() {
30+
result = this.(AstEscape<ReturnContainerInterpreter>::Element).getAnEscapingElement()
31+
}
1932
}

powershell/ql/lib/semmle/code/powershell/dataflow/internal/DataFlowPrivate.qll

Lines changed: 19 additions & 74 deletions
Original file line numberDiff line numberDiff line change
@@ -550,100 +550,45 @@ abstract class ReturnNode extends Node {
550550
abstract ReturnKind getKind();
551551
}
552552

553-
private module ReturnNodes {
554-
/** An AST element that may produce return values when evaluated. */
555-
abstract private class ReturnContainer extends Ast {
556-
/**
557-
* Gets a direct node that will may be returned when evaluating this node.
558-
*/
559-
CfgNode getANode() { none() }
560-
561-
/** Gets a child that may produce more nodes that may be returned. */
562-
abstract ReturnContainer getAChild();
563-
564-
/**
565-
* Gets a (possibly transitive) node that may be returned when evaluating
566-
* this node.
567-
*/
568-
final CfgNode getAReturnedNode() {
569-
result = this.getANode()
553+
private module EscapeContainer {
554+
private import semmle.code.powershell.internal.AstEscape::Private
555+
556+
private module ReturnContainerInterpreter implements InterpretAstInputSig {
557+
class T = CfgNodes::AstCfgNode;
558+
559+
T interpret(Ast a) {
560+
result.(CfgNodes::ExprCfgNode).getExpr() = a
570561
or
571-
result = this.getAChild().getAReturnedNode()
562+
result.(CfgNodes::StmtCfgNode).getStmt() = a.(Cmd)
572563
}
564+
}
573565

566+
class EscapeContainer extends AstEscape<ReturnContainerInterpreter>::Element {
574567
/** Holds if `n` may be returned multiples times. */
575568
predicate mayBeMultiReturned(CfgNode n) {
576569
n = this.getANode() and
577570
n.getASuccessor+() = n
578571
or
579-
this.getAChild().mayBeMultiReturned(n)
572+
this.getAChild().(EscapeContainer).mayBeMultiReturned(n)
580573
}
581574
}
575+
}
582576

583-
class ScriptBlockReturnContainer extends ReturnContainer, ScriptBlock {
584-
final override ReturnContainer getAChild() { result = this.getEndBlock() }
585-
}
586-
587-
class NamedBlockReturnContainer extends ReturnContainer, NamedBlock {
588-
final override ReturnContainer getAChild() { result = this.getAStmt() }
589-
}
590-
591-
class CmdExprReturnContainer extends ReturnContainer, CmdExpr {
592-
final override CfgNodes::ExprCfgNode getANode() { result.getExpr() = this.getExpr() }
593-
594-
final override ReturnContainer getAChild() { none() }
595-
}
596-
597-
class LoopStmtReturnContainer extends ReturnContainer, LoopStmt {
598-
final override ReturnContainer getAChild() { result = this.getBody() }
599-
}
600-
601-
class StmtBlockReturnConainer extends ReturnContainer, StmtBlock {
602-
final override ReturnContainer getAChild() { result = this.getAStmt() }
603-
}
604-
605-
class TryStmtReturnContainer extends ReturnContainer, TryStmt {
606-
final override ReturnContainer getAChild() {
607-
result = this.getBody() or result = this.getACatchClause() or result = this.getFinally()
608-
}
609-
}
610-
611-
class ReturnStmtReturnContainer extends ReturnContainer, ReturnStmt {
612-
final override ReturnContainer getAChild() { result = this.getPipeline() }
613-
}
614-
615-
class CatchClausReturnContainer extends ReturnContainer, CatchClause {
616-
final override ReturnContainer getAChild() { result = this.getBody() }
617-
}
618-
619-
class SwitchStmtReturnContainer extends ReturnContainer, SwitchStmt {
620-
final override ReturnContainer getAChild() { result = this.getACase() }
621-
}
622-
623-
class CmdBaseReturnContainer extends ReturnContainer, CmdExpr {
624-
final override CfgNodes::ExprCfgNode getANode() { result.getExpr() = this.getExpr() }
625-
626-
final override ReturnContainer getAChild() { none() }
627-
}
628-
629-
class CmdReturnContainer extends ReturnContainer, Cmd {
630-
final override CfgNodes::StmtCfgNode getANode() { result.getStmt() = this }
631-
632-
final override ReturnContainer getAChild() { none() }
633-
}
577+
private module ReturnNodes {
578+
private import EscapeContainer
634579

635-
private predicate isReturnedImpl(CfgNodes::AstCfgNode n, ReturnContainer container) {
580+
private predicate isReturnedImpl(CfgNodes::AstCfgNode n, EscapeContainer container) {
636581
container = n.getScope() and
637-
n = container.getAReturnedNode()
582+
n = container.getAnEscapingElement()
638583
}
639584

640585
/**
641586
* Holds if `n` may be returned, and there are possibly
642587
* more than one return value from the function.
643588
*/
644589
predicate isMultiReturned(CfgNodes::AstCfgNode n) {
645-
exists(ReturnContainer container | isReturnedImpl(n, container) |
646-
strictcount(container.getAReturnedNode()) > 1
590+
exists(EscapeContainer container | isReturnedImpl(n, container) |
591+
strictcount(container.getAnEscapingElement()) > 1
647592
or
648593
container.mayBeMultiReturned(n)
649594
)
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
private import powershell as PS
2+
3+
/**
4+
* TODO: This whole computation cab be sped up by providing a set of "root"s and doing
5+
* a forward/backwards traversal first.
6+
*/
7+
module Private {
8+
signature module InterpretAstInputSig {
9+
/** The type on which to translate `Ast` elements during escape calculations */
10+
class T;
11+
12+
/** Interpret `a` into a `T` */
13+
T interpret(PS::Ast a);
14+
}
15+
16+
module AstEscape<InterpretAstInputSig Interpret> {
17+
private import Interpret
18+
19+
/** An AST element that may produce a value which can escape from this `Ast` when evaluated. */
20+
abstract private class ElementImpl instanceof PS::Ast {
21+
string toString() { result = super.toString() }
22+
23+
/** Gets a direct node that will may escape when evaluating this element. */
24+
T getANode() { none() }
25+
26+
/** Gets a child that may produce more elements that may escape. */
27+
abstract Element getAChild();
28+
29+
/**
30+
* Gets a (possibly transitive) element that may escape when evaluating
31+
* this element.
32+
*/
33+
final T getAnEscapingElement() {
34+
result = this.getANode()
35+
or
36+
result = this.getAChild().getAnEscapingElement()
37+
}
38+
}
39+
40+
final class Element = ElementImpl;
41+
42+
private class ScriptBlockElement extends ElementImpl instanceof PS::ScriptBlock {
43+
final override Element getAChild() { result = super.getEndBlock() }
44+
}
45+
46+
private class NamedBlockElement extends ElementImpl instanceof PS::NamedBlock {
47+
final override Element getAChild() { result = super.getAStmt() }
48+
}
49+
50+
private class CmdExprElement extends ElementImpl instanceof PS::CmdExpr {
51+
final override T getANode() { result = interpret(super.getExpr()) }
52+
53+
final override Element getAChild() { none() }
54+
}
55+
56+
private class LoopStmtElement extends ElementImpl instanceof PS::LoopStmt {
57+
final override Element getAChild() { result = super.getBody() }
58+
}
59+
60+
private class StmtBlockElement extends ElementImpl instanceof PS::StmtBlock {
61+
final override Element getAChild() { result = super.getAStmt() }
62+
}
63+
64+
private class TryStmtElement extends ElementImpl instanceof PS::TryStmt {
65+
final override Element getAChild() {
66+
result = super.getBody() or result = super.getACatchClause() or result = super.getFinally()
67+
}
68+
}
69+
70+
private class ReturnStmtElement extends ElementImpl instanceof PS::ReturnStmt {
71+
final override Element getAChild() { result = super.getPipeline() }
72+
}
73+
74+
private class CatchClausElement extends ElementImpl instanceof PS::CatchClause {
75+
final override Element getAChild() { result = super.getBody() }
76+
}
77+
78+
private class SwitchStmtElement extends ElementImpl instanceof PS::SwitchStmt {
79+
final override Element getAChild() { result = super.getACase() }
80+
}
81+
82+
private class CmdBaseElement extends ElementImpl instanceof PS::CmdExpr {
83+
final override T getANode() { result = interpret(super.getExpr()) }
84+
85+
final override Element getAChild() { none() }
86+
}
87+
88+
private class CmdElement extends ElementImpl instanceof PS::Cmd {
89+
final override T getANode() { result = interpret(this) }
90+
91+
final override Element getAChild() { none() }
92+
}
93+
}
94+
}
95+
96+
module Public { }

0 commit comments

Comments
 (0)