Skip to content

Commit e2fcaa9

Browse files
Fixing typos & implementing the PR feedback
1 parent ce99f46 commit e2fcaa9

File tree

5 files changed

+116
-43
lines changed

5 files changed

+116
-43
lines changed

.gitignore

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,6 @@
1313
/.vs/ql/v15/Browse.VC.db
1414
/.vs/ProjectSettings.json
1515

16+
/.vs/ql_6293a/v15/Browse.VC.opendb
17+
/.vs/ql_6293a/v15/Browse.VC.db
18+
/.vs/ql_6293a/v15/.suo

cpp/ql/src/Likely Bugs/Likely Typos/illDefinedForLoop.qhelp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
</overview>
1010

1111
<recommendation>
12-
<p>Verify the iteration expression on the <code>for-loop</code> and make sure the direction of the iteration expression is correct.</p>
12+
<p>To fix this issue, check that the loop condition is correct and change the iteration expression to match.</p>
1313
</recommendation>
1414

1515
<example>

cpp/ql/src/Likely Bugs/Likely Typos/illDefinedForLoop.ql

Lines changed: 46 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -10,58 +10,56 @@
1010
*/
1111
import cpp
1212
import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
13+
import semmle.code.cpp.dataflow.DataFlow
1314

1415
predicate illDefinedDecrForStmt( ForStmt forstmt, Variable v, Expr initialCondition, Expr terminalCondition ) {
15-
v.getAnAssignedValue() = initialCondition
16+
v.getAnAssignedValue() = initialCondition
1617
and
1718
exists(
18-
RelationalOperation rel, Expr e |
19+
RelationalOperation rel |
1920
rel = forstmt.getCondition() |
20-
e = rel.getGreaterOperand()
21+
terminalCondition = rel.getGreaterOperand()
2122
and v.getAnAccess() = rel.getLesserOperand()
22-
and terminalCondition = e
23-
)
24-
and
25-
(
26-
exists(
27-
PostfixDecrExpr pdec |
28-
pdec = forstmt.getUpdate().(PostfixDecrExpr)
29-
and pdec.getAnOperand() = v.getAnAccess()
30-
) or
31-
exists(
32-
PrefixDecrExpr pdec |
33-
pdec = forstmt.getUpdate().(PrefixDecrExpr)
34-
and pdec.getAnOperand() = v.getAnAccess()
23+
and
24+
DataFlow::localFlowStep(DataFlow::exprNode(initialCondition), DataFlow::exprNode(rel.getLesserOperand()))
3525
)
26+
and
27+
exists(
28+
DecrementOperation dec |
29+
dec = forstmt.getUpdate().(DecrementOperation)
30+
and dec.getAnOperand() = v.getAnAccess()
3631
)
3732
and
38-
upperBound(initialCondition) < lowerBound(terminalCondition)
33+
(
34+
( upperBound(initialCondition) < lowerBound(terminalCondition) )
35+
or
36+
( forstmt.conditionAlwaysFalse() or forstmt.conditionAlwaysTrue() )
37+
)
3938
}
4039

4140
predicate illDefinedIncrForStmt( ForStmt forstmt, Variable v, Expr initialCondition, Expr terminalCondition ) {
4241
v.getAnAssignedValue() = initialCondition
4342
and
4443
exists(
45-
RelationalOperation rel, Expr e |
44+
RelationalOperation rel |
4645
rel = forstmt.getCondition() |
47-
e = rel.getLesserOperand()
46+
terminalCondition = rel.getLesserOperand()
4847
and v.getAnAccess() = rel.getGreaterOperand()
49-
and terminalCondition = e
48+
and
49+
DataFlow::localFlowStep(DataFlow::exprNode(initialCondition), DataFlow::exprNode(rel.getGreaterOperand()))
5050
)
5151
and
52-
( exists( PostfixIncrExpr pincr |
53-
pincr = forstmt.getUpdate().(PostfixIncrExpr)
54-
and
55-
pincr.getAnOperand() = v.getAnAccess()
56-
) or
57-
exists( PrefixIncrExpr pincr |
58-
pincr = forstmt.getUpdate().(PrefixIncrExpr)
59-
and
60-
pincr.getAnOperand() = v.getAnAccess()
61-
)
52+
exists( IncrementOperation incr |
53+
incr = forstmt.getUpdate().(IncrementOperation)
54+
and
55+
incr.getAnOperand() = v.getAnAccess()
6256
)
6357
and
64-
upperBound(terminalCondition) < lowerBound(initialCondition)
58+
(
59+
( upperBound(terminalCondition) < lowerBound(initialCondition))
60+
or
61+
( forstmt.conditionAlwaysFalse() or forstmt.conditionAlwaysTrue())
62+
)
6563
}
6664

6765
predicate illDefinedForStmtWrongDirection( ForStmt forstmt, Variable v, Expr initialCondition, Expr terminalCondition
@@ -91,9 +89,23 @@ private string forLoopTerminalConditionRelationship(boolean b){
9189
Expr terminalCondition |
9290
illDefinedForStmtWrongDirection(for, v, initialCondition, terminalCondition, isIncr)
9391
and
94-
message = "Ill-defined for-loop: a loop using variable \"" + v + "\" counts "
95-
+ forLoopdirection(isIncr) + " from a value ("+ initialCondition +"), but the terminal condition is "
96-
+ forLoopTerminalConditionRelationship(isIncr) + " (" + terminalCondition + ")."
92+
if( for.conditionAlwaysFalse() ) then
93+
(
94+
message = "Ill-defined for-loop: a loop using variable \"" + v + "\" counts "
95+
+ forLoopdirection(isIncr) + " from a value ("+ initialCondition +"), but the terminal condition is always false."
96+
)
97+
else if
98+
(
99+
for.conditionAlwaysTrue() ) then (
100+
message = "Ill-defined for-loop: a loop using variable \"" + v + "\" counts "
101+
+ forLoopdirection(isIncr) + " from a value ("+ initialCondition +"), but the terminal condition is always true."
102+
)
103+
else
104+
(
105+
message = "Ill-defined for-loop: a loop using variable \"" + v + "\" counts "
106+
+ forLoopdirection(isIncr) + " from a value ("+ initialCondition +"), but the terminal condition is "
107+
+ forLoopTerminalConditionRelationship(isIncr) + " (" + terminalCondition + ")."
108+
)
97109
)
98110
}
99111

cpp/ql/test/query-tests/Likely Bugs/Likely Typos/illDefinedForLoop/illDefinedForLoop.cpp

Lines changed: 60 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -43,19 +43,19 @@ void Unsigned()
4343

4444
void DeclarationInLoop()
4545
{
46-
for (signed char i = 0; i < 100; i--) //BUG
46+
for (signed char i = 0; i < 100; --i) //BUG
4747
{
4848
}
4949

50-
for (signed char i = 0; i < 100; i++)
50+
for (signed char i = 0; i < 100; ++i)
5151
{
5252
}
5353

54-
for (unsigned char i = 100; i >= 0; i++) //BUG
54+
for (unsigned char i = 100; i >= 0; ++i) //BUG
5555
{
5656
}
5757

58-
for (unsigned char i = 100; i >= 0; i--)
58+
for (unsigned char i = 100; i >= 0; --i)
5959
{
6060
}
6161
}
@@ -88,22 +88,56 @@ void InitializationOutsideLoop()
8888
{
8989
signed char i = 0;
9090

91-
for (; i < 100; i--) //BUG
91+
for (; i < 100; --i) //BUG
9292
{
9393
}
9494

9595
i = 0;
96-
for (; i < 100; i++)
96+
for (; i < 100; ++i)
9797
{
9898
}
9999

100100
i = 100;
101-
for (; i >= 0; i++) //BUG
101+
for (; i >= 0; ++i) //BUG
102102
{
103103
}
104104

105105
i = 100;
106-
for (; i >= 0; i--)
106+
for (; i >= 0; --i)
107+
{
108+
}
109+
}
110+
111+
112+
void InvalidCondition()
113+
{
114+
signed char i;
115+
signed char min = 0;
116+
signed char max = 100;
117+
118+
for (i = max; i < min; i--) //BUG
119+
{
120+
}
121+
122+
for (i = min; i > max; i++) //BUG
123+
{
124+
}
125+
}
126+
127+
void InvalidConditionUnsignedCornerCase()
128+
{
129+
unsigned char i;
130+
unsigned char min = 0;
131+
unsigned char max = 100;
132+
133+
for (i = 100; i < 0; i--) //BUG
134+
{
135+
}
136+
137+
// Limitation.
138+
// Currently odasa will not detect this for-loop condition as always true
139+
// The rule will still detect the mismatch iterator, but the error message may change in the future.
140+
for (i = 200; i >= 0; i++) //BUG
107141
{
108142
}
109143
}
@@ -126,3 +160,21 @@ void NegativeTestCaseNested()
126160
}
127161
}
128162
}
163+
164+
//////////////////////////////////////
165+
// Query limitation:
166+
//
167+
// The following test cases are bugs,
168+
// but will not be found due to the itearion expression
169+
// not being a prefix or postfix increment/decrement
170+
//
171+
void FalseNegativeTestCases()
172+
{
173+
for (int i = 0; i < 10; i = i - 1) {}
174+
// For comparison
175+
for (int i = 0; i < 10; i-- ) {} // BUG
176+
177+
for (int i = 100; i > 0; i += 2) {}
178+
// For comparison
179+
for (int i = 100; i > 0; i ++ ) {} // BUG
180+
}

