CERT.CONC.ATOMIC_COMP_FAIL_IN_LOOP

Wrap functions that can spuriously fail up in a loop.

Vulnerability and risk

Failing to wrap the atomic_compare_exchange_weak() and atomic_compare_exchange_weak_explicit() functions in a loop can result in incorrect values and control flow.

Vulnerable code example

struct data {
    struct data *next;
    /* ... */
};

extern void cleanup_data_structure(struct data *head);

int reorganize_data_structure(void *thread_arg) {
    struct data *_Atomic *ptr_to_head = thread_arg;
    struct data *old_head = atomic_load(ptr_to_head);
    struct data *new_head;
    bool success;

    /* ... Reorganize the data structure ... */

    success = atomic_compare_exchange_weak(ptr_to_head,
    &old_head, new_head);
    if (!success) {
        cleanup_data_structure(new_head);
    }
    return success; /* Exit the thread */
}

In this noncompliant code example, reorganize_data_structure() is to be used as an argument to thrd_create(). After reorganizing, the function attempts to replace the head pointer so that it points to the new version. If no other thread has changed the head pointer since it was originally loaded, reorganize_data_structure() is intended to exit the thread with a result of true, indicating success. Otherwise, the new reorganization attempt is discarded and the thread is exited with a result of false. However, atomic_compare_exchange_weak() may fail even when the head pointer has not changed. Therefore, reorganize_data_structure() may perform the work and then discard it unnecessarily.