Main Content

CERT C: Rec. CON08-C

R2026b

Do not assume that a group of calls to independently atomic methods is atomic

Since R2026b

Description

Do not assume that a group of calls to independently atomic methods is atomic1

Polyspace Implementation

Polyspace® checks for the issue Incorrect assumption of atomicity.

Examples

expand all

Issue

The issue occurs when your code assumes a group of atomic function calls to be atomic as a group. For example, consider this code:

extern int atomicFuncA();
extern int atomicFuncB();

// called by multiple threads
void foo(){
  int var = atomicFuncA() + atomicFuncB()
}
The functions atomicFuncA() and atomicFuncB() are atomic operations. The function foo() assumes that atomicFuncA() + atomicFuncB() is also atomic and invokes the functions without holding a common lock across both calls, which results in a violation of this rule.

Risk

Calling a group of atomic functions without a common lock can result in a data race. In the preceding code, because there is no common lock across the calls to the atomic functions, it is possible that each function uses a value from a different thread, which can lead to an in incorrect result.

Fix

Hold a common lock across a sequence of atomic function calls.. For example, acquire the common mutex before calling atomicFuncA() and keep it locked until after atomicFuncB() returns.

Example

In this example, two functions set_values() and get_sum() each acquire and release a mutex internally. A worker calls them sequentially without holding a lock across both calls. As a group, the pair of calls is not atomic and can be interleaved by other threads.


#include <stdio.h>
#include <threads.h>

static int a = 0;
static int b = 0;
static mtx_t mtx;

void set_values(int na, int nb) {
    mtx_lock(&mtx);
    a = na;    // protected by internal lock
    b = nb;    // protected by internal lock
    mtx_unlock(&mtx);
}

int get_sum(void) {
    mtx_lock(&mtx);
    int s = a + b;  // protected by internal lock
    mtx_unlock(&mtx);
    return s;
}

typedef struct {
    int x;
    int y;
} worker_args;

int worker_nonatomic(void *arg) {
    worker_args *args = (worker_args *)arg;
    set_values(args->x, args->y);  
    int s = get_sum();             
    printf("sum = %d\n", s);
    return 0;
}

int main(void) {
    mtx_init(&mtx, mtx_plain);

    worker_args args1 = {2, 5};
    worker_args args2 = {10, 20};

    thrd_t t1, t2;
    thrd_create(&t1, worker_nonatomic, &args1); // Noncompliant
    thrd_create(&t2, worker_nonatomic, &args2); // Noncompliant

    thrd_join(t1, NULL);
    thrd_join(t2, NULL);

    mtx_destroy(&mtx);
    return 0;
}
Correction

Acquire a single lock that spans the entire sequence of operations that must be atomic, or provide a combined function that performs both operations while holding the lock.


#include <stdio.h>
#include <threads.h>

static int a = 0;
static int b = 0;
static mtx_t mtx;

void set_values(int na, int nb) {
    a = na;
    b = nb;
}

int get_sum(void) {
    return a + b;
}

typedef struct {
    int x;
    int y;
} worker_args;

int worker_atomic(void *arg) {
    worker_args *args = (worker_args *)arg;

    mtx_lock(&mtx);
    set_values(args->x, args->y);  // Now atomic with get_sum
    int s = get_sum();             
    mtx_unlock(&mtx);

    printf("sum = %d\n", s);
    return 0;
}

int main(void) {
    mtx_init(&mtx, mtx_plain);

    worker_args args1 = {2, 5};
    worker_args args2 = {10, 20};

    thrd_t t1, t2;
    thrd_create(&t1, worker_atomic, &args1);   // Compliant
    thrd_create(&t2, worker_atomic, &args2);   // Compliant

    thrd_join(t1, NULL);
    thrd_join(t2, NULL);

    mtx_destroy(&mtx);
    return 0;
}

Check Information

Group: Rec. 14. Concurrency (CON)
PQL Name: std.cert.CON08_C

Version History

Introduced in R2026b


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.