Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Added PC-lint Plus to Automated Detection Table

Errors during floating-point operations are often neglected by applications; instead, the greatest effort is usually in validating the programmers who instead focus on validating operands before an operation. Errors occurring that occur during floating-point operations are admittedly difficult to determine and diagnose, but the benefits of understanding how to check for these errors and employing the process of doing so may often outweigh the costs. This recommendation suggests ways to capture errors during floating-point operations.

The following code has exhibits undefined behavior:

Code Block

int j = 0;
int iResult = 1 / j;

On most implementations, integer division by zero is a terminal error, commonly printing a diagnostic message and aborting the program.:

Code Block

double x = 0.0;
double dResult = 1 / x;

Though the code above Floating-point division by zero also results in undefined behavior, although most implementations do not view floating point division by zero as a treat it as a terminal error. If extra steps additional precautions are not taken, the operation happens "silently."

Wiki Markup
The most portable way of determining a floating point exceptional condition has occurred is to make use of the floating point exception faculties provided by C99 in {{fenv.h}} \[[ISO/IEC 9899:1999|AA. C References#ISO/IEC 9899-1999]\].

 it results in a silent error.

The most portable way to determine if a floating-point exceptional condition has occurred is to use the floating-point exception facilities provided by C in fenv.h.

However, the C floating-However, the C99 floating point exception functions are not without problems. The following caveats exist regarding the interaction between floating-point exceptions and conversions:

  • Conversion from floating-point to integer may cause an "invalid" floating-point exception. If this occurs, the value of that integer is undefined and should not be used.
  • Most implementations fail to raise "invalid" for conversions from any negative or "large" positive FP floating-point values to unsigned integer types or to signed char. (see See tflt2int.c.).
  • When a nonnoninteger floating-integer floating point value is converted into to an integer, the "inexact" floating-point exception is raised.

For information regarding floating-point number conversions, see FLP34-C. Ensure that floating-point conversions are within range of the new type.

Though the notion of floating point exceptions guaranteed by C99, floating point exceptions generally only exist on architectures utilizing IEEE-754. Despite this, these functions are the only somewhat portable solution to handling floating point exceptions.

The C Standard does not require all implementations to support floating-point exceptions. Each exception macro in fenv.h is defined if, and only if, the corresponding exception is supported. Only implementations that use IEC 60559 (formerly IEEE-754) floating-point arithmetic are required to support all five exceptions defined by C (see the C Standard, subclause 7.6.2 [ISO/IEC 9899:2011]). Nevertheless, these functions are the most portable solution for handling floating-point exceptions.

A less portable but potentially more secure solution is to use the capabilities A less portable, but sometimes more intuitive and/or more informative, solution is to make use of the faculties provided by the underlying implementation. If this approach is taken, the caveats of that system need to must be well understood. The following table can serve as  The following table provides a starting point for some common architecturesoperating systems:

Operating System

How to

handle floating point errors

Handle Floating-Point Errors

Linux
Solaris 10
AIX 5.3
HP-UX 11.31
Mac OS X 10.5

Use the

C99

C floating-point exception functions

.

<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="97029c54-c2e9-4dca-8383-b2428f7b2816"><ac:plain-text-body><![CDATA[

Windows

Either use the C99 floating point exception function or structured exception handling through _fpieee_flt [[MSDN

AA. C References#MSDN]]

]]></ac:plain-text-body></ac:structured-macro>

Non-Compliant Code Example

In the following non-compliant code, floating point operations are carried out and there is no observation for errors during floating point operations. Please note that the range check on various operands for the operations has been intentionally ignored because we intend to capture the errors during a floating point operation.

Windows

Use either the C floating-point exception functions or structured exception handling through _fpieee_flt [MSDN]

Noncompliant Code Example

In this noncompliant code example, floating-point operations are performed without checking for errors. Note that range checking has been intentionally omitted because the intent is to detect errors following the floating-point operation.

Code Block
bgColor#FFCCCC
langc
void fpOper_noErrorChecking(void) {
  /* ... */
  double a = 1e-40, b, c = 0.1;
  float x = 0, y;
  /* Inexact and underflows */
  y = a;
  /* Divide-by-zero operation */
  b = y / x;
  /* Inexact (loss of precision) */
  c = sin(30) * a;
Code Block
bgColor#FFCCCC

fpOper_noErrorChecking(void) {
  /* ... */
  double a = 1e-40, b, c = 0.1;
  float x = 0, y;
  /* inexact and underflows */
  y = a;
  /* divide by zero operation */
  b = y / x}

However, exceptional conditions (as indicated by the comments) occur that may lead to unexpected arithmetic results.

Compliant Solution (C)

This compliant solution uses C Standard functions to handle floating-point errors:

Code Block
bgColor#ccccff
langc
#include <fenv.h>
#pragma STDC FENV_ACCESS ON

void fpOper_fenv(void) {
  double a = 1e-40, b, c = 0.1;
  float x = 0, y;
  int fpeRaised;
  /* inexact (loss of precision)... */

  c = sin(30) * a;
  /* ... */
}

However, as the comments indicate, various exceptional conditions occur that may lead to unexpected arithmetic results.

Compliant Solution 1

This compliant solution uses C99 standard functions to handle floating point errors.

Code Block
bgColor#ccccff

#include <fenv.h>
#pragma STDC FENV_ACCESS ON

fpOper_fenv(void) {
  double a = 1e-40, b, c = 0.1;
  float x = 0, y;
  int fpeRaised;
  /* ... feclearexcept(FE_ALL_EXCEPT);
  /* Store a into y is inexact and underflows: */
  y = a;
  fpeRaised = fetestexcept(FE_ALL_EXCEPT);
  /* fpeRaised has FE_INEXACT and FE_UNDERFLOW */

  feclearexcept(FE_ALL_EXCEPT);

  /* Divide-by-zero operation */
  b = y / x;
  fpeRaised = fetestexcept(FE_ALL_EXCEPT);
  /* fpeRaised has FE_DIVBYZERO */

  feclearexcept(FE_ALL_EXCEPT);

  /*c Store a into y is inexact and underflows: */
  y = a;
  fpeRaised = = sin(30) * a;
  fpeRaised = fetestexcept(FE_ALL_EXCEPT);
  /* fpeRaised  has FE_INEXACT and FE_UNDERFLOW */

  feclearexcept(FE_ALL_EXCEPT);

  /* divide by zero operation... */
  b = y / x;
  fpeRaised = fetestexcept(FE_ALL_EXCEPT);
  /* fpeRaised has FE_DIVBYZERO */

  feclearexcept(FE_ALL_EXCEPT);

  c = sin(30) * a;
  fpeRaised = fetestexcept(FE_ALL_EXCEPT);
  /* fpeRaised has FE_INEXACT */

  feclearexcept(FE_ALL_EXCEPT);
  /* ... */
}

Compliant Solution 2 (Windows)

Microsoft Visual Studio 2008 and earlier does not support C99 functions to handle floating point errors. Windows provides an alternative method to get floating point exception code using _statusfp(), _statusfp2(), and _clearfp().

}

Compliant Solution (Windows)

Microsoft Visual Studio 2008 and earlier versions do not support C functions to handle floating-point errors. Windows provides an alternative method using _statusfp(), _statusfp2(), and _clearfp().

Code Block
bgColor#ccccff
langc
void fpOper_usingStatus(void) {
  /* ... */
  double a = 1e-40, b, c;
  float x = 0, y;
  unsigned int rv = _clearfp();

  /* Store into y is inexact and underflows: */
  y = a;
  rv = _clearfp();  /* rv has _SW_INEXACT and _SW_UNDERFLOW */

  /* Zero-divide */
  b = y / x; 
Code Block
bgColor#ccccff

fpOper_usingStatus(void) {
  /* ... */
  double a = 1e-40, b, c;
  float x = 0, y;
  unsigned int rv = _clearfp();

  /* Storerv into y is inexact and underflows:has _SW_ZERODIVIDE */

  /* Inexact */
  yc = sin(30) * a;
  rv = _clearfp();  /* rv has _SW_INEXACT and _SW_UNDERFLOW */

  /* zero-divide... */
  b = y / x; rv = _clearfp(); /* rv has _SW_ZERODIVIDE */

  /* inexact
}

Compliant Solution (Windows SEH)

Microsoft Visual Studio 2008 also uses structured exception handling (SEH) to handle floating-point operations. SEH provides more information about the error and allows the programmer to change the results of the floating-point operation that caused the error condition.

Code Block
bgColor#ccccff
langc
void fp_usingSEH(void) {
  /* ... */
  c = sin(30) *double a; rv = _clearfp(); /* rv has _SW_INEXACT */
  /* ... */
}

Compliant Solution 3 (Windows)

Microsoft Visual Studio 2008 also uses structured exception handling (SEH) to handle floating point operation. Using the SEH allows the programmer to change the results of the floating point operation that caused the error condition. Using SEH also provides more information about the error condition.

Code Block
bgColor#ccccff

fp_usingSEH(void) {
  /* ... */
  double a = 1e-40, b, c = 0.1;
  float x = 0, y;
  unsigned int rv ;

  unmask_fp();

  _try {
    /* Store into y is inexact and underflows */
    y = a;

    /* divide by zero operation */
    b = y / x;

    /* inexact */
    c = sin(30) * a;
  }

  _except (_fpieee_flt(
             GetExceptionCode(),
             GetExceptionInformation(),
             fpieee_handler))
  {
	printf ("fpieee_handler: EXCEPTION_EXECUTE_HANDLER");
  }

  /* ... */
}

void unmask_fpsr(void) {
  unsigned int u;
  unsigned int control_word;
  _controlfp_s(&control_word, 0, 0);
  u = control_word & ~(_EM_INVALID
  = 1e-40, b, c = 0.1;
  float x = 0, y;
  unsigned int rv ;

  unmask_fpsr();

  _try {
    /* Store into y is inexact and underflows: */
    y = a;

    /* Divide-by-zero operation */
    b = y / x;

    /* Inexact */
    c = sin(30) * a;
  }

  _except (_fpieee_flt(
             GetExceptionCode(),
             GetExceptionInformation(),
             fpieee_handler)) {
  {
  printf ("fpieee_handler: EXCEPTION_EXECUTE_HANDLER");
  }

  /* ... */
}

void unmask_fpsr(void) {
  unsigned int u;
  unsigned int control_word;
  _controlfp_s(&control_word, 0, 0);
  u = control_word & ~(_EM_INVALID
                     | _EM_DENORMAL
                     | _EM_ZERODIVIDE
                             | _EM_DENORMALOVERFLOW
                     | _EM_ZERODIVIDEUNDERFLOW
                     | _EM_OVERFLOWINEXACT);
  _controlfp_s( &control_word, u, _MCW_EM);
  return ;
}

int fpieee_handler(_FPIEEE_RECORD *ieee) {
  /* ... */

  switch (ieee->RoundingMode) {
    |case _EM_UNDERFLOWFpRoundNearest:
      /* ... */
      break;

      /*
   | _EM_INEXACT);
  _controlfp_s( &control_word, u, _MCW_EM);
  return ;
}

int fpieee_handler(_FPIEEE_RECORD *ieee) {
  /* ... */

     * Other RMs include _FpRoundMinusInfinity,
       * _FpRoundPlusInfinity, _FpRoundChopped.
       */

      /* ... */
    }

  switch (ieee->RoundingMode>Precision) {
    case _FpRoundNearestFpPrecision24:
      /* ... */
      break;

      /* Other RMsPs include _FpRoundMinusInfinity,
       * _FpRoundPlusInfinity, _FpRoundChoppedFpPrecision53 */

      /* ... */
    }

   switch (ieee->Precision>Operation) {
     case _FpPrecision24FpCodeAdd:
       /* ... */
       break;

       /* Other
 Ps include _FpPrecision53*/
      /* ... */
    }
Other Ops include _FpCodeSubtract, _FpCodeMultiply,
   switch (ieee->Operation) {
   *  case_FpCodeDivide, _FpCodeSquareRoot, _FpCodeAdd:FpCodeCompare,
        /* ... */_FpCodeConvert, _FpCodeConvertTrunc.
       break; */

       /* Other Ops include _FpCodeSubtract, _FpCodeMultiply,... */
    }

  /* 
   * Process *the _FpCodeDivide, _FpCodeSquareRoot, _FpCodeCompare,bitmap ieee->Cause.
   * Process the bitmap ieee->Enable.
   * _FpCodeConvert, _FpCodeConvertTrunc */Process the bitmap ieee->Status.
   * Process the  /* ... */
    }

  /* process the bitmap ieee->Cause */
  /* process the bitmap ieee->Enable */
  /* process the bitmap ieee->Status */
  /* process the Operand ieee->Operand1,Operand ieee->Operand1, 
   * evaluate format and Value.
   * Process the Operand ieee->Operand2, 
   * evaluate format and Value.
   * Process the Result ieee->Result, 
   * evaluate format and Value.
 */
  /* processThe theresult Operand ieee->Operand2,
   *evaluate format and Value */
  /* process the Result ieee->Result,should be set according to the operation 
   * specified in ieee->Cause and the result formatted as 
   * evaluate format and Valuespecified in ieee->Result.
   */

  /* The result should be set according to the operation
   * specified in ieee->Cause and the result format as
   * specified in ieee->Result */

  /* ... */
}

Risk Assessment

... */
}

Risk Assessment

Undetected floating-point errors may result in lower program efficiency, inaccurate results, or software vulnerabilitiesIf floating point exceptions go undetected, they will cause one or more of these conditions: a security vulnerability, lower program efficiency, and inaccurate results. Most processors stall for a significant duration (sometimes up to a second or even more on 32-bit desktop processors) when an when an operation incurs a NaN (not a number) value.

Recommendation

Severity

Likelihood

Remediation Cost

Priority

Level

FLP03-

A

C

low

Low

probable

Probable

high

High

P2

L3

Automated Detection

...

Tool

Version

Checker

Description

Astrée
Include Page
Astrée_V
Astrée_V
float-division-by-zeroPartially checked
Compass/ROSE



Could detect violations of this rule by ensuring that floating-point operations are surrounded by feclearexcept() and fetestexcept(). It would need to look for type conversions to float or double, divisions (by a number not known to be nonzero), and multiplication. It may be wisest to apply this to all floating-point operations in general

...

Related Vulnerabilities

Search for vulnerabilities resulting from the violation of this rule on the CERT website.

References

Wiki Markup
\[[IEEE 754|AA. C References#IEEE 754 2006]\]
\[[Intel 01|AA. C References#Intel 01]\]
\[[Keil 08|AA. C References#Keil 08]\]
\[[MSDN|AA. C References#MSDN]\] "[fpieee_flt (CRT)|http://msdn.microsoft.com/en-us/library/te2k2f2t(VS.80).aspx]"
\[[Open Group 04|AA. C References#Open Group 04]\] "[{{fenv.h}} - Floating point environment|http://www.opengroup.org/onlinepubs/009695399/basedefs/fenv.h.html]"
\[[SecurityFocus 07|AA. C References#SecurityFocus 07]\]

LDRA tool suite
Include Page
LDRA_V
LDRA_V
43 DPartially implemented
Parasoft C/C++test
Include Page
Parasoft_V
Parasoft_V

CERT_C-FLP03-a
CERT_C-FLP03-b
CERT_C-FLP03-c
CERT_C-FLP03-d

Avoid division by zero
Avoid implicit conversions from wider to narrower floating type
Avoid implicit conversions from narrower to wider floating type
Avoid implicit conversions of floating point numbers from wider to narrower floating type

Parasoft Insure++

Runtime analysis
PC-lint Plus

Include Page
PC-lint Plus_V
PC-lint Plus_V

736, 9120, 9227

Assistance provided

Polyspace Bug Finder

Include Page
Polyspace Bug Finder_V
Polyspace Bug Finder_V

CERT C: Rec. FLP03-C


Checks for:

  • Float conversion overflow
  • Float overflow
  • Float division by zero

Rec. partially covered.

Related Vulnerabilities

Search for vulnerabilities resulting from the violation of this recommendation on the CERT website.

Related Guidelines

Bibliography

[IEEE Std 1003.1:2013]XBD, Headers, <fenv.h>
[Intel 2001]
[ISO/IEC 9899:2011]Subclause 7.6.2, "Floating-Point Exceptions"
[Keil 2008]
[MSDN]"fpieee_flt (CRT)"
[SecurityFocus 2007]


...

Image Added Image Added Image AddedFLP02-A. Consider avoiding floating point numbers when precise computation is needed      05. Floating Point (FLP)       FLP30-C. Do not use floating point variables as loop counters