Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ public override void Populate(TextWriter trapFile)
EntityConstructor.ConstructAppropriateEntity(PowerShellContext, Fragment.Traps[index]));
}
}

trapFile.parent(this, EntityConstructor.ConstructAppropriateEntity(PowerShellContext, Fragment.Parent));
}

public override bool NeedsPopulation => true;
Expand Down
2 changes: 1 addition & 1 deletion powershell/ql/lib/powershell.qll
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ import semmle.code.powershell.Attribute
import semmle.code.powershell.NamedAttributeArgument
import semmle.code.powershell.TypeConstraint
import semmle.code.powershell.VariableExpression
import semmle.code.powershell.Parameter
import semmle.code.powershell.ModuleSpecification
import semmle.code.powershell.ParamBlock
import semmle.code.powershell.NamedBlock
Expand Down Expand Up @@ -77,3 +76,4 @@ import semmle.code.powershell.IndexExpr
import semmle.code.powershell.HashTable
import semmle.code.powershell.SplitExpr
import semmle.code.powershell.CommentEntity
import semmle.code.powershell.Variable
1 change: 1 addition & 0 deletions powershell/ql/lib/qlpack.yml
Original file line number Diff line number Diff line change
Expand Up @@ -10,5 +10,6 @@ upgrades: upgrades
dependencies:
codeql/controlflow: ${workspace}
codeql/dataflow: ${workspace}
codeql/ssa: ${workspace}
codeql/util: ${workspace}
warnOnImplicitThis: true
3 changes: 3 additions & 0 deletions powershell/ql/lib/semmle/code/powershell/Ast.qll
Original file line number Diff line number Diff line change
@@ -1,9 +1,12 @@
import powershell
private import semmle.code.powershell.controlflow.internal.Scope

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

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

Location getLocation() { none() }

