Skip to content

Commit 4343d6b

Browse files
authored
Merge pull request #93 from microsoft/powershell-ssa-skeleton
PS: SSA skeleton and various fixes
2 parents f63c2b0 + 9499972 commit 4343d6b

File tree

27 files changed

+1328
-493
lines changed

27 files changed

+1328
-493
lines changed

powershell/extractor/Semmle.Extraction.PowerShell/Entities/StatementBlockEntity.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ public override void Populate(TextWriter trapFile)
3232
EntityConstructor.ConstructAppropriateEntity(PowerShellContext, Fragment.Traps[index]));
3333
}
3434
}
35+
36+
trapFile.parent(this, EntityConstructor.ConstructAppropriateEntity(PowerShellContext, Fragment.Parent));
3537
}
3638

3739
public override bool NeedsPopulation => true;

powershell/ql/lib/powershell.qll

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@ import semmle.code.powershell.Attribute
1414
import semmle.code.powershell.NamedAttributeArgument
1515
import semmle.code.powershell.TypeConstraint
1616
import semmle.code.powershell.VariableExpression
17-
import semmle.code.powershell.Parameter
1817
import semmle.code.powershell.ModuleSpecification
1918
import semmle.code.powershell.ParamBlock
2019
import semmle.code.powershell.NamedBlock
@@ -77,3 +76,4 @@ import semmle.code.powershell.IndexExpr
7776
import semmle.code.powershell.HashTable
7877
import semmle.code.powershell.SplitExpr
7978
import semmle.code.powershell.CommentEntity
79+
import semmle.code.powershell.Variable

powershell/ql/lib/qlpack.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,5 +10,6 @@ upgrades: upgrades
1010
dependencies:
1111
codeql/controlflow: ${workspace}
1212
codeql/dataflow: ${workspace}
13+
codeql/ssa: ${workspace}
1314
codeql/util: ${workspace}
1415
warnOnImplicitThis: true
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,12 @@
11
import powershell
2+
private import semmle.code.powershell.controlflow.internal.Scope
23

