CertC-FLP30¶
Do not use floating-point variables as loop counters
Required inputs: IR
Because floating-point numbers represent real numbers, it is often mistakenly assumed that they can represent any simple fraction exactly. Floating-point numbers are subject to representational limitations just as integers are, and binary floating-point numbers cannot represent all real numbers exactly, even if they can be represented in a small number of decimal digits.
In addition, because floating-point numbers can represent large values, it is often mistakenly assumed that they can represent all significant digits of those values. To gain a large dynamic range, floating-point numbers maintain a fixed number of precision bits (also called the significand) and an exponent, which limit the number of significant digits they can represent.
Different implementations have different precision limitations, and to keep code portable, floating-point variables must not be used as the loop induction variable. See Goldberg's work for an introduction to this topic [ Goldberg 1991].
For the purpose of this rule, a loop counter is an induction
variable that is used as an operand of a comparison expression that is used as
the controlling expression of a
do,
while, or
for loop. An induction variable is a
variable that gets increased or decreased by a fixed amount on every iteration
of a loop [
Aho
1986]. Furthermore, the change to the variable must occur directly in the
loop body (rather than inside a function executed within the loop).
Noncompliant Code Example
In this noncompliant code example, a floating-point variable is used as a loop
counter. The decimal number
0.1 is a repeating fraction in binary and cannot be exactly
represented as a binary floating-point number. Depending on the implementation,
the loop may iterate 9 or 10 times.
void func(void) {
for (float x = 0.1f; x <= 1.0f; x += 0.1f) {
/* Loop may iterate 9 or 10 times */
}
}
For example, when compiled with GCC or Microsoft Visual Studio 2013 and executed on an x86 processor, the loop is evaluated only nine times.
Compliant Solution
In this compliant solution, the loop counter is an integer from which the floating-point value is derived:
#include <stddef.h>
void func(void) {
for (size_t count = 1; count <= 10; ++count) {
float x = count / 10.0f;
/* Loop iterates exactly 10 times */
}
}
Noncompliant Code Example
In this noncompliant code example, a floating-point loop counter is incremented by an amount that is too small to change its value given its precision:
void func(void) {
for (float x = 100000001.0f; x <= 100000010.0f; x += 1.0f) {
/* Loop may not terminate */
}
}
On many implementations, this produces an infinite loop.
Compliant Solution
In this compliant solution, the loop counter is an integer from which the
floating-point value is derived. The variable
x is assigned a computed value to reduce compounded rounding
errors that are present in the noncompliant code example.
void func(void) {
for (size_t count = 1; count <= 10; ++count) {
float x = 100000000.0f + (count * 1.0f);
/* Loop iterates exactly 10 times */
}
}
Risk Assessment
The use of floating-point variables as loop counters can result in unexpected behavior.
| Rule | Severity | Likelihood | Remediation Cost | Priority | Level |
|---|---|---|---|---|---|
| FLP30-C | Low | Probable | Low | P6 | L2 |
Related Guidelines
| Taxonomy | Taxonomy item | Relationship |
|---|---|---|
| CERT C | FLP30-CPP. Do not use floating-point variables as loop counters | Prior to 2018-01-12: CERT: Unspecified Relationship |
| CERT Oracle Secure Coding Standard for Java | NUM09-J. Do not use floating-point variables as loop counters | Prior to 2018-01-12: CERT: Unspecified Relationship |
| ISO/IEC TR 24772:2013 | Floating-Point Arithmetic [PLF] | Prior to 2018-01-12: CERT: Unspecified Relationship |
| MISRA C:2012 | Directive 1.1 (required) | Prior to 2018-01-12: CERT: Unspecified Relationship |
| MISRA C:2012 | Rule 14.1 (required) | Prior to 2018-01-12: CERT: Unspecified Relationship |
Bibliography
| [ Aho 1986] | |
| [ Goldberg 1991] | |
| [ Lockheed Martin 05] | AV Rule 197 |
Possible Messages
Key |
Text |
Severity |
Disabled |
|---|---|---|---|
float_loop_counter |
Use of floating-point loop counter. |
None |
False |
Options¶
This rule shares the following common options: exclude_in_macros, exclude_messages_in_system_headers, excludes, extend_exclude_to_macro_invocations, includes, justification_checker, languages, post_processing, provider, report_at, severity
The following places define options that affect this rule: Stylechecks, Analysis-GlobalOptions
loop_counter_model¶
loop_counter_model : LoopCounterModel = 'cert'
Option Types¶
These types are used by options listed above:
LoopCounterModel¶
An enumeration.misra_c_2004
misra_c_2004_continue
misra_c_2012
misra_c_2012_continue
misra_cpp_2008
cert
generic