CERT.MATH.RANGE.CHECK
Error condition must be checked after calling a library math function that might cause range error
The CERT.MATH.RANGE.CHECK checker identifies potential defects where a standard library math function might trigger a range error, but the code fails to verify or handle the resulting error condition.
Vulnerability and risk
A range error arises only when a computation results in either an overflow or an underflow. The following table outlines the double-precision variants of standard mathematical functions and indicates whether they are capable of triggering range errors, as specified by the C Standard:
| Function | Range Error Possible |
|---|---|
| acos(x) | No |
| asin(x) | Yes |
| atan(x) | Yes |
| atan2(y, x) | No |
| acosh(x) | Yes |
| asinh(x) | Yes |
| atanh(x) | Yes |
| cosh(x),sinh(x) | Yes |
| exp(x),exp2(x),expm1(x) | Yes |
| ldexp(x, exp) | Yes |
| log(x),log10(x),log2(x) | No |
| log1p(x) | No |
| ilogb(x) | Yes |
| logb(x) | Yes |
| scalbn(x, n),scalbln(x, n) | Yes |
| hypot(x, y) | Yes |
| pow(x,y) | Yes |
| sqrt(x) | No |
| erf(x) | Yes |
| erfc(x) | Yes |
| lgamma(x),tgamma(x) | Yes |
| lrint(x), lround(x) | Yes |
| fmod(x, y),remainder(x, y), remquo(x, y, quo) | Yes |
| nextafter(x, y), nexttoward(x, y) | Yes |
| fdim(x,y) | Yes |
| fma(x,y,z) | Yes |
Since such errors can't usually be prevented, it's essential to detect them reliably. This involves checking multiple error indicators, such as errno, math_errhandling, and floating-point exceptions.
By examining these conditions, programs can identify range errors and respond appropriately.
Mitigation and prevention
A compliant approach involves verifying and handling any error conditions that may arise after invoking a standard library math function capable of producing a range error.
Vulnerable code example
void func(double x)
{
double res = sinh(x);
}
Klocwork reports CERT.MATH.RANGE.CHECK because the result of sinh(x) function call is capable of producing range error, but error condition check is missing.
Fixed code example
void func1(double x) {
double result;
#pragma STDC FENV_ACCESS ON
if (math_errhandling & MATH_ERREXCEPT) {
feclearexcept(FE_ALL_EXCEPT);
}
errno = 0;
result = sinh(x);
if ((math_errhandling & MATH_ERRNO) && errno != 0) {
// Handle range error via errno
}
if ((math_errhandling & MATH_ERREXCEPT) &&
fetestexcept(FE_INVALID | FE_DIVBYZERO |
FE_OVERFLOW | FE_UNDERFLOW)) {
// Handle range error via floating-point exceptions
}
// Use result...
result = 89.67;
}
There is no possibility of CERT.MATH.RANGE.CHECK here since error condition is properly checked after calling sinh(x) at line 11.