Skip to content

Commit 129b787

Browse files
committed
PS: Allow shadowing of automatic variables.
1 parent 08dc818 commit 129b787

File tree

3 files changed

+59
-5
lines changed

3 files changed

+59
-5
lines changed

powershell/ql/lib/semmle/code/powershell/ast/internal/Raw/VariableExpression.qll

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,10 @@ class VarAccess extends @variable_expression, Expr {
2424
boolean isVariable() { variable_expression(this, _, _, _, _, _, _, _, _, _, result, _) }
2525

2626
boolean isDriveQualified() { variable_expression(this, _, _, _, _, _, _, _, _, _, _, result) }
27+
28+
predicate isReadAccess() { not this.isWriteAccess() }
29+
30+
predicate isWriteAccess() { any(AssignStmt assign).getLeftHandSide() = this }
2731
}
2832

2933
class ThisAccess extends VarAccess {

powershell/ql/lib/semmle/code/powershell/ast/internal/Synthesis.qll

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -587,6 +587,57 @@ private module CmdArguments {
587587
* Synthesize literals from known constant strings.
588588
*/
589589
private module LiteralSynth {
590+
pragma[nomagic]
591+
private predicate assignmentHasLocation(
592+
Raw::Scope scope, string name, File file, int startLine, int startColumn
593+
) {
594+
Raw::isAutomaticVariableAccess(_, name) and
595+
exists(Raw::Ast n, Location loc |
596+
scopeAssigns(scope, name, n) and
597+
loc = n.getLocation() and
598+
file = loc.getFile() and
599+
startLine = loc.getStartLine() and
600+
startColumn = loc.getStartColumn()
601+
)
602+
}
603+
604+
pragma[nomagic]
605+
private predicate varAccessHasLocation(
606+
Raw::VarAccess va, File file, int startLine, int startColumn
607+
) {
608+
exists(Location loc |
609+
loc = va.getLocation() and
610+
loc.getFile() = file and
611+
loc.getStartLine() = startLine and
612+
loc.getStartColumn() = startColumn
613+
)
614+
}
615+
616+
/**
617+
* Holds if `va` is an access to the automatic variable named `name`.
618+
*
619+
* Unlike `Raw::isAutomaticVariableAccess`, this predicate also checks for
620+
* shadowing.
621+
*/
622+
private predicate isAutomaticVariableAccess(Raw::VarAccess va, string name) {
623+
Raw::isAutomaticVariableAccess(va, name) and
624+
exists(Raw::Scope scope, File file, int startLine, int startColumn |
625+
scope = Raw::scopeOf(va) and
626+
varAccessHasLocation(va, file, startLine, startColumn)
627+
|
628+
// If it's a read then make sure there is no assignment precedeeding it
629+
va.isReadAccess() and
630+
not exists(int assignStartLine, int assignStartCoumn |
631+
assignmentHasLocation(scope, name, file, assignStartLine, assignStartCoumn)
632+
|
633+
assignStartLine < startLine
634+
or
635+
assignStartLine = startLine and
636+
assignStartCoumn < startColumn
637+
)
638+
)
639+
}
640+
590641
private class LiteralSynth extends Synthesis {
591642
final override predicate isRelevant(Raw::Ast a) {
592643
exists(Raw::VarAccess va | a = va |
@@ -598,7 +649,7 @@ private module LiteralSynth {
598649
or
599650
Raw::isEnvVariableAccess(va, _)
600651
or
601-
Raw::isAutomaticVariableAccess(va, _)
652+
isAutomaticVariableAccess(va, _)
602653
)
603654
}
604655

@@ -628,7 +679,7 @@ private module LiteralSynth {
628679
Raw::isEnvVariableAccess(va, s) and
629680
child = SynthChild(EnvVariableKind(s))
630681
or
631-
Raw::isAutomaticVariableAccess(va, s) and
682+
isAutomaticVariableAccess(va, s) and
632683
child = SynthChild(AutomaticVariableKind(s))
633684
)
634685
}

powershell/ql/lib/semmle/code/powershell/ast/internal/TAst.qll

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,16 +17,15 @@ string variableNameInScope(Raw::Ast n, Scope::Range scope) {
1717
not scope.getAParameter().(Raw::PipelineByPropertyNameParameter).getName() = result and
1818
not result.toLowerCase() = ["_", "this", "false", "true", "null"] and
1919
not parameter(_, n, _, _) and
20-
not Raw::isEnvVariableAccess(n, _) and
21-
not Raw::isAutomaticVariableAccess(n, _)
20+
not Raw::isEnvVariableAccess(n, _)
2221
or
2322
any(Synthesis s).explicitAssignment(n, result, _)
2423
or
2524
any(Synthesis s).implicitAssignment(n, result)
2625
)
2726
}
2827

29-
private predicate scopeAssigns(Scope::Range scope, string name, Raw::Ast n) {
28+
predicate scopeAssigns(Scope::Range scope, string name, Raw::Ast n) {
3029
(explicitAssignment(n, _) or implicitAssignment(n)) and
3130
name = variableNameInScope(n, scope)
3231
}

0 commit comments

Comments
 (0)