C defines <
, >
, <=
, and >=
to be relational operators, and it defines ==
and !=
to be equality operators.
If a for
or while
statement uses a loop counter, than it is safer to use a relational operator (such as <
) to terminate the loop than to use an equality operator (such as !=
).
Noncompliant Code Example (Equality Operators)
This noncompliant code example appears to have five iterations, but in fact, the loop never terminates:
size_t i; for (i = 1; i != 10; i += 2) { /* ... */ }
Compliant Solution (Relational Operators)
Using the relational operator <=
instead of an equality operator guarantees loop termination:
size_t i; for (i = 1; i <= 10; i += 2 ) { /* ... */ }
Noncompliant Code Example (Equality Operators)
It is also important to ensure termination of loops where the start and end values are variables that might not be properly ordered. The following function assumes that begin < end
; if this is not the case, the loop will never terminate:
void f(size_t begin, size_t end) { size_t i; for (i = begin; i != end; ++i) { /* ... */ } }
Compliant Solution (Relational Operators)
Again, using a relational operator instead of equivalence guarantees loop termination. If begin >= end
, the loop never executes its body.
void f(size_t begin, size_t end) { size_t i; for (i = begin; i < end; ++i) { /* ... */ } }
Noncompliant Code Example (Boundary Conditions)
Numerical comparison operators do not always ensure loop termination when comparing against the minimum or maximum representable value of a type, such as SIZE_MAX
:
void f(size_t begin, size_t step) { size_t i; for (i = begin; i <= SIZE_MAX; i += step) { /* ... */ } }
Compliant Solution (Boundary Conditions)
A compliant solution is to compare against the difference between the maximum representable value of a type and the increment:
void f(size_t begin, size_t step) { if (0 < step) { int i; for (i = begin; i <= INT_MAX - step; i += step) { /* ... */ } } }
Exceptions
MSC21-C-EX1: If the loop counter is incremented by 1 on each iteration, and it is known that the starting value of a loop is less than or equal to the ending value, then an equality operator may be used to terminate the loop. Likewise, if the loop counter is decremented by 1 on each iteration, and it is known that the starting value of the loop is greater than or equal to the ending value, then an equality operator may be used to terminate the loop.
size_t i; for (i = 1; i != 5; ++i) { /* ... */ }
Risk Assessment
Testing for exact values runs the risk of a loop terminating much longer than expected or never terminating at all.
Recommendation | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
MSC21-C | Low | Unlikely | Low | P3 | L3 |
Automated Detection
Tool | Version | Checker | Description |
---|---|---|---|
Astrée | 19.04 | Supported: Astrée reports potential infinite loops. | |
CodeSonar | 5.1p0 | LANG.STRUCT.LOOP.HR | High risk loop |
Compass/ROSE | |||
LDRA tool suite | 9.7.1 | 510 S | Partially implemented |
Polyspace Bug Finder | R2019a | Checks for loop bounded with tainted value (rec. partially covered) | |
PVS-Studio | 6.23 | V621 |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
11 Comments
Martin Sebor
A related problem I've seen is in cases where the controlling expression of a loop assumes the lower bound of the loop is less than or equal to the upper bound but where this assumtion doesn't hold.
The solution in such cases is also to use a relational operator rather than inequality, regardless of the increment:
David Svoboda
Good point. I added your NCCE/CS code samples to the rule.
Dhruv Mohindra
In the last CS there is a formatting problem - < instead of <.
Another problem can arise when comparing with INT_MAX, and having a step size more than 1. For example, see the last NCE in the corresponding Java guideline MSC54-J. Avoid inadvertent wrapping of loop counters.
Martin Sebor
Fixed/added, thanks!
Masaki Kubo
There seems to be some confusion between "inequality" and "equality-expression"
"a != b" is one of the equality expressions in C.
"a < b" is an inequality statement in math and relational expression in C.
So the first "Noncompliant Code Example (inequality)" should be corrected to "Noncompliant Code Example (equality !=)" for example?
David Svoboda
I s/inequality/equivalence/g for this rule. Inequality can mean either != or < > <= => in English.
Martin Sebor
C doesn't define or use the term equivalence. For clarity I think we should stay with the standard (as in ISO/IEC 9899) terminology:
==
and!=
(i.e., the inequality operator)<
,>
,<=
, and>=
.Robert Seacord (Manager)
I was thinking the same thing.
David Svoboda
That's fine, but we should then define the terms we are using, since inequality has two meanings in mathematics, and, unless you're intimately familiar with the C standard, you don't know that they ignore one of the meanings.
Eduardo Silva
Having an education strong in algebra, where "inequalities" are often formulas like a <= b, I was *very* confused when I read the title of this recommendation and saw the example. I beg for a change on the title, like "Use robust loop termination conditions". English is not my mother tongue, though.
David Svoboda
Changed the title.
The rule still uses the terminology of the C standard, which can confuse a mathematician, so the intro now also defines the terminology used.