Skip to content

Commit 8a575c4

Browse files
authored
Merge pull request #118 from microsoft/powershell-add-return-and-out-nodes
PS: Add flow out of functions
2 parents 0814a90 + 1527479 commit 8a575c4

File tree

5 files changed

+197
-6
lines changed

5 files changed

+197
-6
lines changed

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

Lines changed: 90 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -489,7 +489,89 @@ abstract class ReturnNode extends Node {
489489
}
490490

491491
private module ReturnNodes {
492-
// TODO
492+
/** An AST element that may produce return values when evaluated. */
493+
abstract private class ReturnContainer extends Ast {
494+
/**
495+
* Gets a direct node that will may be returned when evaluating this node.
496+
*/
497+
Node getANode() { none() }
498+
499+
/** Gets a child that may produce more nodes that may be returned. */
500+
abstract ReturnContainer getAChild();
501+
502+
/**
503+
* Gets a (possibly transitive) node that may be returned when evaluating
504+
* this node.
505+
*/
506+
final Node getAReturnedNode() {
507+
result = this.getANode()
508+
or
509+
result = this.getAChild().getAReturnedNode()
510+
}
511+
}
512+
513+
class ScriptBlockReturnContainer extends ReturnContainer, ScriptBlock {
514+
final override ReturnContainer getAChild() { result = this.getEndBlock() }
515+
}
516+
517+
class NamedBlockReturnContainer extends ReturnContainer, NamedBlock {
518+
final override ReturnContainer getAChild() { result = this.getAStmt() }
519+
}
520+
521+
class CmdExprReturnContainer extends ReturnContainer, CmdExpr {
522+
final override ExprNode getANode() { result.getExprNode().getExpr() = this.getExpr() }
523+
524+
final override ReturnContainer getAChild() { none() }
525+
}
526+
527+
class LoopStmtReturnContainer extends ReturnContainer, LoopStmt {
528+
final override ReturnContainer getAChild() { result = this.getBody() }
529+
}
530+
531+
class StmtBlockReturnConainer extends ReturnContainer, StmtBlock {
532+
final override ReturnContainer getAChild() { result = this.getAStmt() }
533+
}
534+
535+
class TryStmtReturnContainer extends ReturnContainer, TryStmt {
536+
final override ReturnContainer getAChild() {
537+
result = this.getBody() or result = this.getACatchClause() or result = this.getFinally()
538+
}
539+
}
540+
541+
class ReturnStmtReturnContainer extends ReturnContainer, ReturnStmt {
542+
final override ReturnContainer getAChild() { result = this.getPipeline() }
543+
}
544+
545+
class CatchClausReturnContainer extends ReturnContainer, CatchClause {
546+
final override ReturnContainer getAChild() { result = this.getBody() }
547+
}
548+
549+
class SwitchStmtReturnContainer extends ReturnContainer, SwitchStmt {
550+
final override ReturnContainer getAChild() { result = this.getACase() }
551+
}
552+
553+
class CmdBaseReturnContainer extends ReturnContainer, CmdExpr {
554+
final override ExprNode getANode() { result.getExprNode().getExpr() = this.getExpr() }
555+
556+
final override ReturnContainer getAChild() { none() }
557+
}
558+
559+
class CmdReturnContainer extends ReturnContainer, Cmd {
560+
final override StmtNode getANode() { result.getStmtNode().getStmt() = this }
561+
562+
final override ReturnContainer getAChild() { none() }
563+
}
564+
565+
class NormalReturnNode extends ReturnNode instanceof NodeImpl {
566+
NormalReturnNode() {
567+
exists(ReturnContainer container |
568+
container = this.getEnclosingCallable().asCfgScope() and
569+
this = container.getAReturnedNode()
570+
)
571+
}
572+
573+
final override NormalReturnKind getKind() { any() }
574+
}
493575
}
494576

495577
import ReturnNodes
@@ -501,7 +583,13 @@ abstract class OutNode extends Node {
501583
}
502584

