Errors during floating-point operation operations are often ignored by the applications; instead much effort is only in validating the neglected by programmers who instead focus on validating operands before an operation.. Errors that occur during floating-point operations are admittedly difficult to determine and diagnose, but the benefits of doing so often outweigh the costs. This recommendation suggests ways to capture errors during floating-point operations. What makes it difficult to detect these errors is that the application will not abort or even complain when these exceptions occur. For example, while the following statement
The following code exhibits undefined behavior:
Code Block |
---|
int j = 0;
int iResult = 1 / j;
|
readily generates a runtime error / exception , whereasOn 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;
|
generates no error messages.
Wiki Markup |
---|
Though the floating point exception conditions and handling is standardized by IEEE \[1\], the Operating Systems implement support for handling floating point errors and other conditions in different ways. |
Operating System | Handling FP errors | |
---|---|---|
Linux | C99 FP functions - These functions are declared in fenv.h [2] | |
<ac:structured-macro ac:name="unmigrated-wiki-markup" ac:schema-version="1" ac:macro-id="1db98668-3661-4779-90b6-a0f9c926752e"><ac:plain-text-body><![CDATA[ | Windows | Structured Exception Handling - user defined handler _fpieee_flt [3] |
Non-Compliant Code Example
Floating-point division by zero also results in undefined behavior, although most implementations do not treat it as a terminal error. If additional precautions are not taken, 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-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 floating-point values to unsigned integer types or to
signed char
. (See tflt2int.c.) - When a noninteger floating-point value is converted 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.
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 provided by the underlying implementation. If this approach is taken, the caveats of that system must be well understood. The following table provides a starting point for some common operating systems:
Operating System | How to Handle Floating-Point Errors |
---|---|
Linux | Use the C floating-point exception functions |
Windows | Use either the C floating-point exception functions or structured exception handling through |
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-In this NCCE, floating point operations are carried out and there is no observation for errors during floating point operations. Please note the range check on various operands for the operations has been intentionally ignored, since our intention is capture the errors during a floating point operation.
Code Block | ||||
---|---|---|---|---|
| ||||
void fpOper_ fpOper_noErrorChecking(void) { /* ... */ double a = 1e-40, b, c = 0.1; float x = 0, y; //* inexactInexact and underflows */ y = a; //* divide Divide-by -zero operation */ b = y / x; // inexact /* Inexact (loss of precision) */ c = sin(30) * a; /* ... */ } |
Compliant Solution
Here is an example that demonstrates how to handle FP operations using the FP functions as standardized in C99.
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 | ||||
---|---|---|---|---|
| ||||
#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; /* ... */ feclearexceptfeclearexcept(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 Divide-by -zero operation */ b = y / x; fpeRaised 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); /* ..... */ } |
Implementation-Specific Details
Windows OS nor the libraries with MS Visual studio support C99 functions, instead Structured Exception Handling is used to handle for FP operation. Windows also provides an alternative method to get the FP exception code - using _statusfp/_statusfp2 and/or _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 | ||||
---|---|---|---|---|
| ||||
void fpOper_usingStatus(void | ||||
Code Block | ||||
fpOper_usingStatus() { /* .... */ 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 */ //* zeroZero-divide */ b = y / x; rv = _clearfp() ; //* rv has _SW_ZERODIVIDE */ /* Inexact /*/ inexact c = sin(30) * a; rv = _clearfp(); ;//* rv has _SW_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 Using the SEH allows the programmer to change the results of the FP operation that caused the error condition. Using SEH also provides more information about the error condition.
Code Block | ||||
---|---|---|---|---|
| ||||
void fp_usingSEH(void) { /* ... */ double a = 1e-40, b, c = 0.1; float x = 0, y; unsigned int rv ; unmask_fpfpsr(); _try { // /* Store into y is inexact and underflows: */ y = a; // divide by /* Divide-by-zero operation */ b = y / x; // inexact /* Inexact */ c = sin(30) * a; } _except (_fpieee_flt (GetExceptionCode(), GetExceptionInformation(), fpieee( 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_OVERFLOW | _EM_UNDERFLOW | _EM_INEXACT); _controlfp_s( &control_word, u, _MCW_EM); return ; } int fpieee_handler (_FPIEEE_RECORD \*ieee) { // ... switch(ieee->RoundingMode) { case \_FpRoundNearest: // .... break; /\* Other RMs include \_FpRoundMinusInfinity, \_FpRoundPlusInfinity, \_FpRoundChopped \*/ // .... } switch(ieee->Precision) { case \_FpPrecision24: // .... break; /\* Other Ps include \_FpPrecision53*/ // .... } switch(ieee->Operation) { case \_FpCodeAdd: // ... break; /\* Other Ops include \_FpCodeSubtract, \_FpCodeMultiply, \_FpCodeDivide, \_FpCodeSquareRoot, \_FpCodeCompare, \_FpCodeConvert, \_FpCodeConvertTrunc \*/ // .... } // process the bitmap ieee->Cause // process the bitmap ieee->Enable // process the bitmap ieee->Status // process the 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 // the result should be set according to the operation specified in ieee->Cause and the result format as specified in ieee->Result // the Result set is based on the ... } |
Risk Assessment
The Floating point exceptions if they go undetected will cause one or more of these conditions - security vulnerability, lower program efficiency and generate inaccurate results. Most processors stall for significant duration (sometimes upto a second or even more on 32bit desktop processors) when an operation incur a NaN.
References
Wiki Markup |
---|
\[1\] IEEE standard for binary floating-point arithmetic |
Wiki Markup |
---|
\[2\] fenv.h - Floating point environment |
Wiki Markup |
---|
\[3\] MSDN - CRT - fpieee_flt |
Wiki Markup |
---|
\[4\] Floating-Point IEEE Filter for Microsoft\* Windows\* 2000 on the Intel® Itanium⢠Architecture |
Wiki Markup |
---|
\[5\] Linux Kernel Floating Point Exception Handler Local Denial of Service Vulnerability |
http://www.securityfocus.com/bid/10538/discuss
Wiki Markup |
---|
\[6\] ARM support for floating-point computations |
DENORMAL
| _EM_ZERODIVIDE
| _EM_OVERFLOW
| _EM_UNDERFLOW
| _EM_INEXACT);
_controlfp_s( &control_word, u, _MCW_EM);
return ;
}
int fpieee_handler(_FPIEEE_RECORD *ieee) {
/* ... */
switch (ieee->RoundingMode) {
case _FpRoundNearest:
/* ... */
break;
/*
* Other RMs include _FpRoundMinusInfinity,
* _FpRoundPlusInfinity, _FpRoundChopped.
*/
/* ... */
}
switch (ieee->Precision) {
case _FpPrecision24:
/* ... */
break;
/* Other Ps include _FpPrecision53 */
/* ... */
}
switch (ieee->Operation) {
case _FpCodeAdd:
/* ... */
break;
/*
* Other Ops include _FpCodeSubtract, _FpCodeMultiply,
* _FpCodeDivide, _FpCodeSquareRoot, _FpCodeCompare,
* _FpCodeConvert, _FpCodeConvertTrunc.
*/
/* ... */
}
/*
* Process the bitmap ieee->Cause.
* Process the bitmap ieee->Enable.
* Process the bitmap ieee->Status.
* Process the 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.
* The result should be set according to the operation
* specified in ieee->Cause and the result formatted as
* specified in ieee->Result.
*/
/* ... */
}
|
Risk Assessment
Undetected floating-point errors may result in lower program efficiency, inaccurate results, or software vulnerabilities. Most processors stall for a significant duration when an operation incurs a NaN (not a number) value.
Recommendation | Severity | Likelihood | Remediation Cost | Priority | Level |
---|---|---|---|---|---|
FLP03-C | Low | Probable | High | P2 | L3 |
Automated Detection
Tool | Version | Checker | Description | ||||||
---|---|---|---|---|---|---|---|---|---|
Astrée |
| float-division-by-zero | Partially checked | ||||||
Compass/ROSE | Could detect violations of this rule by ensuring that floating-point operations are surrounded by | ||||||||
LDRA tool suite |
| 43 D | Partially implemented | ||||||
Parasoft C/C++test |
| CERT_C-FLP03-a | Avoid division by zero | ||||||
Parasoft Insure++ | Runtime analysis | ||||||||
PC-lint Plus |
| 736, 9120, 9227 | Assistance provided | ||||||
Polyspace Bug Finder |
| Checks for:
Rec. partially covered. |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this recommendation on the CERT website.
Related Guidelines
SEI CERT C++ Coding Standard | VOID FLP03-CPP. Detect and handle floating point errors |
MITRE CWE | CWE-369, Divide by zero |
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] |
...
http://www.keil.com/support/man/docs/armlib/armlib_bihbjiea.htmhttp://www.keil.com/support/man/docs/armlib/armlib_bihbjiea.htm