34
class Ast extends @ast {
45
string toString() { none() }
56

67
Ast getParent() { parent(this, result) }
78

89
Location getLocation() { none() }
10+
11+
final Scope getEnclosingScope() { result = scopeOf(this) }
912
}

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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,15 @@ class ForEachStmt extends @foreach_statement, LoopStmt {
77

88
final override StmtBlock getBody() { foreach_statement(this, _, _, result, _) }
99

10-
VarAccess getVariable() { foreach_statement(this, result, _, _, _) }
10+
VarAccess getVarAccess() { foreach_statement(this, result, _, _, _) }
11+
12+
Variable getVariable() {
13+
exists(VarAccess va |
14+
va = this.getVarAccess() and
15+
foreach_statement(this, va, _, _, _) and
16+
result = va.getVariable()
17+
)
18+
}
1119

1220
PipelineBase getIterableExpr() { foreach_statement(this, _, result, _, _) }
1321

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ class NonMemberFunction extends @function_definition, Stmt, AbstractFunction {
3535

3636
predicate isWorkflow() { function_definition(this, _, _, _, true) }
3737

38-
override Parameter getFunctionParameter(int i) { function_definition_parameter(this, i, result) }
38+
override Parameter getFunctionParameter(int i) { result.isFunctionParameter(this, i) }
3939
}
4040

4141
class MemberFunction extends @function_member, Member, AbstractFunction {
@@ -57,7 +57,7 @@ class MemberFunction extends @function_member, Member, AbstractFunction {
5757

5858
predicate isConstructor() { function_member(this, _, true, _, _, _, _, _, _) }
5959

60-
override Parameter getFunctionParameter(int i) { function_member_parameter(this, i, result) }
60+
override Parameter getFunctionParameter(int i) { result.isFunctionParameter(this, i) }
6161

6262
TypeConstraint getTypeConstraint() { function_member_return_type(this, result) }
6363
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ class NamedBlock extends @named_block, Ast {
99

1010
int getNumTraps() { named_block(this, _, result) }
1111

12-
Stmt getStatement(int i) { named_block_statement(this, i, result) }
12+
Stmt getStmt(int i) { named_block_statement(this, i, result) }
1313

14-
Stmt getAStatement() { result = this.getStatement(_) }
14+
Stmt getAStmt() { result = this.getStmt(_) }
1515

1616
TrapStmt getTrap(int i) { named_block_trap(this, i, result) }
1717

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ class ParamBlock extends @param_block, Ast {
1313

1414
Attribute getAnAttribute() { result = this.getAttribute(_) }
1515

16-
Parameter getParameter(int i) { param_block_parameter(this, i, result) }
16+
Parameter getParameter(int i) { result.hasParameterBlock(this, i) }
1717

1818
Parameter getAParameter() { result = this.getParameter(_) }
1919
}
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
private import powershell
2+
private import semmle.code.powershell.controlflow.internal.Scope
3+
private import internal.Internal as Internal
4+
5+
bindingset[scope]
6+
pragma[inline_late]
7+
private predicate isParameterImpl(string name, Scope scope) {
8+
exists(Internal::Parameter p | p.getName() = name and p.getEnclosingScope() = scope)
9+
or
10+
name = "_"
11+
}
12+
13+
private newtype TParameterImpl =
14+
TInternalParameter(Internal::Parameter p) or
15+
TUnderscore(Scope scope) {
16+
exists(VarAccess va | va.getUserPath() = "_" and scope = va.getEnclosingScope())
17+
}
18+
19+
private class ParameterImpl extends TParameterImpl {
20+
abstract Location getLocation();
21+
22+
string toString() { result = this.getName() }
23+
24+
abstract string getName();
25+
26+
abstract Scope getEnclosingScope();
27+
28+
predicate hasParameterBlock(ParamBlock block, int i) { none() }
29+
30+
predicate isFunctionParameter(Function f, int i) { none() }
31+
32+
Expr getDefaultValue() { none() }
33+
34+
VarAccess getAnAccess() {
35+
// TODO: This won't join order nicely.
36+
result.getUserPath() = this.getName() and
37+
result.getEnclosingScope() = this.getEnclosingScope()
38+
}
39+
}
40+
41+
private class InternalParameter extends ParameterImpl, TInternalParameter {
42+
Internal::Parameter p;
43+
44+
InternalParameter() { this = TInternalParameter(p) }
45+
46+
override Location getLocation() { result = p.getLocation() }
47+
48+
override string getName() { result = p.getName() }
49+
50+
final override Scope getEnclosingScope() { result = p.getEnclosingScope() }
51+
52+
override predicate hasParameterBlock(ParamBlock block, int i) {
53+
param_block_parameter(block, i, p)
54+
}
55+
56+
override predicate isFunctionParameter(Function f, int i) {
57+
function_definition_parameter(f, i, p)
58+
or
59+
function_member_parameter(f, i, p)
60+
}
61+
62+
override Expr getDefaultValue() { result = p.getDefaultValue() }
63+
}
64+
65+
private class Underscore extends ParameterImpl, TUnderscore {
66+
Scope scope;
67+
68+
Underscore() { this = TUnderscore(scope) }
69+
70+
override Location getLocation() {
71+
// The location is the first access (ordered by location) to the variable in the scope
72+
exists(VarAccess va |
73+
va =
74+
min(VarAccess cand, Location location |
75+
cand = this.getAnAccess() and location = cand.getLocation()
76+
|
77+
cand order by location.getStartLine(), location.getStartColumn()
78+
) and
79+
result = va.getLocation()
80+
)
81+
}
82+
83+
override string getName() { result = "_" }
84+
85+
final override Scope getEnclosingScope() { result = scope }
86+
}
87+
88+
private newtype TVariable =
89+
TLocalVariable(string name, Scope scope) {
90+
not isParameterImpl(name, scope) and
91+
exists(VarAccess va | va.getUserPath() = name and scope = va.getEnclosingScope())
92+
} or
93+
TParameter(ParameterImpl p)
94+
95+
private class AbstractVariable extends TVariable {
96+
abstract Location getLocation();
97+
98+
string toString() { result = this.getName() }
99+
100+
abstract string getName();
101+
102+
abstract Scope getDeclaringScope();
103+
104+
VarAccess getAnAccess() {
105+
exists(string s |
106+
s = concat(this.getAQlClass(), ", ") and
107+
// TODO: This won't join order nicely.
108+
result.getUserPath() = this.getName() and
109+
result.getEnclosingScope() = this.getDeclaringScope()
110+
)
111+
}
112+
}
113+
114+
class LocalVariable extends AbstractVariable, TLocalVariable {
115+
string name;
116+
Scope scope;
117+
118+
LocalVariable() { this = TLocalVariable(name, scope) }
119+
120+
override Location getLocation() {
121+
// The location is the first access (ordered by location) to the variable in the scope
122+
exists(VarAccess va |
123+
va =
124+
min(VarAccess cand, Location location |
125+
cand = this.getAnAccess() and location = cand.getLocation()
126+
|
127+
cand order by location.getStartLine(), location.getStartColumn()
128+
) and
129+
result = va.getLocation()
130+
)
131+
}
132+
133+
override string getName() { result = name }
134+
135+
final override Scope getDeclaringScope() { result = scope }
136+
}
137+
138+
class Parameter extends AbstractVariable, TParameter {
139+
ParameterImpl p;
140+
141+
Parameter() { this = TParameter(p) }
142+
143+
override Location getLocation() { result = p.getLocation() }
144+
145+
override string getName() { result = p.getName() }
146+
147+
final override Scope getDeclaringScope() { result = p.getEnclosingScope() }
148+
149+
predicate hasParameterBlock(ParamBlock block, int i) { p.hasParameterBlock(block, i) }
150+
151+
predicate isFunctionParameter(Function f, int i) { p.isFunctionParameter(f, i) }
152+
153+
Expr getDefaultValue() { result = p.getDefaultValue() }
154+
155+
predicate hasDefaultValue() { exists(this.getDefaultValue()) }
156+
157+
int getIndex() { this.isFunctionParameter(_, result) }
158+
}
159+
160+
final class Variable = AbstractVariable;

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
import powershell
22

3+
private predicate isParameterName(@variable_expression ve) { parameter(_, ve, _, _) }
4+
35
class VarAccess extends @variable_expression, Expr {
6+
VarAccess() { not isParameterName(this) }
7+
48
override string toString() { result = this.getUserPath() }
59

610
override SourceLocation getLocation() { variable_expression_location(this, result) }
@@ -26,4 +30,22 @@ class VarAccess extends @variable_expression, Expr {
2630
boolean isVariable() { variable_expression(this, _, _, _, _, _, _, _, _, _, result, _) }
2731

2832
boolean isDriveQualified() { variable_expression(this, _, _, _, _, _, _, _, _, _, _, result) }
33+
34+
Variable getVariable() { result.getAnAccess() = this }
35+
}
36+
37+
private predicate isVariableWriteAccess(Expr e) {
38+
e = any(AssignStmt assign).getLeftHandSide()
39+
or
40+
e = any(ConvertExpr convert | isVariableWriteAccess(convert)).getExpr()
41+
or
42+
e = any(ArrayLiteral array | isVariableWriteAccess(array)).getAnElement()
43+
}
44+
45+
class VarReadAccess extends VarAccess {
46+
VarReadAccess() { not this instanceof VarWriteAccess }
47+
}
48+
49+
class VarWriteAccess extends VarAccess {
50+
VarWriteAccess() { isVariableWriteAccess(this) }
2951
}

0 commit comments

Comments
 (0)