Main Content

MISRA C:2023 Dir 4.7

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

Since R2024a

Description

Directive Definition

If a function returns 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.

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.

The checker only considers functions where the return value indicates if the function completed without errors.

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.

This directive is only partially supported.

Troubleshooting

If you expect a rule violation but do not see it, refer to Diagnose Why Coding Standard Violations Do Not Appear as Expected.

Examples

expand all

#include <pthread.h>
#include <string.h>
#include <stddef.h>
#include <stdio.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();
    }
}

int read_file_1(int argc, char *argv[])
{
  FILE *in;
  if (argc != 2) {
    /* Handle error */
  }

  in = fmemopen (argv[1], strlen (argv[1]), "r");   
  return 0; //Noncompliant
 
}
int read_file_2(int argc, char *argv[])
{
  FILE *in;
  if (argc != 2) {
    /* Handle error */
  }

  in = fmemopen (argv[1], strlen (argv[1]), "r"); //Compliant
  if (in==NULL){
	  // Handle error
  }
  return 0; 
}

This example shows a call to the sensitive functions pthread_attr_init and fmemopen. Polyspace® raises a flag if:

  • You implicitly ignore the return of the sensitive function. Explicitly ignoring the output of sensitive functions is not flagged.

  • You obtain the return value of a sensitive function but do not test the value before exiting the relevant scope. The violation is raised on the exit statement.

To be compliant, you can explicitly cast their return value to void or test the return values to check for errors.

#include <pthread.h>
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.

Check Information

Group: Code design
Category: Required
AGC Category: Required

Version History

Introduced in R2024a