Skip to content

Commit 1f432dc

Browse files
authored
Merge pull request github#4023 from geoffw0/loopdir
C++: Exclude decrementing unsigned counters from inconsistentLoopDirection.ql
2 parents 7c4e10d + 3cf11ec commit 1f432dc

File tree

4 files changed

+68
-2
lines changed

4 files changed

+68
-2
lines changed

change-notes/1.26/analysis-cpp.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
# Improvements to C/C++ analysis
2+
3+
The following changes in version 1.26 affect C/C++ analysis in all applications.
4+
5+
## General improvements
6+
7+
## New queries
8+
9+
| **Query** | **Tags** | **Purpose** |
10+
|-----------------------------|-----------|--------------------------------------------------------------------|
11+
12+
## Changes to existing queries
13+
14+
| **Query** | **Expected impact** | **Change** |
15+
|----------------------------|------------------------|------------------------------------------------------------------|
16+
| Inconsistent direction of for loop (`cpp/inconsistent-loop-direction`) | Fewer false positive results | The query now accounts for intentional wrapping of an unsigned loop counter. |
17+
18+
## Changes to libraries
19+

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

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,12 @@ predicate illDefinedDecrForStmt(
5050
DataFlow::localFlowStep(DataFlow::exprNode(initialCondition), DataFlow::exprNode(lesserOperand)) and
5151
// `initialCondition` < `terminalCondition`
5252
(
53-
upperBound(initialCondition) < lowerBound(terminalCondition)
53+
upperBound(initialCondition) < lowerBound(terminalCondition) and
54+
(
55+
// exclude cases where the loop counter is `unsigned` (where wrapping behaviour can be used deliberately)
56+
v.getUnspecifiedType().(IntegralType).isSigned() or
57+
initialCondition.getValue().toInt() = 0
58+
)
5459
or
5560
(forstmt.conditionAlwaysFalse() or forstmt.conditionAlwaysTrue())
5661
)

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

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,4 +177,43 @@ void FalseNegativeTestCases()
177177
for (int i = 100; i > 0; i += 2) {}
178178
// For comparison
179179
for (int i = 100; i > 0; i ++ ) {} // BUG
180-
}
180+
}
181+
182+
void IntendedOverflow(unsigned char p)
183+
{
184+
const unsigned char m = 10;
185+
unsigned char i;
186+
signed char s;
187+
188+
for (i = 63; i < 64; i--) {} // GOOD (legitimate way to count down with an unsigned)
189+
for (i = 63; i < 128; i--) {} // DUBIOUS (could still be a typo?)
190+
for (i = 63; i < 255; i--) {} // GOOD
191+
192+
for (i = m - 1; i < m; i--) {} // GOOD
193+
for (i = m - 2; i < m; i--) {} // DUBIOUS
194+
for (i = m; i < m + 1; i--) {} // GOOD
195+
196+
for (s = 63; s < 64; s--) {} // BAD (signed numbers don't wrap at 0 / at all)
197+
for (s = m + 1; s < m; s--) {} // BAD (never runs)
198+
199+
for (i = p - 1; i < p; i--) {} // GOOD
200+
for (s = p - 1; s < p; s--) {} // BAD [NOT DETECTED]
201+
202+
{
203+
int n;
204+
205+
n = 64;
206+
for (i = n - 1; i < n; i--) {} // GOOD
207+
n = 64;
208+
for (i = n - 1; i < 64; i--) {} // GOOD
209+
n = 64;
210+
for (i = 63; i < n; i--) {} // GOOD
211+
212+
n = 64;
213+
for (s = n - 1; s < n; s--) {} // BAD [NOT DETECTED]
214+
n = 64;
215+
for (s = n - 1; s < 64; s--) {} // BAD
216+
n = 64;
217+
for (s = 63; s < n; s--) {} // BAD [NOT DETECTED]
218+
}
219+
}

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,3 +20,6 @@
2020
| inconsistentLoopDirection.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). |
2121
| inconsistentLoopDirection.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). |
2222
| inconsistentLoopDirection.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). |
23+
| inconsistentLoopDirection.cpp:196:5:196:32 | for(...;...;...) ... | Ill-defined for-loop: a loop using variable "s" counts downward from a value (63), but the terminal condition is higher (64). |
24+
| inconsistentLoopDirection.cpp:197:5:197:34 | for(...;...;...) ... | Ill-defined for-loop: a loop using variable "s" counts downward from a value (... + ...), but the terminal condition is always false. |
25+
| inconsistentLoopDirection.cpp:215:3:215:33 | for(...;...;...) ... | Ill-defined for-loop: a loop using variable "s" counts downward from a value (... - ...), but the terminal condition is higher (64). |

0 commit comments

Comments
 (0)