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

Copy
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

Copy
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.

Related checkers