503585
private module OutNodes {
504-
// TODO
586+
/** A data-flow node that reads a value returned directly by a callable */
587+
class CallOutNode extends OutNode instanceof CallNode {
588+
override DataFlowCall getCall(ReturnKind kind) {
589+
result.asCall() = super.getCallNode() and
590+
kind instanceof NormalReturnKind
591+
}
592+
}
505593
}
506594

507595
import OutNodes

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

Lines changed: 23 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -33,15 +33,25 @@ class Node extends TNode {
3333
Node getASuccessor() { localFlowStep(this, result) }
3434
}
3535

36+
/** A control-flow node, viewed as a node in a data flow graph. */
37+
abstract private class AbstractAstNode extends Node {
38+
CfgNodes::AstCfgNode n;
39+
40+
/** Gets the control-flow node corresponding to this node. */
41+
CfgNodes::AstCfgNode getCfgNode() { result = n }
42+
}
43+
44+
final class AstNode = AbstractAstNode;
45+
3646
/**
3747
* An expression, viewed as a node in a data flow graph.
3848
*
3949
* Note that because of control-flow splitting, one `Expr` may correspond
4050
* to multiple `ExprNode`s, just like it may correspond to multiple
4151
* `ControlFlow::Node`s.
4252
*/
43-
class ExprNode extends Node, TExprNode {
44-
private CfgNodes::ExprCfgNode n;
53+
class ExprNode extends AbstractAstNode, TExprNode {
54+
override CfgNodes::ExprCfgNode n;
4555

4656
ExprNode() { this = TExprNode(n) }
4757

@@ -56,8 +66,8 @@ class ExprNode extends Node, TExprNode {
5666
* to multiple `StmtNode`s, just like it may correspond to multiple
5767
* `ControlFlow::Node`s.
5868
*/
59-
class StmtNode extends Node, TStmtNode {
60-
private CfgNodes::StmtCfgNode n;
69+
class StmtNode extends AbstractAstNode, TStmtNode {
70+
override CfgNodes::StmtCfgNode n;
6171

6272
StmtNode() { this = TStmtNode(n) }
6373

@@ -312,3 +322,12 @@ class ObjectCreationNode extends Node {
312322

313323
final CfgNodes::ObjectCreationCfgNode getObjectCreationNode() { result = objectCreation }
314324
}
325+
326+
/** A call, viewed as a node in a data flow graph. */
327+
class CallNode extends AstNode {
328+
CfgNodes::CallCfgNode call;
329+
330+
CallNode() { call = this.getCfgNode() }
331+
332+
CfgNodes::CallCfgNode getCallNode() { result = call }
333+
}
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
models
2+
edges
3+
| test.ps1:2:5:2:15 | Source | test.ps1:5:6:5:20 | callSourceOnce | provenance | |
4+
| test.ps1:5:6:5:20 | callSourceOnce | test.ps1:6:6:6:8 | x | provenance | |
5+
| test.ps1:9:5:9:15 | Source | test.ps1:13:6:13:21 | callSourceTwice | provenance | |
6+
| test.ps1:10:5:10:15 | Source | test.ps1:13:6:13:21 | callSourceTwice | provenance | |
7+
| test.ps1:13:6:13:21 | callSourceTwice | test.ps1:14:6:14:8 | x | provenance | |
8+
| test.ps1:17:12:17:22 | Source | test.ps1:20:6:20:19 | returnSource1 | provenance | |
9+
| test.ps1:20:6:20:19 | returnSource1 | test.ps1:21:6:21:8 | x | provenance | |
10+
| test.ps1:24:10:24:20 | Source | test.ps1:25:5:25:7 | x | provenance | |
11+
| test.ps1:25:5:25:7 | x | test.ps1:30:6:30:19 | returnSource2 | provenance | |
12+
| test.ps1:26:10:26:20 | Source | test.ps1:27:12:27:14 | y | provenance | |
13+
| test.ps1:27:12:27:14 | y | test.ps1:30:6:30:19 | returnSource2 | provenance | |
14+
| test.ps1:30:6:30:19 | returnSource2 | test.ps1:31:6:31:8 | x | provenance | |
15+
nodes
16+
| test.ps1:2:5:2:15 | Source | semmle.label | Source |
17+
| test.ps1:5:6:5:20 | callSourceOnce | semmle.label | callSourceOnce |
18+
| test.ps1:6:6:6:8 | x | semmle.label | x |
19+
| test.ps1:9:5:9:15 | Source | semmle.label | Source |
20+
| test.ps1:10:5:10:15 | Source | semmle.label | Source |
21+
| test.ps1:13:6:13:21 | callSourceTwice | semmle.label | callSourceTwice |
22+
| test.ps1:14:6:14:8 | x | semmle.label | x |
23+
| test.ps1:17:12:17:22 | Source | semmle.label | Source |
24+
| test.ps1:20:6:20:19 | returnSource1 | semmle.label | returnSource1 |
25+
| test.ps1:21:6:21:8 | x | semmle.label | x |
26+
| test.ps1:24:10:24:20 | Source | semmle.label | Source |
27+
| test.ps1:25:5:25:7 | x | semmle.label | x |
28+
| test.ps1:26:10:26:20 | Source | semmle.label | Source |
29+
| test.ps1:27:12:27:14 | y | semmle.label | y |
30+
| test.ps1:30:6:30:19 | returnSource2 | semmle.label | returnSource2 |
31+
| test.ps1:31:6:31:8 | x | semmle.label | x |
32+
subpaths
33+
testFailures
34+
#select
35+
| test.ps1:6:6:6:8 | x | test.ps1:2:5:2:15 | Source | test.ps1:6:6:6:8 | x | $@ | test.ps1:2:5:2:15 | Source | Source |
36+
| test.ps1:14:6:14:8 | x | test.ps1:9:5:9:15 | Source | test.ps1:14:6:14:8 | x | $@ | test.ps1:9:5:9:15 | Source | Source |
37+
| test.ps1:14:6:14:8 | x | test.ps1:10:5:10:15 | Source | test.ps1:14:6:14:8 | x | $@ | test.ps1:10:5:10:15 | Source | Source |
38+
| test.ps1:21:6:21:8 | x | test.ps1:17:12:17:22 | Source | test.ps1:21:6:21:8 | x | $@ | test.ps1:17:12:17:22 | Source | Source |
39+
| test.ps1:31:6:31:8 | x | test.ps1:24:10:24:20 | Source | test.ps1:31:6:31:8 | x | $@ | test.ps1:24:10:24:20 | Source | Source |
40+
| test.ps1:31:6:31:8 | x | test.ps1:26:10:26:20 | Source | test.ps1:31:6:31:8 | x | $@ | test.ps1:26:10:26:20 | Source | Source |
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
function callSourceOnce {
2+
Source "1"
3+
}
4+
5+
$x = callSourceOnce
6+
Sink $x # $ hasValueFlow=1
7+
8+
function callSourceTwice {
9+
Source "2"
10+
Source "3"
11+
}
12+
13+
$x = callSourceTwice
14+
Sink $x # $ hasValueFlow=2 hasValueFlow=3
15+
16+
function returnSource1 {
17+
return Source "4"
18+
}
19+
20+
$x = returnSource1
21+
Sink $x # $ hasValueFlow=4
22+
23+
function returnSource2 {
24+
$x = Source "5"
25+
$x
26+
$y = Source "6"
27+
return $y
28+
}
29+
30+
$x = returnSource2
31+
Sink $x # $ hasValueFlow=5 hasValueFlow=6
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/**
2+
* @kind path-problem
3+
*/
4+
5+
import powershell
6+
import semmle.code.powershell.dataflow.DataFlow
7+
private import TestUtilities.InlineFlowTest
8+
import DefaultFlowTest
9+
import ValueFlow::PathGraph
10+
11+
from ValueFlow::PathNode source, ValueFlow::PathNode sink
12+
where ValueFlow::flowPath(source, sink)
13+
select sink, source, sink, "$@", source, source.toString()

0 commit comments

Comments
 (0)