AUTOSAR C++14 Rule M0-3-2

If a function generates error information, then that error information shall be tested

Description

Rule Definition

If a function generates error information, then that error information shall be tested.

Rationale

If you do not check the return value of functions that indicate error information through their return values, your program can behave unexpectedly. Errors from these functions can propagate throughout the program causing incorrect output, security vulnerabilities, and possibly system failures.

For the errno-setting functions, to see if the function call completed without errors, check errno for error values. The return values of these errno-setting functions do not indicate errors. The return value can be one of the following:

  • void

  • Even if an error occurs, the return value can be the same as the value from a successful call. Such return values are called in-band error indicators. For instance, strtol converts a string to a long integer and returns the integer. If the result of conversion overflows, the function returns LONG_MAX and sets errno to ERANGE. However, the function can also return LONG_MAX from a successful conversion. Only by checking errno can you distinguish between an error and a successful conversion.

For the errno-setting functions, you can determine if an error occurred only by checking errno.

Polyspace Implementation

The checker raises a violation when:

  • You call sensitive standard functions that return information about possible errors and you do one of the following:

    • Ignore the return value.

      You simply do not assign the return value to a variable, or explicitly cast the return value to void.

    • Use an output from the function (return value or argument passed by reference) without testing the return value for errors.

    The checker considers a function as sensitive if the function call is prone to failure because of reasons such as:

    • Exhausted system resources (for example, when allocating resources).

    • Changed privileges or permissions.

    • Tainted sources when reading, writing, or converting data from external sources.

    • Unsupported features despite an existing API.

    Some of these functions can perform critical tasks such as:

    • Set privileges (for example, setuid)

    • Create a jail (for example, chroot)

    • Create a process (for example, fork)

    • Create a thread (for example, pthread_create)

    • Lock or unlock mutex (for example, pthread_mutex_lock)

    • Lock or unlock memory segments (for example, mlock)

    For functions that are not critical, the checker allows casting the function return value to void.

  • You call a function that sets errno to indicate error conditions, but do not check errno after the call. For these functions, checking errno is the only reliable way to determine if an error occurred.

    Functions that set errno on errors include:

    • fgetwc, strtol, and wcstol.

      For a comprehensive list of functions, see documentation about errno.

    • POSIX® errno-setting functions such as encrypt and setkey.

Troubleshooting

If you expect a rule violation but do not see it, refer to Coding Standard Violations Not Displayed.

Examples

expand all

#include <pthread.h>
#include <cstdlib>
#define fatal_error() abort()

void initialize_1() {
    pthread_attr_t attr;
    pthread_attr_init(&attr); //Noncompliant
}

void initialize_2() {
    pthread_attr_t attr;
   (void)pthread_attr_init(&attr); //Compliant
}

void initialize_3() {
    pthread_attr_t attr;
    int result;
    result = pthread_attr_init(&attr); //Compliant
    if (result != 0) {
        /* Handle error */
        fatal_error();
    }
}

This example shows a call to the sensitive function pthread_attr_init. The return value of pthread_attr_init is ignored, causing a rule violation.

To be compliant, you can explicitly cast the return value to void or test the return value of pthread_attr_init and check for errors.

#include <pthread.h>
#include <cstdlib>
#define fatal_error() abort()
extern void *start_routine(void *);

void returnnotchecked_1() {
    pthread_t thread_id;
    pthread_attr_t attr;
    void *res;

    (void)pthread_attr_init(&attr);
    (void)pthread_create(&thread_id, &attr, &start_routine, ((void *)0)); //Noncompliant
    pthread_join(thread_id,  &res); //Noncompliant
}

void returnnotchecked_2() {
    pthread_t thread_id;
    pthread_attr_t attr;
    void *res;
    int result;

    (void)pthread_attr_init(&attr);
    result = pthread_create(&thread_id, &attr, &start_routine, NULL); //Compliant
    if (result != 0) {
        /* Handle error */
        fatal_error();
    }

    result = pthread_join(thread_id,  &res); //Compliant
    if (result != 0) {
        /* Handle error */
        fatal_error();
    }
}

In this example, two critical functions are called: pthread_create and pthread_join. The return value of the pthread_create is ignored by casting to void, but because pthread_create is a critical function (not just a sensitive function), the rule checker still raises a violation. The other critical function, pthread_join, returns a value that is ignored implicitly.

To be compliant, check the return value of these critical functions to verify the function performed as expected.

#include<cstdlib>
#include<cerrno>
#include<climits>
#include<iostream>

int main(int argc, char *argv[]) {
    char *str, *endptr;
    int base;
    
    str = argv[1];
    base = 10;
    
    long val = strtol(str, &endptr, base); //Noncompliant
    std::cout<<"Return value of strtol() = %ld\n" << val;
    
    errno = 0;
    long val2 = strtol(str, &endptr, base); //Compliant
    if((val2 == LONG_MIN || val2 == LONG_MAX) && errno == ERANGE) {
         std::cout<<"strtol error";
         exit(EXIT_FAILURE);
    }        
    std::cout<<"Return value of strtol() = %ld\n" << val2;
}

In the noncompliant example, the return value of strtol is used without checking errno.

To be compliant, before calling strtol, set errno to zero . After a call to strtol, check the return value for LONG_MIN or LONG_MAX and errno for ERANGE.

Check Information

Group: Language independent issues
Category: Required, Non-automated
Introduced in R2020b