-
Notifications
You must be signed in to change notification settings - Fork 2k
Expand file tree
/
Copy pathConstantCondition.ql
More file actions
121 lines (102 loc) · 3.56 KB
/
ConstantCondition.ql
File metadata and controls
121 lines (102 loc) · 3.56 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
/**
* @name Constant condition
* @description A condition that always evaluates to 'true' or always evaluates to 'false'
* should be removed, and if the condition is a loop condition, the condition
* is likely to cause an infinite loop.
* @kind problem
* @problem.severity warning
* @precision very-high
* @id cs/constant-condition
* @tags maintainability
* readability
* external/cwe/cwe-835
*/
import csharp
import semmle.code.csharp.commons.Assertions
import semmle.code.csharp.commons.Constants
/** A constant condition. */
abstract class ConstantCondition extends Expr {
/** Gets the alert message for this constant condition. */
abstract string getMessage();
/** Holds if this constant condition is white-listed. */
predicate isWhiteListed() { none() }
}
/** A constant Boolean condition. */
class ConstantBooleanCondition extends ConstantCondition {
boolean b;
ConstantBooleanCondition() { isConstantCondition(this, b) }
override string getMessage() { result = "Condition always evaluates to '" + b + "'." }
override predicate isWhiteListed() {
// E.g. `x ?? false`
this.(BoolLiteral) = any(NullCoalescingExpr nce).getRightOperand()
}
}
/** A constant condition in an `if` statement or a conditional expression. */
class ConstantIfCondition extends ConstantBooleanCondition {
ConstantIfCondition() {
this = any(IfStmt is).getCondition().getAChildExpr*() or
this = any(ConditionalExpr ce).getCondition().getAChildExpr*()
}
override predicate isWhiteListed() {
ConstantBooleanCondition.super.isWhiteListed()
or
// It is a common pattern to use a local constant/constant field to control
// whether code parts must be executed or not
this instanceof AssignableRead
}
}
/** A constant loop condition. */
class ConstantLoopCondition extends ConstantBooleanCondition {
ConstantLoopCondition() { this = any(LoopStmt ls).getCondition() }
override predicate isWhiteListed() {
// Clearly intentional infinite loops are allowed
this.(BoolLiteral).getBoolValue() = true
}
}
/** A constant nullness condition. */
class ConstantNullnessCondition extends ConstantCondition {
boolean b;
ConstantNullnessCondition() {
forex(ControlFlow::Node cfn | cfn = this.getAControlFlowNode() |
exists(ControlFlow::SuccessorTypes::NullnessSuccessor t, ControlFlow::Node s |
s = cfn.getASuccessorByType(t)
|
b = t.getValue() and
not s.isJoin()
) and
strictcount(ControlFlow::SuccessorType t | exists(cfn.getASuccessorByType(t))) = 1
)
}
override string getMessage() {
if b = true
then result = "Expression is always 'null'."
else result = "Expression is never 'null'."
}
}
/** A constant matching condition. */
class ConstantMatchingCondition extends ConstantCondition {
boolean b;
ConstantMatchingCondition() {
forex(ControlFlow::Node cfn | cfn = this.getAControlFlowNode() |
exists(ControlFlow::SuccessorTypes::MatchingSuccessor t | exists(cfn.getASuccessorByType(t)) |
b = t.getValue()
) and
strictcount(ControlFlow::SuccessorType t | exists(cfn.getASuccessorByType(t))) = 1
)
}
override predicate isWhiteListed() {
exists(SwitchExpr se, int i |
se.getCase(i).getPattern() = this.(DiscardExpr) and
i > 0
)
}
override string getMessage() {
if b = true then result = "Pattern always matches." else result = "Pattern never matches."
}
}
from ConstantCondition c, string msg
where
msg = c.getMessage() and
not c.isWhiteListed() and
not isExprInAssertion(c)
select c, msg