cpp/ql/test/query-tests/Likely Bugs/Likely Typos/illDefinedForLoop/illDefinedForLoop.expected

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,3 +14,9 @@
1414
| illDefinedForLoop.cpp:77:5:79:5 | for(...;...;...) ... | Ill-defined for-loop: a loop using variable "i" counts upward from a value (max), but the terminal condition is lower (min). |
1515
| illDefinedForLoop.cpp:91:5:93:5 | for(...;...;...) ... | Ill-defined for-loop: a loop using variable "i" counts downward from a value (0), but the terminal condition is higher (100). |
1616
| illDefinedForLoop.cpp:101:5:103:5 | for(...;...;...) ... | Ill-defined for-loop: a loop using variable "i" counts upward from a value (100), but the terminal condition is lower (0). |
17+
| illDefinedForLoop.cpp:118:5:120:5 | for(...;...;...) ... | Ill-defined for-loop: a loop using variable "i" counts downward from a value (max), but the terminal condition is always false. |
18+
| illDefinedForLoop.cpp:122:5:124:5 | for(...;...;...) ... | Ill-defined for-loop: a loop using variable "i" counts upward from a value (min), but the terminal condition is always false. |
19+
| illDefinedForLoop.cpp:133:5:135:5 | for(...;...;...) ... | Ill-defined for-loop: a loop using variable "i" counts downward from a value (100), but the terminal condition is always false. |
20+
| illDefinedForLoop.cpp:140:5:142:5 | for(...;...;...) ... | Ill-defined for-loop: a loop using variable "i" counts upward from a value (200), but the terminal condition is lower (0). |
21+
| illDefinedForLoop.cpp:175:5:175:36 | for(...;...;...) ... | Ill-defined for-loop: a loop using variable "i" counts downward from a value (0), but the terminal condition is higher (10). |
22+
| illDefinedForLoop.cpp:179:5:179:38 | for(...;...;...) ... | Ill-defined for-loop: a loop using variable "i" counts upward from a value (100), but the terminal condition is lower (0). |

0 commit comments

Comments
 (0)