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"
Excerpt from SEI CERT C Coding Standard: Rules for Developing Safe, Reliable, and Secure Systems (2016 Edition) and SEI CERT C Coding Standard [https://cmu-sei.github.io/secure-coding-standards/sei-cert-c-coding-standard/recommendations/floating-point-flp/flp06-c], Copyright (C) 1995-2026 Carnegie Mellon University. See section 9.4. "3rd-Party Licenses" in the documentation for full details.

Possible Messages

Key

Text

Severity

Disabled

cast_changes_type_category

Implicit conversion from integral to float type

None

False

Options

category_changes

category_changes

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'})]

List of (from, to) type category pairs to check for. Both from and to are lists of categories.
 

check_explicit_casts

check_explicit_casts : bool = False

Whether explicit casts should be checked and reported.
 

check_implicit_casts

check_implicit_casts : bool = True

Whether implicit casts should be checked and reported.
 

look_through_casts

look_through_casts : bool = False

If true, operand after stripping casts is used.
 

only_complex_expressions

only_complex_expressions : bool = True

Whether all operands or only those deemed complex should be inspected.
 

show_operand_in_entity

show_operand_in_entity : bool = False

Whether entity should be "from->to" or "(from->to)operand".
 

type_system

type_system : bauhaus.ir.common.types.type_systems.TypeSystem = <bauhaus.ir.common.types.type_systems.CompilerTypeSystem object at 0x7f6f1c5fd510>

Which type system to use: compiler types, underlying types, essential types
 

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.