final Scope getEnclosingScope() { result = scopeOf(this) }
}
10 changes: 9 additions & 1 deletion powershell/ql/lib/semmle/code/powershell/ForEachStmt.qll
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,15 @@ class ForEachStmt extends @foreach_statement, LoopStmt {

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

VarAccess getVariable() { foreach_statement(this, result, _, _, _) }
VarAccess getVarAccess() { foreach_statement(this, result, _, _, _) }

Variable getVariable() {
exists(VarAccess va |
va = this.getVarAccess() and
foreach_statement(this, va, _, _, _) and
result = va.getVariable()
)
}

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

Expand Down
4 changes: 2 additions & 2 deletions powershell/ql/lib/semmle/code/powershell/Function.qll
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class NonMemberFunction extends @function_definition, Stmt, AbstractFunction {

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

override Parameter getFunctionParameter(int i) { function_definition_parameter(this, i, result) }
override Parameter getFunctionParameter(int i) { result.isFunctionParameter(this, i) }
}

class MemberFunction extends @function_member, Member, AbstractFunction {
Expand All @@ -57,7 +57,7 @@ class MemberFunction extends @function_member, Member, AbstractFunction {

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

override Parameter getFunctionParameter(int i) { function_member_parameter(this, i, result) }
override Parameter getFunctionParameter(int i) { result.isFunctionParameter(this, i) }

TypeConstraint getTypeConstraint() { function_member_return_type(this, result) }
}
Expand Down
4 changes: 2 additions & 2 deletions powershell/ql/lib/semmle/code/powershell/NamedBlock.qll
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,9 @@ class NamedBlock extends @named_block, Ast {

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

Stmt getStatement(int i) { named_block_statement(this, i, result) }
Stmt getStmt(int i) { named_block_statement(this, i, result) }

Stmt getAStatement() { result = this.getStatement(_) }
Stmt getAStmt() { result = this.getStmt(_) }

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

Expand Down
2 changes: 1 addition & 1 deletion powershell/ql/lib/semmle/code/powershell/ParamBlock.qll
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ class ParamBlock extends @param_block, Ast {

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

Parameter getParameter(int i) { param_block_parameter(this, i, result) }
Parameter getParameter(int i) { result.hasParameterBlock(this, i) }

Parameter getAParameter() { result = this.getParameter(_) }
}
160 changes: 160 additions & 0 deletions powershell/ql/lib/semmle/code/powershell/Variable.qll
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
private import powershell
private import semmle.code.powershell.controlflow.internal.Scope
private import internal.Internal as Internal

bindingset[scope]
pragma[inline_late]
private predicate isParameterImpl(string name, Scope scope) {
exists(Internal::Parameter p | p.getName() = name and p.getEnclosingScope() = scope)
or
name = "_"
}

private newtype TParameterImpl =
TInternalParameter(Internal::Parameter p) or
TUnderscore(Scope scope) {
exists(VarAccess va | va.getUserPath() = "_" and scope = va.getEnclosingScope())
}

private class ParameterImpl extends TParameterImpl {
abstract Location getLocation();

string toString() { result = this.getName() }

abstract string getName();

abstract Scope getEnclosingScope();

predicate hasParameterBlock(ParamBlock block, int i) { none() }

predicate isFunctionParameter(Function f, int i) { none() }

Expr getDefaultValue() { none() }

VarAccess getAnAccess() {
// TODO: This won't join order nicely.
result.getUserPath() = this.getName() and
result.getEnclosingScope() = this.getEnclosingScope()
}
}

private class InternalParameter extends ParameterImpl, TInternalParameter {
Internal::Parameter p;

InternalParameter() { this = TInternalParameter(p) }

override Location getLocation() { result = p.getLocation() }

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

final override Scope getEnclosingScope() { result = p.getEnclosingScope() }

override predicate hasParameterBlock(ParamBlock block, int i) {
param_block_parameter(block, i, p)
}

override predicate isFunctionParameter(Function f, int i) {
function_definition_parameter(f, i, p)
or
function_member_parameter(f, i, p)
}

override Expr getDefaultValue() { result = p.getDefaultValue() }
}

private class Underscore extends ParameterImpl, TUnderscore {
Scope scope;

Underscore() { this = TUnderscore(scope) }

override Location getLocation() {
// The location is the first access (ordered by location) to the variable in the scope
exists(VarAccess va |
va =
min(VarAccess cand, Location location |
cand = this.getAnAccess() and location = cand.getLocation()
|
cand order by location.getStartLine(), location.getStartColumn()
) and
result = va.getLocation()
)
}

override string getName() { result = "_" }

final override Scope getEnclosingScope() { result = scope }
}

private newtype TVariable =
TLocalVariable(string name, Scope scope) {
not isParameterImpl(name, scope) and
exists(VarAccess va | va.getUserPath() = name and scope = va.getEnclosingScope())
} or
TParameter(ParameterImpl p)

private class AbstractVariable extends TVariable {
abstract Location getLocation();

string toString() { result = this.getName() }

abstract string getName();

abstract Scope getDeclaringScope();

VarAccess getAnAccess() {
exists(string s |
s = concat(this.getAQlClass(), ", ") and
// TODO: This won't join order nicely.
result.getUserPath() = this.getName() and
result.getEnclosingScope() = this.getDeclaringScope()
)
}
}

class LocalVariable extends AbstractVariable, TLocalVariable {
string name;
Scope scope;

LocalVariable() { this = TLocalVariable(name, scope) }

override Location getLocation() {
// The location is the first access (ordered by location) to the variable in the scope
exists(VarAccess va |
va =
min(VarAccess cand, Location location |
cand = this.getAnAccess() and location = cand.getLocation()
|
cand order by location.getStartLine(), location.getStartColumn()
) and
result = va.getLocation()
)
}

override string getName() { result = name }

final override Scope getDeclaringScope() { result = scope }
}

class Parameter extends AbstractVariable, TParameter {
ParameterImpl p;

Parameter() { this = TParameter(p) }

override Location getLocation() { result = p.getLocation() }

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

final override Scope getDeclaringScope() { result = p.getEnclosingScope() }

predicate hasParameterBlock(ParamBlock block, int i) { p.hasParameterBlock(block, i) }

predicate isFunctionParameter(Function f, int i) { p.isFunctionParameter(f, i) }

Expr getDefaultValue() { result = p.getDefaultValue() }

predicate hasDefaultValue() { exists(this.getDefaultValue()) }

int getIndex() { this.isFunctionParameter(_, result) }
}

final class Variable = AbstractVariable;
22 changes: 22 additions & 0 deletions powershell/ql/lib/semmle/code/powershell/VariableExpression.qll
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import powershell

private predicate isParameterName(@variable_expression ve) { parameter(_, ve, _, _) }

class VarAccess extends @variable_expression, Expr {
VarAccess() { not isParameterName(this) }

override string toString() { result = this.getUserPath() }

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

boolean isDriveQualified() { variable_expression(this, _, _, _, _, _, _, _, _, _, _, result) }

Variable getVariable() { result.getAnAccess() = this }
}

private predicate isVariableWriteAccess(Expr e) {
e = any(AssignStmt assign).getLeftHandSide()
or
e = any(ConvertExpr convert | isVariableWriteAccess(convert)).getExpr()
or
e = any(ArrayLiteral array | isVariableWriteAccess(array)).getAnElement()
}

class VarReadAccess extends VarAccess {
VarReadAccess() { not this instanceof VarWriteAccess }
}

class VarWriteAccess extends VarAccess {
VarWriteAccess() { isVariableWriteAccess(this) }
}
Loading