...
- A return value (especially of type
errno_t) - An argument passed by address
- A global object (e.g., such as
errno) longjmp()- Some combination of the above
...
| Code Block | ||||
|---|---|---|---|---|
| ||||
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.
“Smart Libraries,” Practice 23 [Miller 2004], says:
...
| Code Block | ||||
|---|---|---|---|---|
| ||||
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 != 0) {
return status;
}
/* ... doDo the rest of f ... */
return 0;
}
|
...
A return type of errno_t indicates that the function returns a status indicator . (See see DCL09-C. Declare functions that return errno with a return type of errno_t).)
This error-handling approach is secure, but it has the following drawbacks:
- Source and object code can significantly increase in size, perhaps some sources suggest by as much as 30 as 30 to 40 percent [Saks 2007b].
- All function return values must be checked . (See MEM32see ERR33-C. Detect and handle memory allocation standard library errors).)
- Functions should not return other values if they return error indicators . (See see ERR02-C. Avoid in-band error indicators).)
- Any function that allocates resources must ensure they are freed in cases where errors occur.
...
| Code Block | ||||
|---|---|---|---|---|
| ||||
const errno_t ESOMETHINGREALLYBAD = 1;
void g(errno_t * err) {
if (err == NULL) {
/* Handle null pointer */
}
/* ... */
if (something_really_bad_happens) {
*err = ESOMETHINGREALLYBAD;
} else {
/* ... */
*err = 0;
}
}
void f(errno_t * err) {
if (err == NULL) {
/* Handle null pointer */
}
g(err);
if (*err == 0) {
/* ... doDo the rest of f ... */
}
return 0;
}
|
...
- A return status can be returned only if the caller provides a valid pointer to an object of type
errno_t. If this argument isNULL, there is no way to indicate this error. - Source code becomes even 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 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.
...
| Code Block | ||||
|---|---|---|---|---|
| ||||
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 that is 0 upon success and a nonzero value upon failure.
...
| Code Block | ||||
|---|---|---|---|---|
| ||||
#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 ... */
}
/* ... */
if (setjmp(exception_env) != 0) {
/*
* If we get here, an error occurred;
* do not continue processing.
*/
}
/* ... */
f();
/* If we get here, no errors occurred */
/* ... */
|
...
The following table summarizes the characteristics of error-reporting and error-detection mechanisms.
Method | Code Increase | Manages Allocated Resources | Automatically Enforceable |
|---|---|---|---|
Return value | Big (30–40%) | No | Yes |
Address argument | Bigger | No | No |
Global indicator | Medium | No | Yes |
| Small | No | n/a |
Risk Assessment
Lack of an error-detection mechanism prevents applications from knowing when an error has disrupted normal program behavior.
Recommendation | Severity | Likelihood | Detectable |
|---|
Repairable | Priority | Level |
|---|---|---|
ERR05-C | Medium |
Probable |
Yes |
No |
P8 |
L2 |
Automated Detection
Tool | Version | Checker | Description |
|---|---|---|---|
| Compass/ROSE |
Could detect violations of this rule merely by reporting functions that call | |||||||||
| Parasoft C/C++test |
| CERT_C-ERR05-a | The 'abort()' function from the 'stdlib.h' or 'cstdlib' library shall not be used | ||||||
| Security Reviewer - Static Reviewer |
| C32 | Fully implemented |
Related Vulnerabilities
Search for vulnerabilities resulting from the violation of this rule on the CERT website.
Related Guidelines
| SEI CERT C++ |
| Coding Standard | VOID ERR05-CPP. Application-independent code should provide error detection without dictating error handling |
Bibliography
...
...