Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Parasoft 2020.2

Application-independent code includes code that is:

  • shipped Shipped with the compiler or operating system
  • from From a third-party library
  • developed Developed in-house

When application-specific code detects an error, it can immediately respond on the
spot with a specific action, as in:

#ccffcc
Code Block
bgColor

if (something_really_bad_happens) {
  take_me_some_place_safe();
}

This is because This response occurs because the application must both detect errors and provide a
mechanism for handling errors. But because applicationApplication-independent
code is , by contrast, is not associated with any application, it so it cannot handle errors.
However, it must still detect errors , and report them to an
application , so that the application may handle them.

Error detection and reporting can take several forms:

  • a A return value (especially of type errno_t)
  • an An argument passed by address
  • a A global object (e.g., such as errno)
  • longjmp()
  • some Some combination of the above

...

Noncompliant Code Example

This non-compliant noncompliant code example consists of two
application-independent functions, f() and g(). The f()
function is part of the external API for the module; the g()
function is an internal function.

Code Block
bgColor#ffcccc
langc

void g(void) {
  /* ... */
  if (something_really_bad_happens) {
    fprintf(stderr, "Something really bad happened!\n");
    abort();
  }
  /* ... */
}

void f(void) {
  g();
  /* ... doDo the rest of f ... */
}

If something_really_bad_happens in g(), the function prints an
error message to stderr and then calls abort(). The problem is
that this application-independent code does not know the context in
which it is being called, so it is erroneous to handle the error.

