...
Function | Domain | Range |
---|---|---|
|
| noNo |
|
| noNo |
|
| noNo |
|
| noNo |
noneNone | yesYes | |
| noneNone | yesYes |
| noneNone | yesYes |
|
| noNo |
|
| noNo |
|
| yesYes |
| noneNone | yesYes |
| noneNone | yesYes |
| yesYes | |
| noNo | |
| noneNone | yesYes |
|
| yesYes |
| noneNone | yesYes |
|
| noNo |
| noneNone | yesYes |
| noneNone | yesYes |
| noneNone | yesYes |
Domain Checking
The most reliable way to handle domain errors is to prevent them by checking arguments beforehand, as in the following template:
...
It is also difficult to check for math errors using errno
because an implementation might not set it. For real functions, the programmer can tell whether the implementation sets errno
by checking whether math_errhandling & MATH_ERRNO
is nonzero. For complex functions, the C Standard, Section section 7.3.2, simply states that "an implementation may set errno
but is not required to" [ISO/IEC 9899:2011].
The System V Interface Definition, Third Edition (SVID3), provides more control over the treatment of errors in the math library. The user can provide a function named matherr
that is invoked if errors occur in a math function. This function can print diagnostics, terminate the execution, or specify the desired return value. The matherr()
function has not been adopted by C, so its use is not generally portable.
The following error-handing template uses C Standard functions for floating-point errors when the C macro math_errhandling
is defined and indicates that they should be used; otherwise, it examines errno
.:
Code Block |
---|
#include <math.h> #if defined(math_errhandling) \ && (math_errhandling & MATH_ERREXCEPT) #include <fenv.h> #endif /* ... */ #if defined(math_errhandling) \ && (math_errhandling & MATH_ERREXCEPT) feclearexcept(FE_ALL_EXCEPT); #endif errno = 0; /* Call the function */ #if !defined(math_errhandling) \ || (math_errhandling & MATH_ERRNO) if (errno != 0) { /* Handle range error */ } #endif #if defined(math_errhandling) \ && (math_errhandling & MATH_ERREXCEPT) if (fetestexcept(FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW) != 0) { /* Handle range error */ } #endif |
...
The following noncompliant code determines the square root of x
.:
Code Block | ||||
---|---|---|---|---|
| ||||
double x; double result; result = sqrt(x); |
...
Since this function has domain errors but no range errors, bounds checking can be used to prevent domain errors.:
Code Block | ||||
---|---|---|---|---|
| ||||
double x; double result; if (isless(x, 0)) { /* Handle domain error */ } result = sqrt(x); |
...
This noncompliant code example determines the hyperbolic cosine of x
.:
Code Block | ||||
---|---|---|---|---|
| ||||
double x; double result; result = cosh(x); |
...
Since this function has no domain errors but may have range errors, the programmer must detect a range error and act accordingly.:
Code Block | ||||
---|---|---|---|---|
| ||||
#include <math.h> #if defined(math_errhandling) \ && (math_errhandling & MATH_ERREXCEPT) #include <fenv.h> #endif /* ... */ #if defined(math_errhandling) \ && (math_errhandling & MATH_ERREXCEPT) feclearexcept(FE_ALL_EXCEPT); #endif errno = 0; double x; double result; result = sinh(x); #if !defined(math_errhandling) \ || (math_errhandling & MATH_ERRNO) if (errno != 0) { /* Handle range error */ } #endif #if defined(math_errhandling) \ && (math_errhandling & MATH_ERREXCEPT) if (fetestexcept(FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW) != 0) { /* Handle range error */ } #endif |
...
The following noncompliant code raises x
to the power of y
.:
Code Block | ||||
---|---|---|---|---|
| ||||
double x; double y; double result; result = pow(x, y); |
However, this code may produce a domain error if x
is negative and y
is not an integer or if x
is zero 0 and y
is zero0. A domain error or range error may occur if x
is zero 0 and y
is negative, and a range error may occur if the result cannot be represented as a double
.
...
Since the pow()
function can produce both domain errors and range errors, the programmer must first check that x
and y
lie within the proper domain, then detect if a range error occurs and act accordingly.:
Code Block | ||||
---|---|---|---|---|
| ||||
#include <math.h> #if defined(math_errhandling) \ && (math_errhandling & MATH_ERREXCEPT) #include <fenv.h> #endif /* ... */ #if defined(math_errhandling) \ && (math_errhandling & MATH_ERREXCEPT) feclearexcept(FE_ALL_EXCEPT); #endif errno = 0; /* Call the function */ double x; double y; double result; if (((x == 0.f) && islessequal(y, 0)) || (isless(x, 0))) { /* Handle domain error */ } result = pow(x, y); #if !defined(math_errhandling) \ || (math_errhandling & MATH_ERRNO) if (errno != 0) { /* Handle range error */ } #endif #if defined(math_errhandling) \ && (math_errhandling & MATH_ERREXCEPT) if (fetestexcept(FE_INVALID | FE_DIVBYZERO | FE_OVERFLOW | FE_UNDERFLOW) != 0) { /* Handle range error */ } #endif |
...
Tool | Version | Checker | Description |
---|---|---|---|
Fortify SCA | 5.0 |
| Can detect violations of this rule with CERT C Rule Pack. |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
...
[ISO/IEC 9899:2011] | Section 7.3, "Complex Arithmetic <complex.h >"Section 7.12, "Mathematics < math.h >" |
[Plum 1985] | Rule 2-2 |
[Plum 1989] | Topic 2.10, "conv—Conversions and Overflow" |
...