Merge pull request #180 from microsoft/powershell-ast-modernization-follow-up

PS: Fix PowerShell dataflow/taint-tracking failures
This commit is contained in:
Mathias Vorreiter Pedersen
2025-03-28 13:19:00 -07:00
committed by GitHub
18 changed files with 590 additions and 346 deletions

View File

@@ -53,5 +53,13 @@ class If extends Expr, TIf {
)
}
StmtBlock getABranch(boolean b) {
b = true and result = this.getAThen()
or
b = false and result = this.getElse()
}
StmtBlock getABranch() { result = this.getAThen() or result = this.getElse() }
predicate hasElse() { exists(this.getElse()) }
}

View File

@@ -79,6 +79,9 @@ class ScriptBlock extends Ast, TScriptBlock {
result = this.getParameter(index)
)
or
i = ThisVar() and
result = this.getThisParameter()
or
exists(int index |
i = scriptBlockUsing(index) and
result = this.getUsingStmt(index)
@@ -90,13 +93,14 @@ class ScriptBlock extends Ast, TScriptBlock {
or
any(Synthesis s).pipelineParameterHasIndex(this, i) and
synthChild(getRawAst(this), PipelineParamVar(), result)
or
i = -1 and
synthChild(getRawAst(this), ThisVar(), result)
}
Parameter getThisParameter() { synthChild(getRawAst(this), ThisVar(), result) }
/**
* Gets a parameter of this block.
*
* Note: This does not include the `this` parameter, but it does include pipeline parameters.
*/
Parameter getAParameter() { result = this.getParameter(_) }

View File

@@ -84,6 +84,8 @@ class Synthesis extends TSynthesis {
predicate functionName(FunctionBase f, string name) { none() }
predicate getAnAccess(VarAccessSynth va, Variable v) { none() }
predicate memberName(Member m, string name) { none() }
predicate typeName(Type t, string name) { none() }
@@ -116,13 +118,26 @@ Raw::Ast getRawAst(Ast r) { r = getResultAst(result) }
private module ThisSynthesis {
private class ThisSynthesis extends Synthesis {
private predicate thisAccess(Raw::Ast parent, ChildIndex i, Child child, Raw::Scope scope) {
scope = parent.getScope() and
parent.getChild(toRawChildIndex(i)).(Raw::VarAccess).getUserPath().toLowerCase() = "this" and
child = SynthChild(VarAccessSynthKind(TVariableSynth(scope, ThisVar())))
}
override predicate child(Raw::Ast parent, ChildIndex i, Child child) {
parent instanceof Raw::MethodScriptBlock and
i = ThisVar() and
child = SynthChild(VarSynthKind(ThisVarKind()))
or
parent.getChild(toRawChildIndex(i)).(Raw::VarAccess).getUserPath().toLowerCase() = "this" and
child = SynthChild(VarAccessSynthKind(TVariableSynth(parent.getScope(), ThisVar())))
this.thisAccess(parent, i, child, _)
}
final override predicate getAnAccess(VarAccessSynth va, Variable v) {
exists(Raw::Ast parent, Raw::Scope scope, ChildIndex i |
this.thisAccess(parent, i, _, scope) and
v = TVariableSynth(scope, ThisVar()) and
va = TVarAccessSynth(parent, i)
)
}
override predicate variableSynthName(VariableSynth v, string name) {
@@ -731,18 +746,26 @@ private module IteratorAccessSynth {
)
}
final override predicate getAnAccess(VarAccessSynth va, Variable v) {
exists(Raw::Ast parent, ChildIndex i, Raw::VarAccess r |
this.expr(parent, i, r, _) and
va = TVarAccessSynth(parent, i) and
v = this.varAccess(r)
)
}
override predicate exprStmtExpr(ExprStmt e, Expr expr) {
exists(Raw::Ast p, Raw::VarAccess va, Raw::CmdExpr cmdExpr, ChildIndex i1, ChildIndex i2 |
this.stmt(p, i1, _, _) and
this.expr(cmdExpr, i2, va, _) and
e = TExprStmtSynth(p, i1) and
expr = TVarAccessSynth(cmdExpr, i2, this.varAccess(va))
expr = TVarAccessSynth(cmdExpr, i2)
)
}
final override Expr getResultAstImpl(Raw::Ast r) {
exists(Raw::Ast parent, ChildIndex i | this.expr(parent, i, r, _) |
result = TVarAccessSynth(parent, i, this.varAccess(r))
result = TVarAccessSynth(parent, i)
)
}

View File

@@ -61,7 +61,7 @@ private predicate hasScopeAndName(VariableImpl variable, Scope::Range scope, str
scope = variable.getDeclaringScopeImpl()
}
private predicate access(Raw::VarAccess va, VariableImpl v) {
predicate access(Raw::VarAccess va, VariableImpl v) {
exists(string name, Scope::Range scope |
pragma[only_bind_into](name) = variableNameInScope(va, scope)
|
@@ -150,11 +150,11 @@ private module Cached {
)
} or
TVariableSynth(Raw::Ast scope, ChildIndex i) { mkSynthChild(VarSynthKind(_), scope, i) } or
TVarAccessReal(Raw::VarAccess va, Variable v) { access(va, v) } or
TVarAccessSynth(Raw::Ast parent, ChildIndex i, Variable v) {
mkSynthChild(VarAccessRealKind(v), parent, i)
TVarAccessReal(Raw::VarAccess va) { access(va, _) } or
TVarAccessSynth(Raw::Ast parent, ChildIndex i) {
mkSynthChild(VarAccessRealKind(_), parent, i)
or
mkSynthChild(VarAccessSynthKind(v), parent, i)
mkSynthChild(VarAccessSynthKind(_), parent, i)
} or
TWhileStmt(Raw::WhileStmt w) or
TTypeNameExpr(Raw::TypeNameExpr t) or
@@ -277,7 +277,7 @@ private module Cached {
n = TTypeConstraint(result) or
n = TUnaryExpr(result) or
n = TUsingStmt(result) or
n = TVarAccessReal(result, _) or
n = TVarAccessReal(result) or
n = TWhileStmt(result) or
n = TFunctionDefinitionStmt(result) or
n = TExpandableSubExpr(result) or
@@ -308,7 +308,7 @@ private module Cached {
result = TFunctionSynth(parent, i) or
result = TBoolLiteral(parent, i) or
result = TNullLiteral(parent, i) or
result = TVarAccessSynth(parent, i, _) or
result = TVarAccessSynth(parent, i) or
result = TEnvVariable(parent, i) or
result = TTypeSynth(parent, i) or
result = TAutomaticVariable(parent, i) or

View File

@@ -95,25 +95,23 @@ module Private {
class VarAccessReal extends VarAccessImpl, TVarAccessReal {
Raw::VarAccess va;
Variable v;
VarAccessReal() { this = TVarAccessReal(va, v) }
VarAccessReal() { this = TVarAccessReal(va) }
final override Variable getVariableImpl() { result = v }
final override Variable getVariableImpl() { access(va, result) }
final override string toString() { result = v.getName() }
final override string toString() { result = va.getUserPath() }
}
class VarAccessSynth extends VarAccessImpl, TVarAccessSynth {
Raw::Ast parent;
ChildIndex i;
Variable v;
VarAccessSynth() { this = TVarAccessSynth(parent, i, v) }
VarAccessSynth() { this = TVarAccessSynth(parent, i) }
final override Variable getVariableImpl() { result = v }
final override Variable getVariableImpl() { any(Synthesis s).getAnAccess(this, result) }
final override string toString() { result = v.getName() }
final override string toString() { result = this.getVariableImpl().getName() }
final override Location getLocation() { result = parent.getLocation() }
}

View File

@@ -284,6 +284,26 @@ class ProcessBlockCfgNode extends NamedBlockCfgNode {
ScriptBlockCfgNode getScriptBlock() { result.getProcessBlock() = this }
}
private class CatchClauseChildMapping extends NonExprChildMapping, CatchClause {
override predicate relevantChild(Ast child) {
child = this.getBody() or child = this.getACatchType()
}
}
class CatchClauseCfgNode extends AstCfgNode {
override string getAPrimaryQlClass() { result = "CatchClauseCfgNode" }
CatchClauseChildMapping s;
CatchClause getCatchClause() { result = s }
StmtCfgNode getBody() { s.hasCfgChild(s.getBody(), this, result) }
TypeConstraint getCatchType(int i) { result = s.getCatchType(i) }
TypeConstraint getACatchType() { result = this.getCatchType(_) }
}
module ExprNodes {
private class ArrayExprChildMapping extends ExprChildMapping, ArrayExpr {
override predicate relevantChild(Ast child) {
@@ -371,7 +391,7 @@ module ExprNodes {
ExprCfgNode getOperand() { e.hasCfgChild(e.getOperand(), this, result) }
}
class ConstExprChildMapping extends ExprChildMapping, ConstExpr {
private class ConstExprChildMapping extends ExprChildMapping, ConstExpr {
override predicate relevantChild(Ast child) { none() }
}
@@ -383,7 +403,7 @@ module ExprNodes {
override ConstExpr getExpr() { result = e }
}
class ConvertExprChildMapping extends ExprChildMapping, ConvertExpr {
private class ConvertExprChildMapping extends ExprChildMapping, ConvertExpr {
override predicate relevantChild(Ast child) { child = this.getExpr() }
}
@@ -397,7 +417,7 @@ module ExprNodes {
ExprCfgNode getSubExpr() { e.hasCfgChild(e.getExpr(), this, result) }
}
class IndexExprChildMapping extends ExprChildMapping, IndexExpr {
private class IndexExprChildMapping extends ExprChildMapping, IndexExpr {
override predicate relevantChild(Ast child) {
child = this.getBase()
or
@@ -457,7 +477,7 @@ module ExprNodes {
override IndexExprReadAccess getExpr() { result = e }
}
class CallExprChildMapping extends ExprChildMapping, CallExpr {
private class CallExprChildMapping extends ExprChildMapping, CallExpr {
override predicate relevantChild(Ast child) {
child = this.getQualifier()
or
@@ -503,7 +523,7 @@ module ExprNodes {
predicate isStatic() { this.getExpr().isStatic() }
}
class ObjectCreationChildMapping extends CallExprChildMapping instanceof ObjectCreation {
private class ObjectCreationChildMapping extends CallExprChildMapping instanceof ObjectCreation {
override predicate relevantChild(Ast child) { child = super.getConstructedTypeExpr() }
}
@@ -522,7 +542,7 @@ module ExprNodes {
}
}
class CallOperatorChildMapping extends CallExprChildMapping instanceof CallOperator {
private class CallOperatorChildMapping extends CallExprChildMapping instanceof CallOperator {
override predicate relevantChild(Ast child) { none() }
}
@@ -536,7 +556,7 @@ module ExprNodes {
ExprCfgNode getCommand() { result = this.getArgument(0) }
}
class MemberExprChildMapping extends ExprChildMapping, MemberExpr {
private class MemberExprChildMapping extends ExprChildMapping, MemberExpr {
override predicate relevantChild(Ast child) {
child = this.getQualifier()
or
@@ -603,7 +623,7 @@ module ExprNodes {
override MemberExprReadAccess getExpr() { result = e }
}
class TypeNameExprChildMapping extends ExprChildMapping, TypeNameExpr {
private class TypeNameExprChildMapping extends ExprChildMapping, TypeNameExpr {
override predicate relevantChild(Ast child) { none() }
}
@@ -631,7 +651,7 @@ module ExprNodes {
override QualifiedTypeNameExpr getExpr() { result = e }
}
class ErrorExprChildMapping extends ExprChildMapping, ErrorExpr {
private class ErrorExprChildMapping extends ExprChildMapping, ErrorExpr {
override predicate relevantChild(Ast child) { none() }
}
@@ -643,7 +663,7 @@ module ExprNodes {
override ErrorExpr getExpr() { result = e }
}
class ScriptBlockExprChildMapping extends ExprChildMapping, ScriptBlockExpr {
private class ScriptBlockExprChildMapping extends ExprChildMapping, ScriptBlockExpr {
override predicate relevantChild(Ast child) { child = this.getBody() }
}
@@ -657,7 +677,7 @@ module ExprNodes {
ScriptBlockCfgNode getBody() { e.hasCfgChild(e.getBody(), this, result) }
}
class StringLiteralExprChildMapping extends ExprChildMapping, StringConstExpr {
private class StringLiteralExprChildMapping extends ExprChildMapping, StringConstExpr {
override predicate relevantChild(Ast child) { none() }
}
@@ -671,7 +691,7 @@ module ExprNodes {
string getValueString() { result = e.getValueString() }
}
class ExpandableStringExprChildMapping extends ExprChildMapping, ExpandableStringExpr {
private class ExpandableStringExprChildMapping extends ExprChildMapping, ExpandableStringExpr {
override predicate relevantChild(Ast child) { child = this.getAnExpr() }
}
@@ -728,7 +748,7 @@ module ExprNodes {
override VarReadAccess getExpr() { result = e }
}
class HashTableExprChildMapping extends ExprChildMapping, HashTableExpr {
private class HashTableExprChildMapping extends ExprChildMapping, HashTableExpr {
override predicate relevantChild(Ast child) {
child = this.getAKey()
or
@@ -747,7 +767,7 @@ module ExprNodes {
ExprCfgNode getAnKey() { result = this.getKey(_) }
ExprCfgNode getValue(int i) { e.hasCfgChild(e.getKey(i), this, result) }
ExprCfgNode getValue(int i) { e.hasCfgChild(e.getValue(i), this, result) }
ExprCfgNode getValueFromKey(ExprCfgNode key) {
exists(int i |
@@ -759,7 +779,7 @@ module ExprNodes {
ExprCfgNode getAValue() { result = this.getValue(_) }
}
class PipelineChildMapping extends ExprChildMapping, Pipeline {
private class PipelineChildMapping extends ExprChildMapping, Pipeline {
override predicate relevantChild(Ast child) { child = this.getAComponent() }
}
@@ -775,7 +795,7 @@ module ExprNodes {
ExprCfgNode getAComponent() { result = this.getComponent(_) }
}
class PipelineChainChildMapping extends ExprChildMapping, PipelineChain {
private class PipelineChainChildMapping extends ExprChildMapping, PipelineChain {
override predicate relevantChild(Ast child) {
child = this.getLeft() or child = this.getRight()
}
@@ -793,7 +813,7 @@ module ExprNodes {
ExprCfgNode getRight() { e.hasCfgChild(e.getRight(), this, result) }
}
class ConditionalExprChildMapping extends ExprChildMapping, ConditionalExpr {
private class ConditionalExprChildMapping extends ExprChildMapping, ConditionalExpr {
override predicate relevantChild(Ast child) {
child = this.getCondition()
or
@@ -827,7 +847,7 @@ module ExprNodes {
ExprCfgNode getABranch() { result = this.getBranch(_) }
}
class ExpandableSubExprChildMapping extends ExprChildMapping, ExpandableSubExpr {
private class ExpandableSubExprChildMapping extends ExprChildMapping, ExpandableSubExpr {
override predicate relevantChild(Ast child) { child = this.getExpr() }
}
@@ -841,7 +861,7 @@ module ExprNodes {
ExprCfgNode getSubExpr() { e.hasCfgChild(e.getExpr(), this, result) }
}
class UsingExprChildMapping extends ExprChildMapping, UsingExpr {
private class UsingExprChildMapping extends ExprChildMapping, UsingExpr {
override predicate relevantChild(Ast child) { child = this.getExpr() }
}
@@ -855,7 +875,7 @@ module ExprNodes {
ExprCfgNode getSubExpr() { e.hasCfgChild(e.getExpr(), this, result) }
}
class AttributedExprChildMapping extends ExprChildMapping, AttributedExpr {
private class AttributedExprChildMapping extends ExprChildMapping, AttributedExpr {
override predicate relevantChild(Ast child) {
child = this.getExpr() or
child = this.getAttribute()
@@ -874,7 +894,7 @@ module ExprNodes {
ExprCfgNode getAttribute() { e.hasCfgChild(e.getAttribute(), this, result) }
}
class IfChildMapping extends ExprChildMapping, If {
private class IfChildMapping extends ExprChildMapping, If {
override predicate relevantChild(Ast child) {
child = this.getACondition()
or
@@ -900,9 +920,19 @@ module ExprNodes {
StmtCfgNode getAThen() { result = this.getThen(_) }
StmtCfgNode getElse() { e.hasCfgChild(e.getElse(), this, result) }
StmtCfgNode getABranch(boolean b) {
b = true and
result = this.getAThen()
or
b = false and
result = this.getElse()
}
StmtCfgNode getABranch() { result = this.getABranch(_) }
}
class LiteralChildMapping extends ExprChildMapping, Literal {
private class LiteralChildMapping extends ExprChildMapping, Literal {
override predicate relevantChild(Ast child) { none() }
}
@@ -914,7 +944,7 @@ module ExprNodes {
override Literal getExpr() { result = e }
}
class BoolLiteralChildMapping extends ExprChildMapping, BoolLiteral {
private class BoolLiteralChildMapping extends ExprChildMapping, BoolLiteral {
override predicate relevantChild(Ast child) { none() }
}
@@ -926,7 +956,7 @@ module ExprNodes {
override BoolLiteral getExpr() { result = e }
}
class NullLiteralChildMapping extends ExprChildMapping, NullLiteral {
private class NullLiteralChildMapping extends ExprChildMapping, NullLiteral {
override predicate relevantChild(Ast child) { none() }
}
@@ -1004,7 +1034,7 @@ module StmtNodes {
ExprCfgNode getRightHandSide() { s.hasCfgChild(s.getRightHandSide(), this, result) }
}
class BreakStmtChildMapping extends NonExprChildMapping, BreakStmt {
private class BreakStmtChildMapping extends NonExprChildMapping, BreakStmt {
override predicate relevantChild(Ast child) { none() }
}
@@ -1016,7 +1046,7 @@ module StmtNodes {
override BreakStmt getStmt() { result = s }
}
class ContinueStmtChildMapping extends NonExprChildMapping, ContinueStmt {
private class ContinueStmtChildMapping extends NonExprChildMapping, ContinueStmt {
override predicate relevantChild(Ast child) { none() }
}
@@ -1028,7 +1058,7 @@ module StmtNodes {
override ContinueStmt getStmt() { result = s }
}
class DataStmtChildMapping extends NonExprChildMapping, DataStmt {
private class DataStmtChildMapping extends NonExprChildMapping, DataStmt {
override predicate relevantChild(Ast child) {
child = this.getACmdAllowed() or child = this.getBody()
}
@@ -1048,13 +1078,27 @@ module StmtNodes {
StmtCfgNode getBody() { s.hasCfgChild(s.getBody(), this, result) }
}
class DoUntilStmtChildMapping extends NonExprChildMapping, DoUntilStmt {
private class LoopStmtChildMapping extends NonExprChildMapping, LoopStmt {
override predicate relevantChild(Ast child) { child = this.getBody() }
}
class LoopStmtCfgNode extends StmtCfgNode {
override string getAPrimaryQlClass() { result = "LoopStmtCfgNode" }
override LoopStmtChildMapping s;
override LoopStmt getStmt() { result = s }
StmtCfgNode getBody() { s.hasCfgChild(s.getBody(), this, result) }
}
private class DoUntilStmtChildMapping extends LoopStmtChildMapping, DoUntilStmt {
override predicate relevantChild(Ast child) {
child = this.getCondition() or child = this.getBody()
child = this.getCondition() or super.relevantChild(child)
}
}
class DoUntilStmtCfgNode extends StmtCfgNode {
class DoUntilStmtCfgNode extends LoopStmtCfgNode {
override string getAPrimaryQlClass() { result = "DoUntilStmtCfgNode" }
override DoUntilStmtChildMapping s;
@@ -1062,17 +1106,15 @@ module StmtNodes {
override DoUntilStmt getStmt() { result = s }
ExprCfgNode getCondition() { s.hasCfgChild(s.getCondition(), this, result) }
StmtCfgNode getBody() { s.hasCfgChild(s.getBody(), this, result) }
}
class DoWhileStmtChildMapping extends NonExprChildMapping, DoWhileStmt {
private class DoWhileStmtChildMapping extends LoopStmtChildMapping, DoWhileStmt {
override predicate relevantChild(Ast child) {
child = this.getCondition() or child = this.getBody()
child = this.getCondition() or super.relevantChild(child)
}
}
class DoWhileStmtCfgNode extends StmtCfgNode {
class DoWhileStmtCfgNode extends LoopStmtCfgNode {
override string getAPrimaryQlClass() { result = "DoWhileStmtCfgNode" }
override DoWhileStmtChildMapping s;
@@ -1080,11 +1122,9 @@ module StmtNodes {
override DoWhileStmt getStmt() { result = s }
ExprCfgNode getCondition() { s.hasCfgChild(s.getCondition(), this, result) }
StmtCfgNode getBody() { s.hasCfgChild(s.getBody(), this, result) }
}
class ErrorStmtChildMapping extends NonExprChildMapping, ErrorStmt {
private class ErrorStmtChildMapping extends NonExprChildMapping, ErrorStmt {
override predicate relevantChild(Ast child) { none() }
}
@@ -1096,7 +1136,7 @@ module StmtNodes {
override ErrorStmt getStmt() { result = s }
}
class ExitStmtChildMapping extends NonExprChildMapping, ExitStmt {
private class ExitStmtChildMapping extends NonExprChildMapping, ExitStmt {
override predicate relevantChild(Ast child) { child = this.getPipeline() }
}
@@ -1110,7 +1150,7 @@ module StmtNodes {
ExprCfgNode getPipeline() { s.hasCfgChild(s.getPipeline(), this, result) }
}
class DynamicStmtChildMapping extends NonExprChildMapping, DynamicStmt {
private class DynamicStmtChildMapping extends NonExprChildMapping, DynamicStmt {
override predicate relevantChild(Ast child) {
child = this.getName() or child = this.getScriptBlock() or child = this.getHashTableExpr()
}
@@ -1130,13 +1170,13 @@ module StmtNodes {
ExprCfgNode getHashTableExpr() { s.hasCfgChild(s.getHashTableExpr(), this, result) }
}
class ForEachStmtChildMapping extends NonExprChildMapping, ForEachStmt {
private class ForEachStmtChildMapping extends LoopStmtChildMapping, ForEachStmt {
override predicate relevantChild(Ast child) {
child = this.getVarAccess() or child = this.getIterableExpr() or child = this.getBody()
child = this.getVarAccess() or child = this.getIterableExpr() or super.relevantChild(child)
}
}
class ForEachStmtCfgNode extends StmtCfgNode {
class ForEachStmtCfgNode extends LoopStmtCfgNode {
override string getAPrimaryQlClass() { result = "ForEachStmtCfgNode" }
override ForEachStmtChildMapping s;
@@ -1146,20 +1186,18 @@ module StmtNodes {
ExprCfgNode getVarAccess() { s.hasCfgChild(s.getVarAccess(), this, result) }
ExprCfgNode getIterableExpr() { s.hasCfgChild(s.getIterableExpr(), this, result) }
StmtCfgNode getBody() { s.hasCfgChild(s.getBody(), this, result) }
}
class ForStmtChildMapping extends NonExprChildMapping, ForStmt {
private class ForStmtChildMapping extends LoopStmtChildMapping, ForStmt {
override predicate relevantChild(Ast child) {
child = this.getInitializer() or
child = this.getCondition() or
child = this.getIterator() or
child = this.getBody()
super.relevantChild(child)
}
}
class ForStmtCfgNode extends StmtCfgNode {
class ForStmtCfgNode extends LoopStmtCfgNode {
override string getAPrimaryQlClass() { result = "ForStmtCfgNode" }
override ForStmtChildMapping s;
@@ -1171,11 +1209,9 @@ module StmtNodes {
ExprCfgNode getCondition() { s.hasCfgChild(s.getCondition(), this, result) }
AstCfgNode getIterator() { s.hasCfgChild(s.getIterator(), this, result) }
StmtCfgNode getBody() { s.hasCfgChild(s.getBody(), this, result) }
}
class GotoStmtChildMapping extends NonExprChildMapping, GotoStmt {
private class GotoStmtChildMapping extends NonExprChildMapping, GotoStmt {
override predicate relevantChild(Ast child) { child = this.getLabel() }
}
@@ -1189,7 +1225,7 @@ module StmtNodes {
ExprCfgNode getLabel() { s.hasCfgChild(s.getLabel(), this, result) }
}
class ReturnStmtChildMapping extends NonExprChildMapping, ReturnStmt {
private class ReturnStmtChildMapping extends NonExprChildMapping, ReturnStmt {
override predicate relevantChild(Ast child) { child = this.getPipeline() }
}
@@ -1203,7 +1239,7 @@ module StmtNodes {
ExprCfgNode getPipeline() { s.hasCfgChild(s.getPipeline(), this, result) }
}
class StmtBlockChildMapping extends NonExprChildMapping, StmtBlock {
private class StmtBlockChildMapping extends NonExprChildMapping, StmtBlock {
override predicate relevantChild(Ast child) { child = this.getAStmt() }
}
@@ -1219,7 +1255,7 @@ module StmtNodes {
StmtCfgNode getAStmt() { result = this.getStmt(_) }
}
class SwitchStmtChildMapping extends NonExprChildMapping, SwitchStmt {
private class SwitchStmtChildMapping extends NonExprChildMapping, SwitchStmt {
override predicate relevantChild(Ast child) {
child = this.getCondition() or
child = this.getDefault() or
@@ -1248,7 +1284,7 @@ module StmtNodes {
ExprCfgNode getAPattern() { result = this.getPattern(_) }
}
class ThrowStmtChildMapping extends NonExprChildMapping, ThrowStmt {
private class ThrowStmtChildMapping extends NonExprChildMapping, ThrowStmt {
override predicate relevantChild(Ast child) { child = this.getPipeline() }
}
@@ -1262,7 +1298,7 @@ module StmtNodes {
ExprCfgNode getPipeline() { s.hasCfgChild(s.getPipeline(), this, result) }
}
class TrapStmtChildMapping extends NonExprChildMapping, TrapStmt {
private class TrapStmtChildMapping extends NonExprChildMapping, TrapStmt {
override predicate relevantChild(Ast child) { child = this.getBody() }
}
@@ -1276,7 +1312,7 @@ module StmtNodes {
StmtCfgNode getBody() { s.hasCfgChild(s.getBody(), this, result) }
}
class TryStmtChildMapping extends NonExprChildMapping, TryStmt {
private class TryStmtChildMapping extends NonExprChildMapping, TryStmt {
override predicate relevantChild(Ast child) {
child = this.getBody() or
child = this.getFinally() or
@@ -1298,7 +1334,7 @@ module StmtNodes {
StmtCfgNode getCatchClause(int i) { s.hasCfgChild(s.getCatchClause(i), this, result) }
}
class UsingStmtChildMapping extends NonExprChildMapping, UsingStmt {
private class UsingStmtChildMapping extends NonExprChildMapping, UsingStmt {
override predicate relevantChild(Ast child) { none() }
}
@@ -1310,14 +1346,14 @@ module StmtNodes {
override UsingStmt getStmt() { result = s }
}
class WhileStmtChildMapping extends NonExprChildMapping, WhileStmt {
private class WhileStmtChildMapping extends LoopStmtChildMapping, WhileStmt {
override predicate relevantChild(Ast child) {
child = this.getCondition() or
child = this.getBody()
super.relevantChild(child)
}
}
class WhileStmtCfgNode extends StmtCfgNode {
class WhileStmtCfgNode extends LoopStmtCfgNode {
override string getAPrimaryQlClass() { result = "WhileStmtCfgNode" }
override WhileStmtChildMapping s;
@@ -1325,11 +1361,9 @@ module StmtNodes {
override WhileStmt getStmt() { result = s }
ExprCfgNode getCondition() { s.hasCfgChild(s.getCondition(), this, result) }
StmtCfgNode getBody() { s.hasCfgChild(s.getBody(), this, result) }
}
class ConfigurationChildMapping extends NonExprChildMapping, Configuration {
private class ConfigurationChildMapping extends NonExprChildMapping, Configuration {
override predicate relevantChild(Ast child) { child = this.getName() or child = this.getBody() }
}
@@ -1345,7 +1379,7 @@ module StmtNodes {
StmtCfgNode getBody() { s.hasCfgChild(s.getBody(), this, result) }
}
class TypeStmtChildMapping extends NonExprChildMapping, TypeDefinitionStmt {
private class TypeStmtChildMapping extends NonExprChildMapping, TypeDefinitionStmt {
override predicate relevantChild(Ast child) { none() }
}
@@ -1369,7 +1403,7 @@ module StmtNodes {
string getName() { result = s.getName() }
}
class FunctionDefinitionChildMapping extends NonExprChildMapping, FunctionDefinitionStmt {
private class FunctionDefinitionChildMapping extends NonExprChildMapping, FunctionDefinitionStmt {
override predicate relevantChild(Ast child) { none() }
}
@@ -1383,7 +1417,7 @@ module StmtNodes {
FunctionBase getFunction() { result = s.getFunction() }
}
class ExprStmtChildMapping extends NonExprChildMapping, ExprStmt {
private class ExprStmtChildMapping extends NonExprChildMapping, ExprStmt {
override predicate relevantChild(Ast child) { child = this.getExpr() }
}

View File

@@ -151,6 +151,30 @@ module Trees {
override predicate succ(AstNode pred, AstNode succ, Completion c) {
this.succEntry(pred, c) and
(
first(super.getThisParameter(), succ)
or
not exists(super.getThisParameter()) and
first(super.getParameter(0), succ)
or
not exists(super.getThisParameter()) and
not exists(super.getAParameter()) and
first(super.getBeginBlock(), succ)
or
not exists(super.getThisParameter()) and
not exists(super.getAParameter()) and
not exists(super.getBeginBlock()) and
first(super.getProcessBlock(), succ)
or
not exists(super.getThisParameter()) and
not exists(super.getAParameter()) and
not exists(super.getBeginBlock()) and
not exists(super.getProcessBlock()) and
first(super.getEndBlock(), succ)
)
or
last(super.getThisParameter(), pred, c) and
completionIsNormal(c) and
(
first(super.getParameter(0), succ)
or

View File

@@ -113,7 +113,7 @@ module Ssa {
override ThisParameter getSourceVariable() { result = v }
final override string toString() { result = "self (" + v.getDeclaringScope() + ")" }
final override string toString() { result = "this (" + v.getDeclaringScope() + ")" }
final override Location getLocation() { result = this.getControlFlowNode().getLocation() }
}

View File

@@ -8,6 +8,7 @@ private import DataFlowDispatch
private import SsaImpl as SsaImpl
private import FlowSummaryImpl as FlowSummaryImpl
private import semmle.code.powershell.frameworks.data.ModelsAsData
private import PipelineReturns as PipelineReturns
/** Gets the callable in which this node occurs. */
DataFlowCallable nodeGetEnclosingCallable(Node n) { result = n.(NodeImpl).getEnclosingCallable() }
@@ -61,6 +62,8 @@ module SsaFlow {
private ParameterNodeImpl toParameterNode(SsaImpl::ParameterExt p) {
result = TNormalParameterNode(p.asParameter())
or
result = TThisParameterNode(p.asThis())
}
Impl::Node asNode(Node n) {
@@ -85,6 +88,16 @@ module SsaFlow {
}
}
private module ArrayExprFlow {
private module Input implements PipelineReturns::InputSig {
predicate isSource(CfgNodes::AstCfgNode source) {
source = any(CfgNodes::ExprNodes::ArrayExprCfgNode ae).getStmtBlock()
}
}
import PipelineReturns::Make<Input>
}
/** Provides predicates related to local data flow. */
module LocalFlow {
pragma[nomagic]
@@ -97,16 +110,13 @@ module LocalFlow {
or
nodeFrom.asExpr() = nodeTo.asExpr().(CfgNodes::ExprNodes::ParenExprCfgNode).getSubExpr()
or
exists(
CfgNodes::ExprNodes::ArrayExprCfgNode arrayExpr, EscapeContainer::EscapeContainer container
|
nodeTo.asExpr() = arrayExpr and
container = arrayExpr.getStmtBlock().getAstNode() and
nodeFrom.(AstNode).getCfgNode() = container.getAnEscapingElement() and
not container.mayBeMultiReturned(_)
)
nodeFrom.asExpr() = nodeTo.asExpr().(CfgNodes::ExprNodes::ArrayExprCfgNode)
or
nodeFrom.(AstNode).getCfgNode() = nodeTo.(PreReturNodeImpl).getReturnedNode()
exists(CfgNodes::ExprCfgNode e |
e = nodeFrom.(AstNode).getCfgNode() and
isReturned(e) and
e.getScope() = nodeTo.(PreReturNodeImpl).getCfgScope()
)
or
exists(CfgNode cfgNode |
nodeFrom = TPreReturnNodeImpl(cfgNode, true) and
@@ -118,10 +128,12 @@ module LocalFlow {
nodeTo = TReturnNodeImpl(cfgNode.getScope())
)
or
exists(CfgNode cfgNode |
cfgNode = nodeFrom.(AstNode).getCfgNode() and
isUniqueReturned(cfgNode) and
nodeTo.(ReturnNodeImpl).getCfgScope() = cfgNode.getScope()
exists(CfgNodes::ExprCfgNode e, CfgNodes::ScriptBlockCfgNode scriptBlock |
e = nodeFrom.(AstNode).getCfgNode() and
isReturned(e) and
e.getScope() = scriptBlock.getAstNode() and
not blockMayReturnMultipleValues(scriptBlock) and
nodeTo.(ReturnNodeImpl).getCfgScope() = scriptBlock.getAstNode()
)
}
@@ -164,7 +176,6 @@ private module Cached {
cached
newtype TNode =
TExprNode(CfgNodes::ExprCfgNode n) or
TStmtNode(CfgNodes::StmtCfgNode n) or
TSsaNode(SsaImpl::DataFlowIntegration::SsaNode node) or
TNormalParameterNode(SsaImpl::NormalParameter p) or
TThisParameterNode(Method m) or
@@ -183,8 +194,12 @@ private module Cached {
n = any(CfgNodes::ExprNodes::IndexExprCfgNode index).getBase()
} or
TFlowSummaryNode(FlowSummaryImpl::Private::SummaryNode sn) or
TPreReturnNodeImpl(CfgNodes::AstCfgNode n, Boolean isArray) { isMultiReturned(n) } or
TImplicitWrapNode(CfgNodes::AstCfgNode n, Boolean shouldWrap) { isMultiReturned(n) } or
TPreReturnNodeImpl(CfgNodes::ScriptBlockCfgNode scriptBlock, Boolean isArray) {
blockMayReturnMultipleValues(scriptBlock)
} or
TImplicitWrapNode(CfgNodes::ScriptBlockCfgNode scriptBlock, Boolean shouldWrap) {
blockMayReturnMultipleValues(scriptBlock)
} or
TReturnNodeImpl(CfgScope scope) or
TProcessNode(ProcessBlock process) or
TProcessPropertyByNameNode(PipelineByPropertyNameIteratorVariable iter) {
@@ -549,7 +564,7 @@ private module ParameterNodes {
ThisParameterNode() { this = TThisParameterNode(m) }
override Parameter getParameter() { none() }
override Parameter getParameter() { result = m.getThisParameter() }
override predicate isParameterOf(DataFlowCallable c, ParameterPosition pos) {
m.getBody() = c.asCfgScope() and
@@ -751,64 +766,41 @@ abstract class ReturnNode extends Node {
abstract ReturnKind getKind();
}
private module EscapeContainer {
private import semmle.code.powershell.internal.AstEscape::Private
private class SummaryReturnNode extends FlowSummaryNode, ReturnNode {
private ReturnKind rk;
private module ReturnContainerInterpreter implements InterpretAstInputSig {
class T = CfgNodes::AstCfgNode;
SummaryReturnNode() { FlowSummaryImpl::Private::summaryReturnNode(this.getSummaryNode(), rk) }
T interpret(Ast a) { result.(CfgNodes::ExprCfgNode).getExpr() = a } // TODO: Recutse into expr-to-stmt conversions
}
class EscapeContainer extends AstEscape<ReturnContainerInterpreter>::Element {
/** Holds if `n` may be returned multiples times. */
predicate mayBeMultiReturned(CfgNode n) {
n = this.getANode() and
n.getASuccessor+() = n
or
this.getAChild().(EscapeContainer).mayBeMultiReturned(n)
}
}
private class SummaryReturnNode extends FlowSummaryNode, ReturnNode {
private ReturnKind rk;
SummaryReturnNode() { FlowSummaryImpl::Private::summaryReturnNode(this.getSummaryNode(), rk) }
override ReturnKind getKind() { result = rk }
}
override ReturnKind getKind() { result = rk }
}
private module ReturnNodes {
private import EscapeContainer
private predicate isReturnedImpl(CfgNodes::AstCfgNode n, EscapeContainer container) {
container = n.getScope() and
n = container.getAnEscapingElement()
private CfgNodes::NamedBlockCfgNode getAReturnBlock(CfgNodes::ScriptBlockCfgNode sb) {
result = sb.getBeginBlock()
or
result = sb.getEndBlock()
or
result = sb.getProcessBlock()
}
private module CfgScopeReturn implements PipelineReturns::InputSig {
predicate isSource(CfgNodes::AstCfgNode source) { source = getAReturnBlock(_) }
}
private module P = PipelineReturns::Make<CfgScopeReturn>;
/**
* Holds if `n` may be returned, and there are possibly
* more than one return value from the function.
*/
predicate isMultiReturned(CfgNodes::AstCfgNode n) {
exists(EscapeContainer container | isReturnedImpl(n, container) |
strictcount(container.getAnEscapingElement()) > 1
or
container.mayBeMultiReturned(n)
)
predicate blockMayReturnMultipleValues(CfgNodes::ScriptBlockCfgNode scriptBlock) {
P::mayReturnMultipleValues(getAReturnBlock(scriptBlock))
}
/**
* Holds if `n` may be returned.
*/
predicate isReturned(CfgNodes::AstCfgNode n) { isReturnedImpl(n, _) }
/**
* Holds if `n` may be returned, and this is the only value that may be
* returned from the function.
*/
predicate isUniqueReturned(CfgNodes::AstCfgNode n) { isReturned(n) and not isMultiReturned(n) }
predicate isReturned(CfgNodes::AstCfgNode n) { n = P::getAReturn(_) }
class NormalReturnNode extends ReturnNode instanceof ReturnNodeImpl {
final override NormalReturnKind getKind() { any() }
@@ -851,6 +843,24 @@ predicate jumpStep(Node pred, Node succ) {
succ.(FlowSummaryNode).getSummaryNode())
}
private predicate arrayExprStore(Node node1, ContentSet cs, Node node2, CfgNodes::ExprCfgNode e) {
exists(CfgNodes::ExprNodes::ArrayExprCfgNode ae, CfgNodes::StmtNodes::StmtBlockCfgNode block |
e = node1.(AstNode).getCfgNode() and
ae = node2.asExpr() and
block = ae.getStmtBlock()
|
exists(Content::KnownElementContent ec, int index |
e = ArrayExprFlow::getReturn(block, index) and
cs.isKnownOrUnknownElement(ec) and
index = ec.getIndex().asInt()
)
or
not ArrayExprFlow::eachValueIsReturnedOnce(block) and
e = ArrayExprFlow::getAReturn(block) and
cs.isAnyElement()
)
}
/**
* Holds if data can flow from `node1` to `node2` via an assignment to
* content `c`.
@@ -877,8 +887,10 @@ predicate storeStep(Node node1, ContentSet c, Node node2) {
c.isAnyElement()
)
or
exists(Content::KnownElementContent ec, int index |
node2.asExpr().(CfgNodes::ExprNodes::ArrayLiteralCfgNode).getExpr(index) = node1.asExpr() and
exists(Content::KnownElementContent ec, int index, CfgNodes::ExprCfgNode e |
e = node1.asExpr() and
not arrayExprStore(node1, _, _, e) and
node2.asExpr().(CfgNodes::ExprNodes::ArrayLiteralCfgNode).getExpr(index) = e and
c.isKnownOrUnknownElement(ec) and
index = ec.getIndex().asInt()
)
@@ -895,15 +907,7 @@ predicate storeStep(Node node1, ContentSet c, Node node2) {
c.isAnyElement()
)
or
c.isAnyElement() and
exists(
CfgNodes::ExprNodes::ArrayExprCfgNode arrayExpr, EscapeContainer::EscapeContainer container
|
node2.asExpr() = arrayExpr and
container = arrayExpr.getStmtBlock().getAstNode() and
node1.(AstNode).getCfgNode() = container.getAnEscapingElement() and
container.mayBeMultiReturned(_)
)
arrayExprStore(node1, c, node2, _)
or
c.isAnyElement() and
exists(CfgNode cfgNode |
@@ -1089,12 +1093,12 @@ private import PostUpdateNodes
* (or statement) is being returned from a function.
*/
private class ImplicitWrapNode extends TImplicitWrapNode, NodeImpl {
private CfgNodes::AstCfgNode n;
private CfgNodes::ScriptBlockCfgNode n;
private boolean shouldWrap;
ImplicitWrapNode() { this = TImplicitWrapNode(n, shouldWrap) }
CfgNodes::AstCfgNode getReturnedNode() { result = n }
CfgNodes::ScriptBlockCfgNode getScriptBlock() { result = n }
predicate shouldWrap() { shouldWrap = true }
@@ -1112,12 +1116,12 @@ private class ImplicitWrapNode extends TImplicitWrapNode, NodeImpl {
* has been performed.
*/
private class PreReturNodeImpl extends TPreReturnNodeImpl, NodeImpl {
private CfgNodes::AstCfgNode n;
private CfgNodes::ScriptBlockCfgNode n;
private boolean isArray;
PreReturNodeImpl() { this = TPreReturnNodeImpl(n, isArray) }
CfgNodes::AstCfgNode getReturnedNode() { result = n }
CfgNodes::AstCfgNode getScriptBlock() { result = n }
override CfgScope getCfgScope() { result = n.getScope() }

View File

@@ -0,0 +1,199 @@
private import semmle.code.powershell.controlflow.CfgNodes
/**
* The input module which defines the set of sources for which to calculate
* "escaping expressions".
*/
signature module InputSig {
/**
* Holds if `source` is a relevant AST element that we want to compute
* which expressions are returned from.
*/
predicate isSource(AstCfgNode source);
}
/** The output signature from the "escape analysis". */
signature module OutputSig<InputSig Input> {
/** Gets an expression that escapes from `source` */
ExprCfgNode getAReturn(AstCfgNode source);
/**
* Gets the `i`'th expression that escapes from `source`, if an ordering can
* be determined statically.
*/
ExprCfgNode getReturn(AstCfgNode source, int i);
/** Holds multiple value may escape from `source`. */
predicate mayReturnMultipleValues(AstCfgNode source);
/**
* Holds if each value escaping from `source` is guarenteed to only escape
* once. In particular, if `count(getAReturn(source)) = 1` and this predicate
* holds, then only one value can escape from `source`.
*
* If `count(getAReturn(source)) > 1` and this predicate holds,
* it means that a sequence of values may escape from `source`.
*/
predicate eachValueIsReturnedOnce(AstCfgNode source);
}
module Make<InputSig Input> implements OutputSig<Input> {
private import Input
private predicate step0(AstCfgNode pred, AstCfgNode succ) {
exists(NamedBlockCfgNode nb |
pred = nb and
succ = nb.getAStmt()
)
or
exists(StmtNodes::StmtBlockCfgNode sb |
pred = sb and
succ = sb.getAStmt()
)
or
exists(StmtNodes::ExprStmtCfgNode es |
pred = es and
succ = es.getExpr()
)
or
exists(StmtNodes::ReturnStmtCfgNode es |
pred = es and
succ = es.getPipeline()
)
or
exists(ExprNodes::ArrayLiteralCfgNode al |
pred = al and
succ = al.getAnExpr()
)
or
exists(StmtNodes::LoopStmtCfgNode loop |
pred = loop and
succ = loop.getBody()
)
or
exists(ExprNodes::IfCfgNode if_ |
pred = if_ and
succ = if_.getABranch()
)
or
exists(StmtNodes::SwitchStmtCfgNode switch |
pred = switch and
succ = switch.getACase()
)
or
exists(CatchClauseCfgNode catch |
pred = catch and
succ = catch.getBody()
)
or
exists(StmtNodes::TryStmtCfgNode try |
pred = try and
succ = [try.getBody(), try.getFinally()]
)
}
private predicate fwd(AstCfgNode n) {
isSource(n)
or
exists(AstCfgNode pred |
fwd(pred) and
step0(pred, n)
)
}
private predicate isSink(AstCfgNode sink) {
fwd(sink) and
(
sink instanceof ExprCfgNode and
// If is not really an expression
not sink instanceof ExprNodes::IfCfgNode and
// When `a, b, c` is returned it is flattened to returning a, and b, and c.
not sink instanceof ExprNodes::ArrayLiteralCfgNode
)
}
private predicate rev(AstCfgNode n) {
fwd(n) and
(
isSink(n)
or
exists(AstCfgNode succ |
rev(succ) and
step0(n, succ)
)
)
}
private predicate step(AstCfgNode n1, AstCfgNode n2) {
rev(n1) and
rev(n2) and
step0(n1, n2)
}
private predicate stepPlus(AstCfgNode n1, AstCfgNode n2) =
doublyBoundedFastTC(step/2, isSource/1, isSink/1)(n1, n2)
/** Gets a value that may be returned from `source`. */
private ExprCfgNode getAReturn0(AstCfgNode source) {
isSource(source) and
isSink(result) and
stepPlus(source, result)
}
private predicate inScopeOfSource(AstCfgNode n, AstCfgNode source) {
isSource(source) and
n.getAstNode().getParent*() = source.getAstNode()
}
private predicate getASuccessor(AstCfgNode pred, AstCfgNode succ) {
exists(AstCfgNode source |
inScopeOfSource(pred, source) and
pred.getASuccessor() = succ and
inScopeOfSource(succ, source)
)
}
/** Holds if `e` may be returned multiple times from `source`. */
private predicate mayBeReturnedMoreThanOnce(ExprCfgNode e, AstCfgNode source) {
e = getAReturn0(source) and getASuccessor+(e, e)
}
predicate eachValueIsReturnedOnce(AstCfgNode source) {
isSource(source) and
not mayBeReturnedMoreThanOnce(_, source)
}
private predicate isSourceForSingularReturn(AstCfgNode source) {
isSource(source) and
eachValueIsReturnedOnce(source)
}
private predicate hasReturnOrderImpl0(int dist, ExprCfgNode e, AstCfgNode source) =
shortestDistances(isSourceForSingularReturn/1, getASuccessor/2)(source, e, dist)
private predicate hasReturnOrderImpl(int dist, ExprCfgNode e) {
hasReturnOrderImpl0(dist, e, _) and
e = getAReturn0(_)
}
private predicate hasReturnOrder(int i, ExprCfgNode e) {
e = rank[i + 1](ExprCfgNode e0, int i0 | hasReturnOrderImpl(i0, e0) | e0 order by i0)
}
ExprCfgNode getReturn(AstCfgNode source, int i) {
result = getAReturn0(source) and
eachValueIsReturnedOnce(source) and
hasReturnOrder(i, result)
}
ExprCfgNode getAReturn(AstCfgNode source) { result = getAReturn0(source) }
/**
* Holds if `source` may return multiple values, and `n` is one of the values.
*/
predicate mayReturnMultipleValues(AstCfgNode source) {
strictcount(getAReturn0(source)) > 1
or
mayBeReturnedMoreThanOnce(_, source)
}
}

View File

@@ -27,12 +27,6 @@ module SsaInput implements SsaImplCommon::InputSig<Location> {
*/
predicate variableWrite(BasicBlock bb, int i, SourceVariable v, boolean certain) {
(
exists(Scope scope | scope = v.(ThisParameter).getDeclaringScope() |
// We consider the `this` variable to have a single write at the entry to a method block
scope = bb.(BasicBlocks::EntryBasicBlock).getScope() and
i = 0
)
or
uninitializedWrite(bb, i, v)
or
variableWriteActual(bb, i, v, _)
@@ -138,9 +132,7 @@ private module Cached {
* AST write access is `write`.
*/
cached
predicate variableWriteActual(
Cfg::BasicBlock bb, int i, Variable v, VarWriteAccessCfgNode write
) {
predicate variableWriteActual(Cfg::BasicBlock bb, int i, Variable v, VarWriteAccessCfgNode write) {
exists(Cfg::CfgNode n |
write.getVariable() = v and
n = bb.getNode(i)
@@ -277,7 +269,8 @@ private Parameter getANonPipelineParameter(FunctionBase f) {
class NormalParameter extends Parameter {
NormalParameter() {
not this instanceof PipelineParameter and
not this instanceof PipelineByPropertyNameParameter
not this instanceof PipelineByPropertyNameParameter and
not this instanceof ThisParameter
}
int getIndexExcludingPipelines() {
@@ -295,18 +288,18 @@ class NormalParameter extends Parameter {
private newtype TParameterExt =
TNormalParameter(NormalParameter p) or
TSelfMethodParameter(Method m)
TThisMethodParameter(Method m)
/** A normal parameter or an implicit `self` parameter. */
/** A normal parameter or an implicit `this` parameter. */
class ParameterExt extends TParameterExt {
NormalParameter asParameter() { this = TNormalParameter(result) }
Method asThis() { this = TSelfMethodParameter(result) }
Method asThis() { this = TThisMethodParameter(result) }
predicate isInitializedBy(WriteDefinition def) {
def = getParameterDef(this.asParameter())
or
def.(Ssa::ThisDefinition).getSourceVariable().getDeclaringScope() = this.asThis().(Scope)
def.(Ssa::ThisDefinition).getSourceVariable().getDeclaringScope() = this.asThis().getBody()
}
string toString() { result = [this.asParameter().toString(), this.asThis().toString()] }

View File

@@ -1,84 +0,0 @@
private import powershell as PS
/**
* TODO: This whole computation cab be sped up by providing a set of "root"s and doing
* a forward/backwards traversal first.
*/
module Private {
signature module InterpretAstInputSig {
/** The type on which to translate `Ast` elements during escape calculations */
class T;
/** Interpret `a` into a `T` */
T interpret(PS::Ast a);
}
module AstEscape<InterpretAstInputSig Interpret> {
private import Interpret
/** An AST element that may produce a value which can escape from this `Ast` when evaluated. */
abstract private class ElementImpl instanceof PS::Ast {
string toString() { result = super.toString() }
/** Gets a direct node that will may escape when evaluating this element. */
T getANode() { none() }
/** Gets a child that may produce more elements that may escape. */
abstract Element getAChild();
/**
* Gets a (possibly transitive) element that may escape when evaluating
* this element.
*/
final T getAnEscapingElement() {
result = this.getANode()
or
result = this.getAChild().getAnEscapingElement()
}
}
final class Element = ElementImpl;
private class ScriptBlockElement extends ElementImpl instanceof PS::ScriptBlock {
final override Element getAChild() { result = super.getEndBlock() }
}
private class NamedBlockElement extends ElementImpl instanceof PS::NamedBlock {
final override Element getAChild() { result = super.getAStmt() }
}
private class ExprStmtElement extends ElementImpl instanceof PS::ExprStmt {
final override T getANode() { result = interpret(super.getExpr()) }
final override Element getAChild() { none() }
}
private class LoopStmtElement extends ElementImpl instanceof PS::LoopStmt {
final override Element getAChild() { result = super.getBody() }
}
private class StmtBlockElement extends ElementImpl instanceof PS::StmtBlock {
final override Element getAChild() { result = super.getAStmt() }
}
private class TryStmtElement extends ElementImpl instanceof PS::TryStmt {
final override Element getAChild() {
result = super.getBody() or result = super.getACatchClause() or result = super.getFinally()
}
}
private class ReturnStmtElement extends ElementImpl instanceof PS::ReturnStmt {
final override Element getAChild() { result = super.getPipeline() }
}
private class CatchClausElement extends ElementImpl instanceof PS::CatchClause {
final override Element getAChild() { result = super.getBody() }
}
private class SwitchStmtElement extends ElementImpl instanceof PS::SwitchStmt {
final override Element getAChild() { result = super.getACase() }
}
}
}
module Public { }

View File

@@ -247,7 +247,9 @@
| functions.ps1:13:28:20:1 | enter {...} | functions.ps1:13:28:20:1 | {...} | |
| functions.ps1:13:28:20:1 | exit {...} (normal) | functions.ps1:13:28:20:1 | exit {...} | |
| functions.ps1:13:28:20:1 | name0 | functions.ps1:13:28:20:1 | name1 | |
| functions.ps1:13:28:20:1 | name1 | functions.ps1:13:28:20:1 | name2 | |
| functions.ps1:13:28:20:1 | name1 | functions.ps1:16:24:16:24 | 0 | |
| functions.ps1:13:28:20:1 | name2 | functions.ps1:13:28:20:1 | [synth] pipeline | |
| functions.ps1:13:28:20:1 | name2 | functions.ps1:17:24:17:29 | name1 | |
| functions.ps1:13:28:20:1 | {...} | functions.ps1:16:24:16:24 | 0 | |
| functions.ps1:14:5:19:18 | {...} | functions.ps1:19:5:19:18 | [Stmt] ...+... | |

View File

@@ -8,6 +8,10 @@ multipleSuccessors
| functions.ps1:8:5:8:23 | [Stmt] ...+... | successor | functions.ps1:46:17:46:18 | __pipeline_iterator |
| functions.ps1:8:5:8:23 | [Stmt] __pipeline_iterator | successor | functions.ps1:8:5:8:12 | number1 |
| functions.ps1:8:5:8:23 | [Stmt] __pipeline_iterator | successor | functions.ps1:46:17:46:18 | __pipeline_iterator |
| functions.ps1:13:28:20:1 | name1 | successor | functions.ps1:13:28:20:1 | name2 |
| functions.ps1:13:28:20:1 | name1 | successor | functions.ps1:16:24:16:24 | 0 |
| functions.ps1:13:28:20:1 | name2 | successor | functions.ps1:13:28:20:1 | [synth] pipeline |
| functions.ps1:13:28:20:1 | name2 | successor | functions.ps1:17:24:17:29 | name1 |
| functions.ps1:16:24:16:24 | 0 | successor | functions.ps1:13:28:20:1 | name2 |
| functions.ps1:16:24:16:24 | 0 | successor | functions.ps1:17:24:17:29 | name1 |
| functions.ps1:17:24:17:33 | ...+... | successor | functions.ps1:13:28:20:1 | [synth] pipeline |

View File

@@ -40,11 +40,33 @@ edges
| test.ps1:40:6:40:10 | arr8 [element 2] | test.ps1:40:6:40:13 | ...[...] | provenance | |
| test.ps1:41:6:41:10 | arr8 [element 2] | test.ps1:41:6:41:20 | ...[...] | provenance | |
| test.ps1:43:6:43:16 | Call to Source | test.ps1:45:17:45:18 | y | provenance | |
| test.ps1:45:11:45:18 | ...,... [element 2] | test.ps1:48:6:48:10 | arr9 [element 2] | provenance | |
| test.ps1:45:11:45:18 | ...,... [element 2] | test.ps1:49:6:49:10 | arr9 [element 2] | provenance | |
| test.ps1:45:17:45:18 | y | test.ps1:45:11:45:18 | ...,... [element 2] | provenance | |
| test.ps1:45:9:45:19 | @(...) [element 2] | test.ps1:48:6:48:10 | arr9 [element 2] | provenance | |
| test.ps1:45:9:45:19 | @(...) [element 2] | test.ps1:49:6:49:10 | arr9 [element 2] | provenance | |
| test.ps1:45:17:45:18 | y | test.ps1:45:9:45:19 | @(...) [element 2] | provenance | |
| test.ps1:48:6:48:10 | arr9 [element 2] | test.ps1:48:6:48:13 | ...[...] | provenance | |
| test.ps1:49:6:49:10 | arr9 [element 2] | test.ps1:49:6:49:20 | ...[...] | provenance | |
| test.ps1:54:5:56:5 | this [field] | test.ps1:55:14:55:24 | this [field] | provenance | |
| test.ps1:55:14:55:24 | this [field] | test.ps1:55:14:55:24 | field | provenance | |
| test.ps1:61:1:61:8 | [post] myClass [field] | test.ps1:63:1:63:8 | myClass [field] | provenance | |
| test.ps1:61:18:61:28 | Call to Source | test.ps1:61:1:61:8 | [post] myClass [field] | provenance | |
| test.ps1:63:1:63:8 | myClass [field] | test.ps1:54:5:56:5 | this [field] | provenance | |
| test.ps1:66:10:66:20 | Call to Source | test.ps1:69:5:69:6 | x | provenance | |
| test.ps1:67:10:67:20 | Call to Source | test.ps1:70:5:70:6 | y | provenance | |
| test.ps1:68:10:68:20 | Call to Source | test.ps1:70:9:70:10 | z | provenance | |
| test.ps1:69:5:69:6 | x | test.ps1:73:6:73:12 | Call to produce [element] | provenance | |
| test.ps1:70:5:70:6 | y | test.ps1:73:6:73:12 | Call to produce [element] | provenance | |
| test.ps1:70:9:70:10 | z | test.ps1:73:6:73:12 | Call to produce [element] | provenance | |
| test.ps1:73:6:73:12 | Call to produce [element] | test.ps1:74:6:74:7 | x [element] | provenance | |
| test.ps1:73:6:73:12 | Call to produce [element] | test.ps1:75:6:75:7 | x [element] | provenance | |
| test.ps1:73:6:73:12 | Call to produce [element] | test.ps1:76:6:76:7 | x [element] | provenance | |
| test.ps1:74:6:74:7 | x [element] | test.ps1:74:6:74:10 | ...[...] | provenance | |
| test.ps1:75:6:75:7 | x [element] | test.ps1:75:6:75:10 | ...[...] | provenance | |
| test.ps1:76:6:76:7 | x [element] | test.ps1:76:6:76:10 | ...[...] | provenance | |
| test.ps1:78:9:81:1 | ${...} [element a] | test.ps1:83:6:83:10 | hash [element a] | provenance | |
| test.ps1:78:9:81:1 | ${...} [element a] | test.ps1:87:6:87:10 | hash [element a] | provenance | |
| test.ps1:79:7:79:17 | Call to Source | test.ps1:78:9:81:1 | ${...} [element a] | provenance | |
| test.ps1:83:6:83:10 | hash [element a] | test.ps1:83:6:83:15 | ...[...] | provenance | |
| test.ps1:87:6:87:10 | hash [element a] | test.ps1:87:6:87:15 | ...[...] | provenance | |
| test.ps1:88:1:88:5 | [post] hash [b] | test.ps1:89:6:89:10 | hash [b] | provenance | |
| test.ps1:88:11:88:21 | Call to Source | test.ps1:88:1:88:5 | [post] hash [b] | provenance | |
| test.ps1:89:6:89:10 | hash [b] | test.ps1:89:6:89:12 | b | provenance | |
@@ -98,30 +120,43 @@ nodes
| test.ps1:41:6:41:10 | arr8 [element 2] | semmle.label | arr8 [element 2] |
| test.ps1:41:6:41:20 | ...[...] | semmle.label | ...[...] |
| test.ps1:43:6:43:16 | Call to Source | semmle.label | Call to Source |
| test.ps1:45:11:45:18 | ...,... [element 2] | semmle.label | ...,... [element 2] |
| test.ps1:45:9:45:19 | @(...) [element 2] | semmle.label | @(...) [element 2] |
| test.ps1:45:17:45:18 | y | semmle.label | y |
| test.ps1:48:6:48:10 | arr9 [element 2] | semmle.label | arr9 [element 2] |
| test.ps1:48:6:48:13 | ...[...] | semmle.label | ...[...] |
| test.ps1:49:6:49:10 | arr9 [element 2] | semmle.label | arr9 [element 2] |
| test.ps1:49:6:49:20 | ...[...] | semmle.label | ...[...] |
| test.ps1:54:5:56:5 | this [field] | semmle.label | this [field] |
| test.ps1:55:14:55:24 | field | semmle.label | field |
| test.ps1:55:14:55:24 | this [field] | semmle.label | this [field] |
| test.ps1:61:1:61:8 | [post] myClass [field] | semmle.label | [post] myClass [field] |
| test.ps1:61:18:61:28 | Call to Source | semmle.label | Call to Source |
| test.ps1:63:1:63:8 | myClass [field] | semmle.label | myClass [field] |
| test.ps1:66:10:66:20 | Call to Source | semmle.label | Call to Source |
| test.ps1:67:10:67:20 | Call to Source | semmle.label | Call to Source |
| test.ps1:68:10:68:20 | Call to Source | semmle.label | Call to Source |
| test.ps1:69:5:69:6 | x | semmle.label | x |
| test.ps1:70:5:70:6 | y | semmle.label | y |
| test.ps1:70:9:70:10 | z | semmle.label | z |
| test.ps1:73:6:73:12 | Call to produce [element] | semmle.label | Call to produce [element] |
| test.ps1:74:6:74:7 | x [element] | semmle.label | x [element] |
| test.ps1:74:6:74:10 | ...[...] | semmle.label | ...[...] |
| test.ps1:75:6:75:7 | x [element] | semmle.label | x [element] |
| test.ps1:75:6:75:10 | ...[...] | semmle.label | ...[...] |
| test.ps1:76:6:76:7 | x [element] | semmle.label | x [element] |
| test.ps1:76:6:76:10 | ...[...] | semmle.label | ...[...] |
| test.ps1:78:9:81:1 | ${...} [element a] | semmle.label | ${...} [element a] |
| test.ps1:79:7:79:17 | Call to Source | semmle.label | Call to Source |
| test.ps1:83:6:83:10 | hash [element a] | semmle.label | hash [element a] |
| test.ps1:83:6:83:15 | ...[...] | semmle.label | ...[...] |
| test.ps1:87:6:87:10 | hash [element a] | semmle.label | hash [element a] |
| test.ps1:87:6:87:15 | ...[...] | semmle.label | ...[...] |
| test.ps1:88:1:88:5 | [post] hash [b] | semmle.label | [post] hash [b] |
| test.ps1:88:11:88:21 | Call to Source | semmle.label | Call to Source |
| test.ps1:89:6:89:10 | hash [b] | semmle.label | hash [b] |
| test.ps1:89:6:89:12 | b | semmle.label | b |
subpaths
testFailures
| test.ps1:55:26:55:44 | # $ hasValueFlow=12 | Missing result: hasValueFlow=12 |
| test.ps1:74:12:74:62 | # $ hasValueFlow=13 hasValueFlow=14 hasValueFlow=15 | Missing result: hasValueFlow=13 |
| test.ps1:74:12:74:62 | # $ hasValueFlow=13 hasValueFlow=14 hasValueFlow=15 | Missing result: hasValueFlow=14 |
| test.ps1:74:12:74:62 | # $ hasValueFlow=13 hasValueFlow=14 hasValueFlow=15 | Missing result: hasValueFlow=15 |
| test.ps1:75:12:75:62 | # $ hasValueFlow=13 hasValueFlow=14 hasValueFlow=15 | Missing result: hasValueFlow=13 |
| test.ps1:75:12:75:62 | # $ hasValueFlow=13 hasValueFlow=14 hasValueFlow=15 | Missing result: hasValueFlow=14 |
| test.ps1:75:12:75:62 | # $ hasValueFlow=13 hasValueFlow=14 hasValueFlow=15 | Missing result: hasValueFlow=15 |
| test.ps1:76:12:76:62 | # $ hasValueFlow=13 hasValueFlow=14 hasValueFlow=15 | Missing result: hasValueFlow=13 |
| test.ps1:76:12:76:62 | # $ hasValueFlow=13 hasValueFlow=14 hasValueFlow=15 | Missing result: hasValueFlow=14 |
| test.ps1:76:12:76:62 | # $ hasValueFlow=13 hasValueFlow=14 hasValueFlow=15 | Missing result: hasValueFlow=15 |
| test.ps1:83:17:83:35 | # $ hasValueFlow=16 | Missing result: hasValueFlow=16 |
| test.ps1:87:17:87:45 | # $ SPURIOUS: hasValueFlow=16 | Fixed spurious result: hasValueFlow=16 |
#select
| test.ps1:4:6:4:9 | f | test.ps1:3:8:3:17 | Call to Source | test.ps1:4:6:4:9 | f | $@ | test.ps1:3:8:3:17 | Call to Source | Call to Source |
| test.ps1:11:6:11:13 | ...[...] | test.ps1:10:12:10:21 | Call to Source | test.ps1:11:6:11:13 | ...[...] | $@ | test.ps1:10:12:10:21 | Call to Source | Call to Source |
@@ -136,4 +171,16 @@ testFailures
| test.ps1:41:6:41:20 | ...[...] | test.ps1:35:6:35:16 | Call to Source | test.ps1:41:6:41:20 | ...[...] | $@ | test.ps1:35:6:35:16 | Call to Source | Call to Source |
| test.ps1:48:6:48:13 | ...[...] | test.ps1:43:6:43:16 | Call to Source | test.ps1:48:6:48:13 | ...[...] | $@ | test.ps1:43:6:43:16 | Call to Source | Call to Source |
| test.ps1:49:6:49:20 | ...[...] | test.ps1:43:6:43:16 | Call to Source | test.ps1:49:6:49:20 | ...[...] | $@ | test.ps1:43:6:43:16 | Call to Source | Call to Source |
| test.ps1:55:14:55:24 | field | test.ps1:61:18:61:28 | Call to Source | test.ps1:55:14:55:24 | field | $@ | test.ps1:61:18:61:28 | Call to Source | Call to Source |
| test.ps1:74:6:74:10 | ...[...] | test.ps1:66:10:66:20 | Call to Source | test.ps1:74:6:74:10 | ...[...] | $@ | test.ps1:66:10:66:20 | Call to Source | Call to Source |
| test.ps1:74:6:74:10 | ...[...] | test.ps1:67:10:67:20 | Call to Source | test.ps1:74:6:74:10 | ...[...] | $@ | test.ps1:67:10:67:20 | Call to Source | Call to Source |
| test.ps1:74:6:74:10 | ...[...] | test.ps1:68:10:68:20 | Call to Source | test.ps1:74:6:74:10 | ...[...] | $@ | test.ps1:68:10:68:20 | Call to Source | Call to Source |
| test.ps1:75:6:75:10 | ...[...] | test.ps1:66:10:66:20 | Call to Source | test.ps1:75:6:75:10 | ...[...] | $@ | test.ps1:66:10:66:20 | Call to Source | Call to Source |
| test.ps1:75:6:75:10 | ...[...] | test.ps1:67:10:67:20 | Call to Source | test.ps1:75:6:75:10 | ...[...] | $@ | test.ps1:67:10:67:20 | Call to Source | Call to Source |
| test.ps1:75:6:75:10 | ...[...] | test.ps1:68:10:68:20 | Call to Source | test.ps1:75:6:75:10 | ...[...] | $@ | test.ps1:68:10:68:20 | Call to Source | Call to Source |
| test.ps1:76:6:76:10 | ...[...] | test.ps1:66:10:66:20 | Call to Source | test.ps1:76:6:76:10 | ...[...] | $@ | test.ps1:66:10:66:20 | Call to Source | Call to Source |
| test.ps1:76:6:76:10 | ...[...] | test.ps1:67:10:67:20 | Call to Source | test.ps1:76:6:76:10 | ...[...] | $@ | test.ps1:67:10:67:20 | Call to Source | Call to Source |
| test.ps1:76:6:76:10 | ...[...] | test.ps1:68:10:68:20 | Call to Source | test.ps1:76:6:76:10 | ...[...] | $@ | test.ps1:68:10:68:20 | Call to Source | Call to Source |
| test.ps1:83:6:83:15 | ...[...] | test.ps1:79:7:79:17 | Call to Source | test.ps1:83:6:83:15 | ...[...] | $@ | test.ps1:79:7:79:17 | Call to Source | Call to Source |
| test.ps1:87:6:87:15 | ...[...] | test.ps1:79:7:79:17 | Call to Source | test.ps1:87:6:87:15 | ...[...] | $@ | test.ps1:79:7:79:17 | Call to Source | Call to Source |
| test.ps1:89:6:89:12 | b | test.ps1:88:11:88:21 | Call to Source | test.ps1:89:6:89:12 | b | $@ | test.ps1:88:11:88:21 | Call to Source | Call to Source |

View File

@@ -1,51 +1,37 @@
| test.ps1:1:1:1:3 | a1 | test.ps1:2:6:2:8 | a1 |
| test.ps1:1:1:21:27 | implicit unwrapping of {...} | test.ps1:1:1:21:27 | return value for {...} |
| test.ps1:1:1:21:27 | pre-return value for {...} | test.ps1:1:1:21:27 | implicit unwrapping of {...} |
| test.ps1:1:7:1:12 | Call to Source | test.ps1:1:1:1:3 | a1 |
| test.ps1:2:1:2:8 | Call to Sink | test.ps1:2:1:2:8 | pre-return value for Call to Sink |
| test.ps1:2:1:2:8 | Call to Sink | test.ps1:2:1:2:8 | pre-return value for Call to Sink |
| test.ps1:2:1:2:8 | implicit unwrapping of Call to Sink | test.ps1:1:1:21:27 | return value for {...} |
| test.ps1:2:1:2:8 | pre-return value for Call to Sink | test.ps1:2:1:2:8 | implicit unwrapping of Call to Sink |
| test.ps1:2:1:2:8 | Call to Sink | test.ps1:1:1:21:27 | pre-return value for {...} |
| test.ps1:2:1:2:8 | Call to Sink | test.ps1:1:1:21:27 | pre-return value for {...} |
| test.ps1:4:1:4:2 | b | test.ps1:5:4:5:5 | b |
| test.ps1:4:6:4:12 | Call to GetBool | test.ps1:4:1:4:2 | b |
| test.ps1:5:1:7:1 | if (...) {...} | test.ps1:5:1:7:1 | pre-return value for if (...) {...} |
| test.ps1:5:1:7:1 | if (...) {...} | test.ps1:5:1:7:1 | pre-return value for if (...) {...} |
| test.ps1:5:1:7:1 | implicit unwrapping of if (...) {...} | test.ps1:1:1:21:27 | return value for {...} |
| test.ps1:5:1:7:1 | phi | test.ps1:8:6:8:8 | a2 |
| test.ps1:5:1:7:1 | pre-return value for if (...) {...} | test.ps1:5:1:7:1 | implicit unwrapping of if (...) {...} |
| test.ps1:5:4:5:5 | b | test.ps1:10:14:10:15 | b |
| test.ps1:6:5:6:7 | a2 | test.ps1:6:11:6:16 | [input] phi |
| test.ps1:6:11:6:16 | Call to Source | test.ps1:6:5:6:7 | a2 |
| test.ps1:6:11:6:16 | [input] phi | test.ps1:5:1:7:1 | phi |
| test.ps1:8:1:8:8 | Call to Sink | test.ps1:8:1:8:8 | pre-return value for Call to Sink |
| test.ps1:8:1:8:8 | Call to Sink | test.ps1:8:1:8:8 | pre-return value for Call to Sink |
| test.ps1:8:1:8:8 | implicit unwrapping of Call to Sink | test.ps1:1:1:21:27 | return value for {...} |
| test.ps1:8:1:8:8 | pre-return value for Call to Sink | test.ps1:8:1:8:8 | implicit unwrapping of Call to Sink |
| test.ps1:8:1:8:8 | Call to Sink | test.ps1:1:1:21:27 | pre-return value for {...} |
| test.ps1:8:1:8:8 | Call to Sink | test.ps1:1:1:21:27 | pre-return value for {...} |
| test.ps1:10:1:10:2 | c | test.ps1:11:6:11:7 | c |
| test.ps1:10:6:10:15 | [...]... | test.ps1:10:1:10:2 | c |
| test.ps1:10:14:10:15 | b | test.ps1:10:6:10:15 | [...]... |
| test.ps1:11:1:11:7 | Call to Sink | test.ps1:11:1:11:7 | pre-return value for Call to Sink |
| test.ps1:11:1:11:7 | Call to Sink | test.ps1:11:1:11:7 | pre-return value for Call to Sink |
| test.ps1:11:1:11:7 | implicit unwrapping of Call to Sink | test.ps1:1:1:21:27 | return value for {...} |
| test.ps1:11:1:11:7 | pre-return value for Call to Sink | test.ps1:11:1:11:7 | implicit unwrapping of Call to Sink |
| test.ps1:11:1:11:7 | Call to Sink | test.ps1:1:1:21:27 | pre-return value for {...} |
| test.ps1:11:1:11:7 | Call to Sink | test.ps1:1:1:21:27 | pre-return value for {...} |
| test.ps1:11:6:11:7 | [post] c | test.ps1:13:7:13:8 | c |
| test.ps1:11:6:11:7 | c | test.ps1:13:7:13:8 | c |
| test.ps1:13:1:13:2 | d | test.ps1:14:6:14:7 | d |
| test.ps1:13:6:13:9 | (...) | test.ps1:13:1:13:2 | d |
| test.ps1:13:7:13:8 | c | test.ps1:13:6:13:9 | (...) |
| test.ps1:14:1:14:7 | Call to Sink | test.ps1:14:1:14:7 | pre-return value for Call to Sink |
| test.ps1:14:1:14:7 | Call to Sink | test.ps1:14:1:14:7 | pre-return value for Call to Sink |
| test.ps1:14:1:14:7 | implicit unwrapping of Call to Sink | test.ps1:1:1:21:27 | return value for {...} |
| test.ps1:14:1:14:7 | pre-return value for Call to Sink | test.ps1:14:1:14:7 | implicit unwrapping of Call to Sink |
| test.ps1:14:1:14:7 | Call to Sink | test.ps1:1:1:21:27 | pre-return value for {...} |
| test.ps1:14:1:14:7 | Call to Sink | test.ps1:1:1:21:27 | pre-return value for {...} |
| test.ps1:14:6:14:7 | [post] d | test.ps1:16:6:16:7 | d |
| test.ps1:14:6:14:7 | d | test.ps1:16:6:16:7 | d |
| test.ps1:16:1:16:2 | e | test.ps1:17:6:17:7 | e |
| test.ps1:16:6:16:11 | ...+... | test.ps1:16:1:16:2 | e |
| test.ps1:17:1:17:7 | Call to Sink | test.ps1:17:1:17:7 | pre-return value for Call to Sink |
| test.ps1:17:1:17:7 | Call to Sink | test.ps1:17:1:17:7 | pre-return value for Call to Sink |
| test.ps1:17:1:17:7 | implicit unwrapping of Call to Sink | test.ps1:1:1:21:27 | return value for {...} |
| test.ps1:17:1:17:7 | pre-return value for Call to Sink | test.ps1:17:1:17:7 | implicit unwrapping of Call to Sink |
| test.ps1:17:1:17:7 | Call to Sink | test.ps1:1:1:21:27 | pre-return value for {...} |
| test.ps1:17:1:17:7 | Call to Sink | test.ps1:1:1:21:27 | pre-return value for {...} |
| test.ps1:19:1:19:2 | f | test.ps1:21:25:21:26 | f |
| test.ps1:19:6:19:11 | Call to Source | test.ps1:19:1:19:2 | f |
| test.ps1:21:1:21:27 | Call to Sink | test.ps1:21:1:21:27 | pre-return value for Call to Sink |
| test.ps1:21:1:21:27 | Call to Sink | test.ps1:21:1:21:27 | pre-return value for Call to Sink |
| test.ps1:21:1:21:27 | implicit unwrapping of Call to Sink | test.ps1:1:1:21:27 | return value for {...} |
| test.ps1:21:1:21:27 | pre-return value for Call to Sink | test.ps1:21:1:21:27 | implicit unwrapping of Call to Sink |
| test.ps1:21:1:21:27 | Call to Sink | test.ps1:1:1:21:27 | pre-return value for {...} |
| test.ps1:21:1:21:27 | Call to Sink | test.ps1:1:1:21:27 | pre-return value for {...} |

View File

@@ -1,61 +1,41 @@
| test.ps1:1:1:1:3 | a1 | test.ps1:2:6:2:8 | a1 |
| test.ps1:1:1:21:27 | implicit unwrapping of {...} | test.ps1:1:1:21:27 | return value for {...} |
| test.ps1:1:1:21:27 | pre-return value for {...} | test.ps1:1:1:21:27 | implicit unwrapping of {...} |
| test.ps1:1:1:21:27 | pre-return value for {...} | test.ps1:1:1:21:27 | implicit unwrapping of {...} |
| test.ps1:1:7:1:12 | Call to Source | test.ps1:1:1:1:3 | a1 |
| test.ps1:2:1:2:8 | Call to Sink | test.ps1:2:1:2:8 | pre-return value for Call to Sink |
| test.ps1:2:1:2:8 | Call to Sink | test.ps1:2:1:2:8 | pre-return value for Call to Sink |
| test.ps1:2:1:2:8 | implicit unwrapping of Call to Sink | test.ps1:1:1:21:27 | return value for {...} |
| test.ps1:2:1:2:8 | pre-return value for Call to Sink | test.ps1:2:1:2:8 | implicit unwrapping of Call to Sink |
| test.ps1:2:1:2:8 | pre-return value for Call to Sink | test.ps1:2:1:2:8 | implicit unwrapping of Call to Sink |
| test.ps1:2:1:2:8 | Call to Sink | test.ps1:1:1:21:27 | pre-return value for {...} |
| test.ps1:2:1:2:8 | Call to Sink | test.ps1:1:1:21:27 | pre-return value for {...} |
| test.ps1:4:1:4:2 | b | test.ps1:5:4:5:5 | b |
| test.ps1:4:6:4:12 | Call to GetBool | test.ps1:4:1:4:2 | b |
| test.ps1:5:1:7:1 | if (...) {...} | test.ps1:5:1:7:1 | pre-return value for if (...) {...} |
| test.ps1:5:1:7:1 | if (...) {...} | test.ps1:5:1:7:1 | pre-return value for if (...) {...} |
| test.ps1:5:1:7:1 | implicit unwrapping of if (...) {...} | test.ps1:1:1:21:27 | return value for {...} |
| test.ps1:5:1:7:1 | phi | test.ps1:8:6:8:8 | a2 |
| test.ps1:5:1:7:1 | pre-return value for if (...) {...} | test.ps1:5:1:7:1 | implicit unwrapping of if (...) {...} |
| test.ps1:5:1:7:1 | pre-return value for if (...) {...} | test.ps1:5:1:7:1 | implicit unwrapping of if (...) {...} |
| test.ps1:5:4:5:5 | b | test.ps1:10:14:10:15 | b |
| test.ps1:6:5:6:7 | a2 | test.ps1:6:11:6:16 | [input] phi |
| test.ps1:6:11:6:16 | Call to Source | test.ps1:6:5:6:7 | a2 |
| test.ps1:6:11:6:16 | [input] phi | test.ps1:5:1:7:1 | phi |
| test.ps1:8:1:8:8 | Call to Sink | test.ps1:8:1:8:8 | pre-return value for Call to Sink |
| test.ps1:8:1:8:8 | Call to Sink | test.ps1:8:1:8:8 | pre-return value for Call to Sink |
| test.ps1:8:1:8:8 | implicit unwrapping of Call to Sink | test.ps1:1:1:21:27 | return value for {...} |
| test.ps1:8:1:8:8 | pre-return value for Call to Sink | test.ps1:8:1:8:8 | implicit unwrapping of Call to Sink |
| test.ps1:8:1:8:8 | pre-return value for Call to Sink | test.ps1:8:1:8:8 | implicit unwrapping of Call to Sink |
| test.ps1:8:1:8:8 | Call to Sink | test.ps1:1:1:21:27 | pre-return value for {...} |
| test.ps1:8:1:8:8 | Call to Sink | test.ps1:1:1:21:27 | pre-return value for {...} |
| test.ps1:10:1:10:2 | c | test.ps1:11:6:11:7 | c |
| test.ps1:10:6:10:15 | [...]... | test.ps1:10:1:10:2 | c |
| test.ps1:10:14:10:15 | b | test.ps1:10:6:10:15 | [...]... |
| test.ps1:11:1:11:7 | Call to Sink | test.ps1:11:1:11:7 | pre-return value for Call to Sink |
| test.ps1:11:1:11:7 | Call to Sink | test.ps1:11:1:11:7 | pre-return value for Call to Sink |
| test.ps1:11:1:11:7 | implicit unwrapping of Call to Sink | test.ps1:1:1:21:27 | return value for {...} |
| test.ps1:11:1:11:7 | pre-return value for Call to Sink | test.ps1:11:1:11:7 | implicit unwrapping of Call to Sink |
| test.ps1:11:1:11:7 | pre-return value for Call to Sink | test.ps1:11:1:11:7 | implicit unwrapping of Call to Sink |
| test.ps1:11:1:11:7 | Call to Sink | test.ps1:1:1:21:27 | pre-return value for {...} |
| test.ps1:11:1:11:7 | Call to Sink | test.ps1:1:1:21:27 | pre-return value for {...} |
| test.ps1:11:6:11:7 | [post] c | test.ps1:13:7:13:8 | c |
| test.ps1:11:6:11:7 | c | test.ps1:13:7:13:8 | c |
| test.ps1:13:1:13:2 | d | test.ps1:14:6:14:7 | d |
| test.ps1:13:6:13:9 | (...) | test.ps1:13:1:13:2 | d |
| test.ps1:13:7:13:8 | c | test.ps1:13:6:13:9 | (...) |
| test.ps1:14:1:14:7 | Call to Sink | test.ps1:14:1:14:7 | pre-return value for Call to Sink |
| test.ps1:14:1:14:7 | Call to Sink | test.ps1:14:1:14:7 | pre-return value for Call to Sink |
| test.ps1:14:1:14:7 | implicit unwrapping of Call to Sink | test.ps1:1:1:21:27 | return value for {...} |
| test.ps1:14:1:14:7 | pre-return value for Call to Sink | test.ps1:14:1:14:7 | implicit unwrapping of Call to Sink |
| test.ps1:14:1:14:7 | pre-return value for Call to Sink | test.ps1:14:1:14:7 | implicit unwrapping of Call to Sink |
| test.ps1:14:1:14:7 | Call to Sink | test.ps1:1:1:21:27 | pre-return value for {...} |
| test.ps1:14:1:14:7 | Call to Sink | test.ps1:1:1:21:27 | pre-return value for {...} |
| test.ps1:14:6:14:7 | [post] d | test.ps1:16:6:16:7 | d |
| test.ps1:14:6:14:7 | d | test.ps1:16:6:16:7 | d |
| test.ps1:16:1:16:2 | e | test.ps1:17:6:17:7 | e |
| test.ps1:16:6:16:7 | d | test.ps1:16:6:16:11 | ...+... |
| test.ps1:16:6:16:11 | ...+... | test.ps1:16:1:16:2 | e |
| test.ps1:16:11:16:11 | 1 | test.ps1:16:6:16:11 | ...+... |
| test.ps1:17:1:17:7 | Call to Sink | test.ps1:17:1:17:7 | pre-return value for Call to Sink |
| test.ps1:17:1:17:7 | Call to Sink | test.ps1:17:1:17:7 | pre-return value for Call to Sink |
| test.ps1:17:1:17:7 | implicit unwrapping of Call to Sink | test.ps1:1:1:21:27 | return value for {...} |
| test.ps1:17:1:17:7 | pre-return value for Call to Sink | test.ps1:17:1:17:7 | implicit unwrapping of Call to Sink |
| test.ps1:17:1:17:7 | pre-return value for Call to Sink | test.ps1:17:1:17:7 | implicit unwrapping of Call to Sink |
| test.ps1:17:1:17:7 | Call to Sink | test.ps1:1:1:21:27 | pre-return value for {...} |
| test.ps1:17:1:17:7 | Call to Sink | test.ps1:1:1:21:27 | pre-return value for {...} |
| test.ps1:19:1:19:2 | f | test.ps1:21:25:21:26 | f |
| test.ps1:19:6:19:11 | Call to Source | test.ps1:19:1:19:2 | f |
| test.ps1:21:1:21:27 | Call to Sink | test.ps1:21:1:21:27 | pre-return value for Call to Sink |
| test.ps1:21:1:21:27 | Call to Sink | test.ps1:21:1:21:27 | pre-return value for Call to Sink |
| test.ps1:21:1:21:27 | implicit unwrapping of Call to Sink | test.ps1:1:1:21:27 | return value for {...} |
| test.ps1:21:1:21:27 | pre-return value for Call to Sink | test.ps1:21:1:21:27 | implicit unwrapping of Call to Sink |
| test.ps1:21:1:21:27 | pre-return value for Call to Sink | test.ps1:21:1:21:27 | implicit unwrapping of Call to Sink |
| test.ps1:21:1:21:27 | Call to Sink | test.ps1:1:1:21:27 | pre-return value for {...} |
| test.ps1:21:1:21:27 | Call to Sink | test.ps1:1:1:21:27 | pre-return value for {...} |
| test.ps1:21:25:21:26 | f | test.ps1:21:6:21:27 | here is a string: $f |

View File

@@ -8,6 +8,16 @@ edges
| test.ps1:13:6:13:20 | Call to callSourceTwice [element] | test.ps1:16:6:16:7 | x [element] | provenance | |
| test.ps1:15:6:15:7 | x [element] | test.ps1:15:6:15:10 | ...[...] | provenance | |
| test.ps1:16:6:16:7 | x [element] | test.ps1:16:6:16:10 | ...[...] | provenance | |
| test.ps1:19:12:19:21 | Call to Source | test.ps1:22:6:22:18 | Call to returnSource1 | provenance | |
| test.ps1:22:6:22:18 | Call to returnSource1 | test.ps1:23:6:23:7 | x | provenance | |
| test.ps1:26:10:26:19 | Call to Source | test.ps1:27:5:27:6 | x | provenance | |
| test.ps1:27:5:27:6 | x | test.ps1:32:6:32:18 | Call to returnSource2 [element] | provenance | |
| test.ps1:28:10:28:19 | Call to Source | test.ps1:29:12:29:13 | y | provenance | |
| test.ps1:29:12:29:13 | y | test.ps1:32:6:32:18 | Call to returnSource2 [element] | provenance | |
| test.ps1:32:6:32:18 | Call to returnSource2 [element] | test.ps1:33:6:33:7 | x [element] | provenance | |
| test.ps1:32:6:32:18 | Call to returnSource2 [element] | test.ps1:34:6:34:7 | x [element] | provenance | |
| test.ps1:33:6:33:7 | x [element] | test.ps1:33:6:33:10 | ...[...] | provenance | |
| test.ps1:34:6:34:7 | x [element] | test.ps1:34:6:34:10 | ...[...] | provenance | |
| test.ps1:38:9:38:18 | Call to Source | test.ps1:42:6:42:21 | Call to callSourceInLoop [element] | provenance | |
| test.ps1:42:6:42:21 | Call to callSourceInLoop [element] | test.ps1:43:6:43:7 | x [element] | provenance | |
| test.ps1:42:6:42:21 | Call to callSourceInLoop [element] | test.ps1:44:6:44:7 | x [element] | provenance | |
@@ -24,6 +34,18 @@ nodes
| test.ps1:15:6:15:10 | ...[...] | semmle.label | ...[...] |
| test.ps1:16:6:16:7 | x [element] | semmle.label | x [element] |
| test.ps1:16:6:16:10 | ...[...] | semmle.label | ...[...] |
| test.ps1:19:12:19:21 | Call to Source | semmle.label | Call to Source |
| test.ps1:22:6:22:18 | Call to returnSource1 | semmle.label | Call to returnSource1 |
| test.ps1:23:6:23:7 | x | semmle.label | x |
| test.ps1:26:10:26:19 | Call to Source | semmle.label | Call to Source |
| test.ps1:27:5:27:6 | x | semmle.label | x |
| test.ps1:28:10:28:19 | Call to Source | semmle.label | Call to Source |
| test.ps1:29:12:29:13 | y | semmle.label | y |
| test.ps1:32:6:32:18 | Call to returnSource2 [element] | semmle.label | Call to returnSource2 [element] |
| test.ps1:33:6:33:7 | x [element] | semmle.label | x [element] |
| test.ps1:33:6:33:10 | ...[...] | semmle.label | ...[...] |
| test.ps1:34:6:34:7 | x [element] | semmle.label | x [element] |
| test.ps1:34:6:34:10 | ...[...] | semmle.label | ...[...] |
| test.ps1:38:9:38:18 | Call to Source | semmle.label | Call to Source |
| test.ps1:42:6:42:21 | Call to callSourceInLoop [element] | semmle.label | Call to callSourceInLoop [element] |
| test.ps1:43:6:43:7 | x [element] | semmle.label | x [element] |
@@ -32,16 +54,16 @@ nodes
| test.ps1:44:6:44:10 | ...[...] | semmle.label | ...[...] |
subpaths
testFailures
| test.ps1:23:9:23:26 | # $ hasValueFlow=4 | Missing result: hasValueFlow=4 |
| test.ps1:33:12:33:54 | # $ hasValueFlow=5 SPURIOUS: hasValueFlow=6 | Fixed spurious result: hasValueFlow=6 |
| test.ps1:33:12:33:54 | # $ hasValueFlow=5 SPURIOUS: hasValueFlow=6 | Missing result: hasValueFlow=5 |
| test.ps1:34:12:34:54 | # $ hasValueFlow=6 SPURIOUS: hasValueFlow=5 | Fixed spurious result: hasValueFlow=5 |
| test.ps1:34:12:34:54 | # $ hasValueFlow=6 SPURIOUS: hasValueFlow=5 | Missing result: hasValueFlow=6 |
#select
| test.ps1:6:6:6:7 | x | test.ps1:2:5:2:14 | Call to Source | test.ps1:6:6:6:7 | x | $@ | test.ps1:2:5:2:14 | Call to Source | Call to Source |
| test.ps1:15:6:15:10 | ...[...] | test.ps1:9:5:9:14 | Call to Source | test.ps1:15:6:15:10 | ...[...] | $@ | test.ps1:9:5:9:14 | Call to Source | Call to Source |
| test.ps1:15:6:15:10 | ...[...] | test.ps1:10:5:10:14 | Call to Source | test.ps1:15:6:15:10 | ...[...] | $@ | test.ps1:10:5:10:14 | Call to Source | Call to Source |
| test.ps1:16:6:16:10 | ...[...] | test.ps1:9:5:9:14 | Call to Source | test.ps1:16:6:16:10 | ...[...] | $@ | test.ps1:9:5:9:14 | Call to Source | Call to Source |
| test.ps1:16:6:16:10 | ...[...] | test.ps1:10:5:10:14 | Call to Source | test.ps1:16:6:16:10 | ...[...] | $@ | test.ps1:10:5:10:14 | Call to Source | Call to Source |
| test.ps1:23:6:23:7 | x | test.ps1:19:12:19:21 | Call to Source | test.ps1:23:6:23:7 | x | $@ | test.ps1:19:12:19:21 | Call to Source | Call to Source |
| test.ps1:33:6:33:10 | ...[...] | test.ps1:26:10:26:19 | Call to Source | test.ps1:33:6:33:10 | ...[...] | $@ | test.ps1:26:10:26:19 | Call to Source | Call to Source |
| test.ps1:33:6:33:10 | ...[...] | test.ps1:28:10:28:19 | Call to Source | test.ps1:33:6:33:10 | ...[...] | $@ | test.ps1:28:10:28:19 | Call to Source | Call to Source |
| test.ps1:34:6:34:10 | ...[...] | test.ps1:26:10:26:19 | Call to Source | test.ps1:34:6:34:10 | ...[...] | $@ | test.ps1:26:10:26:19 | Call to Source | Call to Source |
| test.ps1:34:6:34:10 | ...[...] | test.ps1:28:10:28:19 | Call to Source | test.ps1:34:6:34:10 | ...[...] | $@ | test.ps1:28:10:28:19 | Call to Source | Call to Source |
| test.ps1:43:6:43:10 | ...[...] | test.ps1:38:9:38:18 | Call to Source | test.ps1:43:6:43:10 | ...[...] | $@ | test.ps1:38:9:38:18 | Call to Source | Call to Source |
| test.ps1:44:6:44:10 | ...[...] | test.ps1:38:9:38:18 | Call to Source | test.ps1:44:6:44:10 | ...[...] | $@ | test.ps1:38:9:38:18 | Call to Source | Call to Source |