Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

Function

Domain

Range

acos(x), asin(x)

-1 <= x && x <= 1

noNo

atan2(y,x)

x != 0 || y != 0

noNo

acosh(x)

x >= 1

noNo

atanh(x)

-1 < x && x < 1

noNo

cosh(x), sinh(x)

noneNone

yesYes

exp(x), exp2(x), expm1(x)

noneNone

yesYes

ldexp(x, exp)

noneNone

yesYes

log(x), log10(x), log2(x)

x > 0

noNo

log1p(x)

x > -1

noNo

ilogb(x), logb(x)

x != 0

yesYes

scalbn(x, n), scalbln(x, n)

noneNone

yesYes

hypot( x, y)

noneNone

yesYes

pow(x,y)

x > 0 || (x == 0 && y > 0) ||
(x < 0 && y is an integer)

yesYes

sqrt(x)

x >= 0

noNo

erfc(x)

noneNone

yesYes

lgamma(x), tgamma(x)

x != 0 &&
!(x < 0 && x is an integer)

yesYes

lrint(x), lround(x)

noneNone

yesYes

fmod(x,y)

y != 0

noNo

nextafter(x,y), nexttoward(x,y)

noneNone

yesYes

fdim(x,y)

noneNone

yesYes

fma(x,y,z)

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
bgColor#FFcccc
langc
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
bgColor#ccccff
langc
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
bgColor#FFcccc
langc
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
bgColor#ccccff
langc
#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
bgColor#FFcccc
langc
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
bgColor#ccccff
langc
#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"

 

...