Main Content

Atomic load and store sequence not atomic

Variable accessible between load and store operations

Description

This defect occurs when you use these functions to load, and then store an atomic variable.

  • C functions:

    • atomic_load()

    • atomic_load_explicit()

    • atomic_store()

    • atomic_store_explicit()

  • C++ functions:

    • std::atomic_load()

    • std::atomic_load_explicit()

    • std::atomic_store()

    • std::atomic_store_explicit()

    • std::atomic::load()

    • std::atomic::store()

A thread cannot interrupt an atomic load or an atomic store operation on a variable, but a thread can interrupt a store, and then load sequence.

Risk

A thread can modify a variable between the load and store operations, resulting in a data race condition.

Fix

To read, modify, and store a variable atomically, use a compound assignment operator such as +=, atomic_compare_exchange() or atomic_fetch_*-family functions.

Examples

expand all


#include <stdatomic.h>
#include <stdbool.h>

static atomic_bool flag = ATOMIC_VAR_INIT(false);

void init_flag(void)
{
    atomic_init(&flag, false);
}

void toggle_flag(void)
{
    bool temp_flag = atomic_load(&flag);
    temp_flag = !temp_flag;
    atomic_store(&flag, temp_flag);
}

bool get_flag(void)
{
    return atomic_load(&flag);
}

In this example, variable flag of type atomic_bool is referenced twice inside the toggle_flag() function. The function loads the variable, negates its value, then stores the new value back to the variable. If two threads call toggle_flag(), the second thread can access flag between the load and store operations of the first thread. flag can end up in an incorrect state.

Correction — Use Compound Assignment to Modify Variable

One possible correction is to use a compound assignment operator to toggle the value of flag. The C standard defines the operation by using ^= as atomic.


#include <stdatomic.h>
#include <stdbool.h>

static atomic_bool flag = ATOMIC_VAR_INIT(false);

void toggle_flag(void)
{
    flag ^= 1;
}

bool get_flag(void)
{
    return flag;
}

Result Information

Group: Concurrency
Language: C | C++
Default: On for handwritten code, off for generated code
Command-Line Syntax: ATOMIC_VAR_SEQUENCE_NOT_ATOMIC
Impact: Medium

Version History

Introduced in R2018b