Skip to content

Commit 9bdfaa0

Browse files
authored
Merge pull request #96 from microsoft/powershell-param-def-class
PS: Place parameter definitions in the SSA graph
2 parents f0429fa + fbcac10 commit 9bdfaa0

File tree

10 files changed

+136
-18
lines changed

10 files changed

+136
-18
lines changed

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import powershell
2+
import semmle.code.powershell.controlflow.BasicBlocks
23

34
abstract private class AbstractFunction extends Ast {
45
abstract string getName();
@@ -20,6 +21,8 @@ abstract private class AbstractFunction extends Ast {
2021
}
2122

2223
final Parameter getAParameter() { result = this.getParameter(_) }
24+
25+
EntryBasicBlock getEntryBasicBlock() { result.getScope() = this.getBody() }
2326
}
2427

2528
class NonMemberFunction extends @function_definition, Stmt, AbstractFunction {

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

Lines changed: 36 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,40 @@ private import powershell
22
private import semmle.code.powershell.controlflow.internal.Scope
33
private import internal.Internal as Internal
44

5+
private predicate isFunctionParameterImpl(Internal::Parameter p, Function f, int i) {
6+
function_definition_parameter(f, i, p)
7+
or
8+
function_member_parameter(f, i, p)
9+
}
10+
11+
private predicate hasParameterBlockImpl(Internal::Parameter p, ParamBlock block, int i) {
12+
param_block_parameter(block, i, p)
13+
}
14+
15+
/**
16+
* Gets the enclosing scope of `p`.
17+
*
18+
* For a function parameter, this is the function body. For a parameter from a
19+
* parameter block, this is the enclosing scope of the parameter block.
20+
*
21+
* In both of the above cases, the enclosing scope is the function body.
22+
*/
23+
private Scope getEnclosingScopeImpl(Internal::Parameter p) {
24+
exists(Function f |
25+
isFunctionParameterImpl(p, f, _) and
26+
result = f.getBody()
27+
)
28+
or
29+
exists(ParamBlock b |
30+
hasParameterBlockImpl(p, b, _) and
31+
result = b.getEnclosingScope()
32+
)
33+
}
34+
535
bindingset[scope]
636
pragma[inline_late]
737
private predicate isParameterImpl(string name, Scope scope) {
8-
exists(Internal::Parameter p | p.getName() = name and p.getEnclosingScope() = scope)
38+
exists(Internal::Parameter p | p.getName() = name and getEnclosingScopeImpl(p) = scope)
939
or
1040
name = "_"
1141
}
@@ -47,17 +77,13 @@ private class InternalParameter extends ParameterImpl, TInternalParameter {
4777

4878
override string getName() { result = p.getName() }
4979

50-
final override Scope getEnclosingScope() { result = p.getEnclosingScope() }
80+
final override Scope getEnclosingScope() { result = getEnclosingScopeImpl(p) }
5181

5282
override predicate hasParameterBlock(ParamBlock block, int i) {
53-
param_block_parameter(block, i, p)
83+
hasParameterBlockImpl(p, block, i)
5484
}
5585

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-
}
86+
override predicate isFunctionParameter(Function f, int i) { isFunctionParameterImpl(p, f, i) }
6187

6288
override Expr getDefaultValue() { result = p.getDefaultValue() }
6389
}
@@ -161,4 +187,6 @@ class Parameter extends AbstractLocalScopeVariable, TParameter {
161187
predicate hasDefaultValue() { exists(this.getDefaultValue()) }
162188

163189
int getIndex() { this.isFunctionParameter(_, result) }
190+
191+
Function getFunction() { result.getBody() = this.getDeclaringScope() }
164192
}

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

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -34,18 +34,24 @@ class VarAccess extends @variable_expression, Expr {
3434
Variable getVariable() { result.getAnAccess() = this }
3535
}
3636

37-
private predicate isVariableWriteAccess(Expr e) {
38-
e = any(AssignStmt assign).getLeftHandSide()
37+
private predicate isExplicitVariableWriteAccess(Expr e, AssignStmt assign) {
38+
e = assign.getLeftHandSide()
3939
or
40-
e = any(ConvertExpr convert | isVariableWriteAccess(convert)).getExpr()
40+
e = any(ConvertExpr convert | isExplicitVariableWriteAccess(convert, assign)).getExpr()
4141
or
42-
e = any(ArrayLiteral array | isVariableWriteAccess(array)).getAnElement()
42+
e = any(ArrayLiteral array | isExplicitVariableWriteAccess(array, assign)).getAnElement()
4343
}
4444

45+
private predicate isImplicitVariableWriteAccess(Expr e) { none() }
46+
4547
class VarReadAccess extends VarAccess {
4648
VarReadAccess() { not this instanceof VarWriteAccess }
4749
}
4850

4951
class VarWriteAccess extends VarAccess {
50-
VarWriteAccess() { isVariableWriteAccess(this) }
52+
VarWriteAccess() { isExplicitVariableWriteAccess(this, _) or isImplicitVariableWriteAccess(this) }
53+
54+
predicate isExplicit(AssignStmt assign) { isExplicitVariableWriteAccess(this, assign) }
55+
56+
predicate isImplicit() { isImplicitVariableWriteAccess(this) }
5157
}

powershell/ql/lib/semmle/code/powershell/controlflow/CfgNodes.qll

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,8 @@ module ExprNodes {
163163
predicate isExplicitWrite(StmtNodes::AssignStmtCfgNode assignment) {
164164
this = assignment.getLeftHandSide()
165165
}
166+
167+
predicate isImplicitWrite() { e.isImplicit() }
166168
}
167169
}
168170