Wiki Markup\[[Miller 04|AA. C References#Miller 04]\] Practice 23 Smart Libraries,” Practice 23 [Miller 2004], says:

When a library aborts due to some kind of anomaly, it is saying there
is no hope for execution to proceed normally beyond the point where
the anomaly is detected. Nonetheless, it is dictatorially making this
decision on behalf of the client. Even if the anomaly turns out to be
some kind of internal bug in the library, which obviously cannot be
resolved in the current execution, aborting is a bad thing to do. The
fact is, a library developer cannot possibly know the fault-tolerant
context in which his/her library is being used. The client may indeed
be able to recover from the situation even if the library cannot.

It is equally bad to eliminate the call to abort() from g().
In this case, there is no indication back to the calling function has no indication that
any an error has occurred.

Compliant Solution (Return Value)

One way to indicate errors to inform the calling function of errors is to return a value indicating success or
errorsfailure. This compliant solution changes ensures each function to return returns a
value of type errno_t, where 0 indicates that no error has
occurred.:

Code Block
bgColor#ccccff
langc

const errno_t ESOMETHINGREALLYBAD = 1;

errno_t g(void) {
  /* ... */
  if (something_really_bad_happens) {
    return ESOMETHINGREALLYBAD;
  }
  /* ... */
  return 0;
}

errno_t f(void) {
  errno_t status = g();
  if ((status = g()) != 0) {
    return status;
  }

  /* ... doDo the rest of f ... */

  return 0;
}

A call to f() returns a status indicator, which is zero 0 upon
success , and a non-zero nonzero value upon failure indicating what went wrong.unmigrated-wiki-markup

A return type of {{errno_t}} indicates that the function returns a status indicator \[[indicator (see DCL09-AC. Declare functions that return an errno error code with a return type of errno_t]).

While this solution This error-handling approach is secure, but it has the following drawbacks:

...

  • Source and object code can significantly increase in size, perhaps by as much as 30-40% \[[Saks 07b|AA. C References#Saks 07b]\]30 to 40 percent [Saks 2007b].
  • All function return values must be checked (see ERR33-C. Detect and handle standard library errors). Wiki MarkupAll function return values must be checked (see \[[MEM32-C. Detect and handle memory allocation errors]\] among many others\].)
  • Functions should not return other values if they return error
    indicators (see ERR02-AC. Avoid in-band error indicators]).)
  • Any function that allocates resources must ensure they are freed incases in cases where errors occur.

Compliant Solution (Address Argument)

Instead of encoding status indicators in the return value, each
function can take a pointer as an argument, which is used to indicate
errors. In the following example, each function uses a an errno_t\ *
argument to report errors.:

Code Block
bgColor#ccccff
langc

const errno_t ESOMETHINGREALLYBAD = 1;

void g(errno_t * err) {
  if (err == NULL) {
    /* handleHandle null pointer */
  }
  /* ... */
  if (something_really_bad_happens) {
    *err = ESOMETHINGREALLYBAD;
  } else {
    /* ... */
    *err = 0;
  }
}

void f(errno_t * err) {
  if (err == NULL) {
    /* handleHandle null pointer */
  }
  g(err);
  if (*err == 0) {
    /* ... doDo the rest of f ... */
  }
  return 0;
}

A call to f() provides a status indicator which that is zero 0 upon
success , and a non-zero nonzero value indicating upon failure, assuming the user
provided a valid pointer to an object of type errno_t.

While this This solution is secure, but it has the following drawbacks:

  • A return status can only be returned only if the caller provides a valid
    pointer to an object of type errno_t. If this argument is null NULL,
    there is no way to indicate this error.
  • Source code becomes even larger, due to the larger because of the possibilities of
    receiving a null pointer.
  • All error indicators must be checked after calling functions.
  • Any function that allocates resources must ensure they are freed incases in cases where errors occur.
  • Unlike return values, static analysis tools generally do not
    diagnose a failure to check error indicators passed as argument
    pointers.

Compliant Solution (Global Error Indicator)

Instead of encoding error indicators in the return value or arguments,
a functions function can indicate its status by assigning a value to a global
variable. In the following example, each function uses a static
indicator called my_errno.

The original errno variable was the Standard standard C library's
implementation of error handling using this approach.

Code Block
bgColor#ccccff
langc

errno_t my_errno; /* alsoAlso declared in a .h file */
const errno_t ESOMETHINGREALLYBAD = 1;

void g(void) {
  /* ... */
  if (something_really_bad_happens) {
    my_errno = ESOMETHINGREALLYBAD;
    return;
  }
  /* ... */
}

void f(void) {
  my_errno = 0;
  g();
  if (my_errno != 0) {
    return;
  }
  /* ... doDo the rest of f ... */
}

The call to f() provides a status indicator which that is zero 0 upon
success , and a non-zero nonzero value indicating upon failure.

This solution has many of the same properties as those observed with
errno, including advantages and drawbacks.

  • Source code size is inflated, though not by as much as in other
    approaches.
  • All error indicators must be checked after calling functions.
  • Nesting of function calls that all use this mechanism is
    problematic.
  • Any function that allocates resources must ensure they are freed incases in cases where errors occur.
  • In general, combining registries of different sets of errors is
    difficult. For example, changing the above this compliant solution code to use errno is
    difficult and bug-prone ; as one because the programmer must be precisely aware of when C
    library functions set and clear errno, and one also must be aware of
    all valid errno values before adding new ones.
  • There are major limitations on calling Calling f() from other application-independent code has major limitations. Since Because f() sets my_errno to 0, it may potentially be overwriting a nonzero error value set by another application-independent calling function.

For these reasons, among others, this approach is generally
discouraged.

Compliant Solution ( setjmp() and longjmp() )

C provides two functions, setjmp() and longjmp(), that can be
used to alter control flow. This allows a user of these functions to
ignore  Using these functions, a user can ignore error values , and entrust trust that control flow will be correctly
diverted in the event of error.

The following example uses setjmp() and longjmp() to ensure
that control flow is disrupted in the event of error, and also ; it also uses
the my_errno indicator from the previous example. See MSC22-C. Use the setjmp(), longjmp() facility securely for more information on setjmp() and longjmp().

Code Block
bgColor#ccccff
langc

#include <setjmp.h>

const errno_t ESOMETHINGREALLYBAD = 1;

jmp_buf exception_env;

void g(void) {
  /* ... */
  if (something_really_bad_happens) {
    longjmp(exception_env, ESOMETHINGREALLYBAD);
  }
  /* ... */
}

void f(void) {
  g();
  /* ... doDo the rest of f ... */
}

/* ... */
errno_t err;
if ((err = setjmp(exception_env)) != 0) {
  /*
   * ifIf we get here, an error occurred; 
   * do andnot errcontinue indicatesprocessing.
 what went wrong  */
}
/* ... */
f();
/* ifIf we get here, no errors occurred */
/* ... */

Calls to f() will either succeed , or divert control into to an if
clause designed to catch the error.

  • Source The source code will is not become significantly larger , because the function
    signatures do not change, and neither do functions that neither detect
    nor handle the error.
  • Allocated resources must still be freed despite the error.
  • Requires The application to must call setjmp() before invoking
    application-independent code.
  • Signals are not necessarily preserved through longjmp() calls.
  • The use of setjmp()/longjmp() bypasses the normal function
    call and return discipline.
  • Any function that allocates resources must ensure they are freed incases in cases where errors occur.

Summary

The following table summarizes the characteristics of error-reporting and error-detection mechanisms.

Method

Code Increase

Manages Allocated Resources

Automatically Enforceable

...

Return

Value

value

Big (

30-40%

30–40%)

no

No

yes

Yes

Address

Argument

argument

Bigger

no

No

no

No

Global

Indicator

indicator

Medium

no

No

yes

Yes

longjmp()

Small

no

No

n/a

Risk

...

Assessment

A lack Lack of an error-detection mechanism prevents applications from knowing
when an error has disrupted normal program behavior.

Recommendation

Severity

Likelihood

Remediation Cost

Priority

...

Level

...

ERR05-

A

high

likely

high

P9

L2 |

Related Vulnerabilities

Search for vulnerabilities resulting from the violation of this rule
on the [CERT
website|https://www.kb.cert.org/vulnotes/bymetric?searchview&query=FIELD+KEYWORDS+contains+ERR05-A].

References

Wiki Markup
\[[Miller 04|AA. C References#Miller 04]\]
\[[Saks 07b|AA. C References#Saks 07b]\]

C

Medium

Probable

High

P4

L3

Automated Detection

Tool

Version

Checker

Description

Compass/ROSE



Could detect violations of this rule merely by reporting functions that call abort(), exit(), or _Exit() inside an if or switch statement.
This would also catch many false positives, as ROSE could not distinguish a library function from an application function

Parasoft C/C++test
Include Page
Parasoft_V
Parasoft_V

CERT_C-ERR05-a
CERT_C-ERR05-b
CERT_C-ERR05-c

The 'abort()' function from the 'stdlib.h' or 'cstdlib' library shall not be used
The 'exit()' function from the 'stdlib.h' or 'cstdlib' library shall not be used
The 'quick_exit()' and '_Exit()' functions from the 'stdlib.h' or 'cstdlib' library shall not be u

Related Vulnerabilities

Search for vulnerabilities resulting from the violation of this rule on the CERT website.

Related Guidelines

Bibliography


...

Image Added Image Added Image Added*[Image Removed|ERR04-A.
Choose an appropriate termination
strategy]*      *[!CERT C Secure
Coding Standard^button_arrow_up.png!|12. Error Handling
(ERR)]*       *[!CERT C Secure Coding
Standard^button_arrow_right.png!|ERR30-C. Set errno to zero before
calling a function, and use it only after the function returns a value
indicating failure]*