Skip to content

Commit cfe0b88

Browse files
authored
Merge pull request #332 from raulgarciamsft/users/raulga/c6293a
Approved by dave-bartolomeo
2 parents 292189c + e1efcb0 commit cfe0b88

File tree

7 files changed

+442
-0
lines changed

7 files changed

+442
-0
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
void f()
2+
{
3+
for (signed char i = 0; i < 100; i--)
4+
{
5+
// code ...
6+
}
7+
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<!DOCTYPE qhelp PUBLIC
2+
"-//Semmle//qhelp//EN"
3+
"qhelp.dtd">
4+
<qhelp>
5+
6+
<overview>
7+
<p>A <code>for-loop</code> iteration expression goes backwards with respect of the initialization statement and condition expression.</p>
8+
<p>This warning indicates that a <code>for-loop</code> might not function as intended.</p>
9+
</overview>
10+
11+
<recommendation>
12+
<p>To fix this issue, check that the loop condition is correct and change the iteration expression to match.</p>
13+
</recommendation>
14+
15+
<example>
16+
<p>In the following example, the initialization statement (<code>i = 0</code>) and the condition expression (<code>i &lt; 100</code>) indicate that the intended iteration expression should have been incrementing, but instead a postfix decrement operator is used (<code>i--</code>).</p>
17+
<sample src="inconsistentLoopDirection.c" />
18+
19+
<p>To fix this issue, change the iteration expression to match the direction of the initialization statement and the condition expression: <code>i++</code>.</p>
20+
</example>
21+
22+
<references>
23+
<li><a href="https://docs.microsoft.com/en-us/previous-versions/visualstudio/visual-studio-2012/58teb7hd(v=vs.110)">warning C6293: Ill-defined for-loop: counts down from minimum</a>
24+
</li>
25+
</references>
26+
27+
</qhelp>
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
/**
2+
* @name Inconsistent direction of for loop
3+
* @description A for-loop iteration expression goes backward with respect of the initialization statement and condition expression.
4+
* @kind problem
5+
* @problem.severity error
6+
* @precision high
7+
* @id cpp/inconsistent-loop-direction
8+
* @tags correctness
9+
* external/cwe/cwe-835
10+
* external/microsoft/6293
11+
* @msrc.severity important
12+
*/
13+
import cpp
14+
import semmle.code.cpp.rangeanalysis.SimpleRangeAnalysis
15+
import semmle.code.cpp.dataflow.DataFlow
16+
17+
predicate illDefinedDecrForStmt( ForStmt forstmt, Variable v, Expr initialCondition, Expr terminalCondition ) {
18+
v.getAnAssignedValue() = initialCondition
19+
and
20+
exists(
21+
RelationalOperation rel |
22+
rel = forstmt.getCondition() |
23+
terminalCondition = rel.getGreaterOperand()
24+
and v.getAnAccess() = rel.getLesserOperand()
25+
and
26+
DataFlow::localFlowStep(DataFlow::exprNode(initialCondition), DataFlow::exprNode(rel.getLesserOperand()))
27+
)
28+
and
29+
exists(
30+
DecrementOperation dec |
31+
dec = forstmt.getUpdate().(DecrementOperation)
32+
and dec.getAnOperand() = v.getAnAccess()
33+
)
34+
and
35+
(
36+
( upperBound(initialCondition) < lowerBound(terminalCondition) )
37+
or
38+
( forstmt.conditionAlwaysFalse() or forstmt.conditionAlwaysTrue() )
39+
)
40+
}
41+
42+
predicate illDefinedIncrForStmt( ForStmt forstmt, Variable v, Expr initialCondition, Expr terminalCondition ) {
43+
v.getAnAssignedValue() = initialCondition
44+
and
45+
exists(
46+
RelationalOperation rel |
47+
rel = forstmt.getCondition() |
48+
terminalCondition = rel.getLesserOperand()
49+
and v.getAnAccess() = rel.getGreaterOperand()
50+
and
51+
DataFlow::localFlowStep(DataFlow::exprNode(initialCondition), DataFlow::exprNode(rel.getGreaterOperand()))
52+
)
53+
and
54+
exists( IncrementOperation incr |
55+
incr = forstmt.getUpdate().(IncrementOperation)
56+
and
57+
incr.getAnOperand() = v.getAnAccess()
58+
)
59+
and
60+
(
61+
( upperBound(terminalCondition) < lowerBound(initialCondition))
62+
or
63+
( forstmt.conditionAlwaysFalse() or forstmt.conditionAlwaysTrue())
64+
)
65+
}
66+
67+
predicate illDefinedForStmtWrongDirection( ForStmt forstmt, Variable v, Expr initialCondition, Expr terminalCondition
68+
, boolean isIncr ) {
69+
( illDefinedDecrForStmt( forstmt, v, initialCondition, terminalCondition) and isIncr = false )
70+
or
71+
( illDefinedIncrForStmt( forstmt, v, initialCondition, terminalCondition) and isIncr = true)
72+
}
73+
74+
bindingset[b]
75+
private string forLoopdirection(boolean b){
76+
if( b = true ) then result = "upward"
77+
else result = "downward"
78+
}
79+
80+
bindingset[b]
81+
private string forLoopTerminalConditionRelationship(boolean b){
82+
if( b = true ) then result = "lower"
83+
else result = "higher"
84+
}
85+
86+
predicate illDefinedForStmt( ForStmt for, string message ) {
87+
exists(
88+
boolean isIncr,
89+
Variable v,
90+
Expr initialCondition,
91+
Expr terminalCondition |
92+
illDefinedForStmtWrongDirection(for, v, initialCondition, terminalCondition, isIncr)
93+
and
94+
if( for.conditionAlwaysFalse() ) then
95+
(
96+
message = "Ill-defined for-loop: a loop using variable \"" + v + "\" counts "
97+
+ forLoopdirection(isIncr) + " from a value ("+ initialCondition +"), but the terminal condition is always false."
98+
)
99+
else if
100+
(
101+
for.conditionAlwaysTrue() ) then (
102+
message = "Ill-defined for-loop: a loop using variable \"" + v + "\" counts "
103+
+ forLoopdirection(isIncr) + " from a value ("+ initialCondition +"), but the terminal condition is always true."
104+
)
105+
else
106+
(
107+
message = "Ill-defined for-loop: a loop using variable \"" + v + "\" counts "
108+
+ forLoopdirection(isIncr) + " from a value ("+ initialCondition +"), but the terminal condition is "
109+
+ forLoopTerminalConditionRelationship(isIncr) + " (" + terminalCondition + ")."
110+
)
111+
)
112+
}
113+
114+
from ForStmt forstmt, string message
115+
where illDefinedForStmt(forstmt, message)
116+
select forstmt, message
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
void Signed()
2+
{
3+
signed char i;
4+
5+
for (i = 0; i < 100; i--) //BUG
6+
{
7+
}
8+
9+
for (i = 0; i < 100; i++)
10+
{
11+
}
12+
13+
for (i = 100; i >= 0; i++) //BUG
14+
{
15+
}
16+
17+
for (i = 100; i >= 0; i--)
18+
{
19+
}
20+
21+
}
22+
23+
void Unsigned()
24+
{
25+
unsigned long i;
26+
27+
for (i = 0; i < 100; i--) //BUG
28+
{
29+
}
30+
31+
for (i = 0; i < 100; i++)
32+
{
33+
}
34+
35+
for (i = 100; i >= 0; i++) //BUG
36+
{
37+
}
38+
39+
for (i = 100; i >= 0; i--)
40+
{
41+
}
42+
}
43+
44+
void InitializationOutsideLoop()
45+
{
46+
signed char i = 0;
47+
48+
for (; i < 100; i--) //BUG
49+
{
50+
}
51+
52+
i = 0;
53+
for (; i < 100; i++)
54+
{
55+
}
56+
57+
i = 100;
58+
for (; i >= 0; i++) //BUG
59+
{
60+
}
61+
62+
i = 100;
63+
for (; i >= 0; i--)
64+
{
65+
}
66+
}
67+
68+
void NegativeTestCase()
69+
{
70+
int i;
71+
for (i = 0; (200 - i) < 100; i--)
72+
{
73+
// code ...
74+
}
75+
}
76+
77+
void NegativeTestCaseNested()
78+
{
79+
int k;
80+
int i;
81+
82+
for (k = 200; k < 300; k++)
83+
{
84+
for (i = 0; (k - i) < 100; i--)
85+
{
86+
// code ...
87+
}
88+
}
89+
}

0 commit comments

Comments
 (0)