CertC-FLP06¶
Convert integers to floating point for floating-point operations
Required inputs: IR
Using integer arithmetic to calculate a value for assignment to a floating-point variable may lead to loss of information. This problem can be avoided by converting one of the integers in the expression to a floating type.
When converting integers to floating-point values, and vice versa, it is important to carry out proper range checks to avoid undefined behavior (see FLP34-C. Ensure that floating-point conversions are within range of the new type).
Noncompliant Code Example
In this noncompliant code example, the division and multiplication operations
take place on integers and are then converted to floating
point. Consequently, floating-point variables
d,
e, and
f are not initialized correctly because the operations take
place before the values are converted to floating-point values. The results are
truncated to the nearest integer or may overflow.
void func(void) {
short a = 533;
int b = 6789;
long c = 466438237;
float d = a / 7; /* d is 76.0 */
double e = b / 30; /* e is 226.0 */
double f = c * 789; /* f may be negative due to overflow */
}
Compliant Solution (Floating-Point Literal)
In this compliant solution, the decimal error in initialization is eliminated by ensuring that at least one of the operands to the division operation is floating point:
void func(void) {
short a = 533;
int b = 6789;
long c = 466438237;
float d = a / 7.0f; /* d is 76.14286 */
double e = b / 30.; /* e is 226.3 */
double f = (double)c * 789; /* f is 368019768993.0 */
}
Compliant Solution (Conversion)
In this compliant solution, the decimal error in initialization is eliminated by first storing the integer in the floating-point variable and then performing the arithmetic operation. This practice ensures that at least one of the operands is a floating-point number and that the subsequent arithmetic operation is performed on floating-point operands.
void func(void) {
short a = 533;
int b = 6789;
long c = 466438237;
float d = a;
double e = b;
double f = c;
d /= 7; /* d is 76.14286 */
e /= 30; /* e is 226.3 */
f *= 789; /* f is 368019768993.0 */
}
Exceptions
FLP06-C-EX0: It may be desirable to have the operation take
place as integers before the conversion (obviating the need for a call to
trunc(), for example). If this is the programmer's intention, it
should be clearly documented to help future maintainers understand that this
behavior is intentional.
Risk Assessment
Improper conversions between integers and floating-point values may yield unexpected results, especially loss of precision. Additionally, these unexpected results may actually involve overflow, or undefined behavior.
| Recommendation | Severity | Likelihood | Remediation Cost | Priority | Level |
|---|---|---|---|---|---|
| FLP06-C | Low | Probable | Low | P6 | L2 |
Related Guidelines
| CERT C Secure Coding Standard | FLP34-C. Ensure that floating-point conversions are within range of the new type |
| SEI CERT C++ Coding Standard | VOID FLP05-CPP. Convert integers to floating point for floating point operations |
| CERT Oracle Secure Coding Standard for Java | NUM50-J. Convert integers to floating point for floating-point operations |
| MITRE CWE |
CWE-681, Incorrect conversion between numeric types CWE-682, Incorrect calculation |
Bibliography
| [ Hatton 1995] | Section 2.7.3, "Floating-Point Misbehavior" |
Possible Messages
Key |
Text |
Severity |
Disabled |
|---|---|---|---|
cast_changes_type_category |
Implicit conversion from integral to float type |
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
category_changes¶
category_changes
List of (from, to) type category pairs to check for. Both from and to are lists of categories.Type: list[typing.Tuple[typing.Set[bauhaus.ir.common.types.type_systems.TypeCategory], typing.Set[bauhaus.ir.common.types.type_systems.TypeCategory]]]
Default:
[({'bool_types', 'char_types', 'enum_types', 'signed_types', 'unsigned_types'}, {'float_types'})]
check_explicit_casts¶
check_explicit_casts : bool = False
check_implicit_casts¶
check_implicit_casts : bool = True
look_through_casts¶
look_through_casts : bool = False
only_complex_expressions¶
only_complex_expressions : bool = True
show_operand_in_entity¶
show_operand_in_entity : bool = False
type_system¶
type_system : bauhaus.ir.common.types.type_systems.TypeSystem = <bauhaus.ir.common.types.type_systems.CompilerTypeSystem object at 0x7f6f1c5fd510>
Option Types¶
These types are used by options listed above:
TypeCategory¶
Base class for the different type categories.signed_types
unsigned_types
float_types
char_types
plain char.bool_types
bool, _Bool and special expressions.enum_types
void_types
void_pointer_types
incomplete_pointer_types
function_pointer_types
object_pointer_types
null_pointer_types
other_types
Those not covered by other categories.