Main Content

CERT C: Rec. API04-C

Provide a consistent and usable error-checking mechanism

Description

Rule Definition

Provide a consistent and usable error-checking mechanism.1

Polyspace Implementation

The rule checker checks for Returned value of a sensitive function not checked.

Examples

expand all

Issue

This issue occurs when you call sensitive standard functions, but you:

  • Ignore the return value.

  • Use an output or a return value without testing the validity of the return value.

For this defect, two type of functions are considered: sensitive and critical sensitive.

A sensitive function is a standard function that can encounter:

  • 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

A critical sensitive function is a sensitive function that performs one of these critical or vulnerable tasks:

  • 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)

Risk

If you do not check the return value of functions that perform sensitive or critical sensitive tasks, your program can behave unexpectedly. Errors from these functions can propagate throughout the program causing incorrect output, security vulnerabilities, and possibly system failures.

Fix

Before continuing with the program, test the return value of critical sensitive functions.

For sensitive functions, you can explicitly ignore a return value by casting the function to void. Polyspace® does not raise this defect for sensitive functions cast to void. This resolution is not accepted for critical sensitive functions because they perform more vulnerable tasks.

Example – Sensitive Function Return Ignored
#include <pthread.h>

void initialize() {
    pthread_attr_t attr;

    pthread_attr_init(&attr);  //Noncompliant
}

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

Correction 1 – Cast Function to (void)

One possible correction is to cast the function to void. This fix informs Polyspace and any reviewers that you are explicitly ignoring the return value of the sensitive function.

#include <pthread.h>

void initialize() {
    pthread_attr_t attr;

    (void)pthread_attr_init(&attr); 
}
Correction 2 – Test Return Value

One possible correction is to test the return value of pthread_attr_init to check for errors.

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

void initialize() {
    pthread_attr_t attr;
    int result;

    result = pthread_attr_init(&attr);
    if (result != 0) {
        /* Handle error */
        fatal_error();
    }
}
Example – Critical Function Return Ignored
#include <pthread.h>
extern void *start_routine(void *);

void returnnotchecked() {
    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
}

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), Polyspace does not ignore this Return value of a sensitive function not checked defect. The other critical function, pthread_join, returns value that is ignored implicitly. pthread_join uses the return value of pthread_create, which was not checked.

Correction — Test the Return Value of Critical Functions

The correction for this defect is to check the return value of these critical functions to verify the function performed as expected.

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

extern void *start_routine(void *);

void returnnotchecked() {
    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);
    if (result != 0) {
        /* Handle error */
        fatal_error();
    }

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

Check Information

Group: Rec. 13. Application Programming Interfaces (API)

Version History

Introduced in R2019a


1 This software has been created by MathWorks incorporating portions of: the “SEI CERT-C Website,” © 2017 Carnegie Mellon University, the SEI CERT-C++ Web site © 2017 Carnegie Mellon University, ”SEI CERT C Coding Standard – Rules for Developing safe, Reliable and Secure systems – 2016 Edition,” © 2016 Carnegie Mellon University, and “SEI CERT C++ Coding Standard – Rules for Developing safe, Reliable and Secure systems in C++ – 2016 Edition” © 2016 Carnegie Mellon University, with special permission from its Software Engineering Institute.

ANY MATERIAL OF CARNEGIE MELLON UNIVERSITY AND/OR ITS SOFTWARE ENGINEERING INSTITUTE CONTAINED HEREIN IS FURNISHED ON AN "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY KIND, EITHER EXPRESSED OR IMPLIED, AS TO ANY MATTER INCLUDING, BUT NOT LIMITED TO, WARRANTY OF FITNESS FOR PURPOSE OR MERCHANTABILITY, EXCLUSIVITY, OR RESULTS OBTAINED FROM USE OF THE MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT MAKE ANY WARRANTY OF ANY KIND WITH RESPECT TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT.

This software and associated documentation has not been reviewed nor is it endorsed by Carnegie Mellon University or its Software Engineering Institute.