powershell/ql/lib/semmle/code/powershell/dataflow/Ssa.qll

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,21 @@ module Ssa {
103103
final override Location getLocation() { result = write.getLocation() }
104104
}
105105

106+
class ParameterDefinition extends Definition, SsaImpl::WriteDefinition {
107+
private Variable v;
108+
109+
ParameterDefinition() {
110+
exists(BasicBlock bb, int i |
111+
this.definesAt(v, bb, i) and
112+
SsaImpl::parameterWrite(bb, i, v)
113+
)
114+
}
115+
116+
final override string toString() { result = "<parameter> " + v }
117+
118+
final override Location getLocation() { result = v.getLocation() }
119+
}
120+
106121
/**
107122
* An SSA definition inserted at the beginning of a scope to represent an
108123
* uninitialized local variable.

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

Lines changed: 44 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ module SsaInput implements SsaImplCommon::InputSig<Location> {
2929
(
3030
uninitializedWrite(bb, i, v)
3131
or
32+
parameterWrite(bb, i, v)
33+
or
3234
variableWriteActual(bb, i, v, _)
3335
) and
3436
certain = true
@@ -58,6 +60,39 @@ predicate uninitializedWrite(Cfg::EntryBasicBlock bb, int i, LocalVariable v) {
5860
i = -1
5961
}
6062

63+
/**
64+
* Gets index of `p` in a version of the enclosing function where the parameter
65+
* list is reversed.
66+
*
67+
* For example, given
68+
* ```ps
69+
* function f($a, $b) { ... }
70+
* ```
71+
* the inverted index of `$a` is 1, and the inverted index of `$b` is 0.
72+
*/
73+
private int getInvertedIndex(Parameter p) {
74+
exists(int i |
75+
p.getIndex() = i or
76+
p.hasParameterBlock(_, i)
77+
|
78+
result = p.getFunction().getNumberOfParameters() - i - 1
79+
)
80+
}
81+
82+
/**
83+
* Holds if the the SSA definition of `p` should be placed at index `i` in
84+
* block `bb`. Note that the index may be negative.
85+
*/
86+
predicate parameterWrite(Cfg::EntryBasicBlock bb, int i, Parameter p) {
87+
exists(Function f |
88+
f.getEntryBasicBlock() = bb and
89+
p.getFunction() = f and
90+
// If the enclosing function has 2 parameters we map the index of parameter
91+
// 0 to -2, the index of parameter 1 to -1.
92+
i = -getInvertedIndex(p) - 1
93+
)
94+
}
95+
6196
/** Holds if `v` is read at index `i` in basic block `bb`. */
6297
private predicate variableReadActual(Cfg::BasicBlock bb, int i, LocalScopeVariable v) {
6398
exists(VarReadAccess read |
@@ -159,6 +194,9 @@ private module Cached {
159194
n = bb.getNode(i)
160195
|
161196
write.isExplicitWrite(n)
197+
or
198+
write.isImplicitWrite() and
199+
n = write
162200
)
163201
}
164202

@@ -281,19 +319,20 @@ class PhiReadNode extends DefinitionExt, Impl::PhiReadNode {
281319
override Location getLocation() { result = Impl::PhiReadNode.super.getLocation() }
282320
}
283321

284-
abstract class NormalParameter extends Parameter { }
285-
286322
/** Gets the SSA definition node corresponding to parameter `p`. */
287323
pragma[nomagic]
288324
DefinitionExt getParameterDef(Parameter p) {
289-
none() // TODO
325+
exists(Cfg::EntryBasicBlock bb, int i |
326+
parameterWrite(bb, i, p) and
327+
result.definesAt(p, bb, i, _)
328+
)
290329
}
291330

292-
private newtype TParameterExt = TNormalParameter(NormalParameter p)
331+
private newtype TParameterExt = TNormalParameter(Parameter p)
293332

294333
/** A normal parameter or an implicit `self` parameter. */
295334
class ParameterExt extends TParameterExt {
296-
NormalParameter asParameter() { this = TNormalParameter(result) }
335+
Parameter asParameter() { this = TNormalParameter(result) }
297336

298337
predicate isInitializedBy(WriteDefinition def) { def = getParameterDef(this.asParameter()) }
299338

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
$glo_a = 42
2+
$glob_b = $glob_a
3+
4+
function f() {
5+
$a = 43
6+
$b = $a
7+
return $b
8+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
function function-param([int]$n1, [int]$n2) {
2+
return $n1 + $n2
3+
}
4+
5+
function param-block {
6+
param(
7+
[int]$a,
8+
[int]$b
9+
)
10+
return $a + $b
11+
}
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
| explicit.ps1:1:1:8:2 | <uninitialized> glob_a | explicit.ps1:2:11:2:18 | glob_a |
2+
| explicit.ps1:5:5:5:7 | a | explicit.ps1:5:5:5:7 | a |
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
import powershell
2+
import semmle.code.powershell.dataflow.Ssa
3+
4+
query predicate definition(Ssa::Definition def, Variable v) { def.getSourceVariable() = v }

0 commit comments

Comments
 (0)