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 caff6ed8db3..8f19015426f 100644 --- a/powershell/ql/lib/semmle/code/powershell/controlflow/internal/ControlFlowGraphImpl.qll +++ b/powershell/ql/lib/semmle/code/powershell/controlflow/internal/ControlFlowGraphImpl.qll @@ -75,7 +75,95 @@ predicate succExit(CfgScope scope, Ast last, Completion c) { scope.exit(last, c) /** Defines the CFG by dispatch on the various AST types. */ module Trees { - // TODO + class ScriptBlockTree extends PreOrderTree instanceof ScriptBlock { + final override predicate last(AstNode last, Completion c) { + last(super.getEndBlock(), last, c) + or + not exists(super.getEndBlock()) and + last(super.getProcessBlock(), last, c) + or + not exists(super.getEndBlock()) and + not exists(super.getProcessBlock()) and + last(super.getBeginBlock(), last, c) + or + not exists(super.getEndBlock()) and + not exists(super.getProcessBlock()) and + not exists(super.getBeginBlock()) and + last = this and + completionIsSimple(c) + } + + final override predicate propagatesAbnormal(AstNode child) { + child = [super.getBeginBlock(), super.getProcessBlock(), super.getEndBlock()] + } + + final override predicate succ(AstNode pred, AstNode succ, Completion c) { + pred = this and + ( + first(super.getBeginBlock(), succ) + or + not exists(super.getBeginBlock()) and + first(super.getProcessBlock(), succ) + or + not exists(super.getBeginBlock()) and + not exists(super.getProcessBlock()) and + first(super.getEndBlock(), succ) + ) and + completionIsSimple(c) + or + last(super.getBeginBlock(), pred, c) and + c instanceof NormalCompletion and + ( + first(super.getProcessBlock(), succ) + or + not exists(super.getProcessBlock()) and + first(super.getEndBlock(), succ) + or + not exists(super.getProcessBlock()) and + not exists(super.getEndBlock()) and + succ = this + ) + or + last(super.getProcessBlock(), pred, c) and + c instanceof NormalCompletion 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) + ) + } + } + + class NamedBlockTree extends StandardPostOrderTree instanceof NamedBlock { + // TODO: Handle trap + override AstNode getChildNode(int i) { result = super.getStatement(i) } + } + + class AssignStmtTree extends StandardPostOrderTree instanceof AssignStmt { + override AstNode getChildNode(int i) { + i = 0 and result = super.getLeftHandSide() + or + i = 1 and result = super.getRightHandSide() + } + } + + class VarAccessTree extends LeafTree instanceof VarAccess { } + + class BinaryExprTree extends StandardPostOrderTree instanceof BinaryExpr { + override AstNode getChildNode(int i) { + i = 0 and result = super.getLeft() + or + i = 1 and result = super.getRight() + } + } + + class ConstExprTree extends LeafTree instanceof ConstExpr { } + + class CmdExprTree extends StandardPreOrderTree instanceof CmdExpr { + override AstNode getChildNode(int i) { i = 0 and result = super.getExpr() } + } } private import Scope diff --git a/powershell/ql/test/library-tests/controlflow/graph/Cfg.expected b/powershell/ql/test/library-tests/controlflow/graph/Cfg.expected index e69de29bb2d..306b95b03ac 100644 --- a/powershell/ql/test/library-tests/controlflow/graph/Cfg.expected +++ b/powershell/ql/test/library-tests/controlflow/graph/Cfg.expected @@ -0,0 +1,59 @@ +global.ps1: +# 1| {...} +#-----| -> c + +# 1| enter global.ps1 +#-----| -> global.ps1 + +# 1| exit global.ps1 + +# 1| exit global.ps1 (normal) +#-----| -> exit global.ps1 + +# 1| global.ps1 +#-----| -> a + +# 2| a +#-----| -> 1 + +# 2| ...=... +#-----| -> b + +# 2| 1 +#-----| -> ...=... + +# 2| 1 +#-----| -> 1 + +# 3| b +#-----| -> 2 + +# 3| ...=... +#-----| -> {...} + +# 3| 2 +#-----| -> ...=... + +# 3| 2 +#-----| -> 2 + +# 5| {...} +#-----| -> exit global.ps1 (normal) + +# 6| c +#-----| -> ...+... + +# 6| ...=... +#-----| -> {...} + +# 6| a +#-----| -> b + +# 6| ...+... +#-----| -> ...=... + +# 6| ...+... +#-----| -> a + +# 6| b +#-----| -> ...+... diff --git a/powershell/ql/test/library-tests/controlflow/graph/global.ps1 b/powershell/ql/test/library-tests/controlflow/graph/global.ps1 index 003957e2830..e5df15a2fbd 100644 --- a/powershell/ql/test/library-tests/controlflow/graph/global.ps1 +++ b/powershell/ql/test/library-tests/controlflow/graph/global.ps1 @@ -1,3 +1,7 @@ -$a = 1 -$b = 2 -$c = $a + $b \ No newline at end of file +Begin { + $a = 1 + $b = 2 +} +End { + $c = $a + $b +} \ No newline at end of file