Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: changed examples to comply with coding guideline

Functions that can fail spuriously should be wrapped in a loop.  The atomic_compare_exchange_weak() and atomic_compare_exchange_weak_explicit() functions both attempt to set an atomic variable to a new value but only if it currently possesses a known old value. Unlike the related functions atomic_compare_exchange_strong() and atomic_compare_exchange_strong_explicit(), these functions are permitted to "fail spuriously," which makes them faster on some platforms. The C Standard describes this behavior in subclause 7.17.7.4, paragraph 4:

A weak compare-and-exchange operation may fail spuriously. That is, even when the contents of memory referred to by expected and object are equal, it may return zero and store back to expected the same memory contents that were originally there.

Noncompliant Code Example

This noncompliant code example calls the atomic_compare_exchange_weak() outside of a loop . 


Code Block
bgColor#FFcccc
langc
#include <threads.h>
 
<stdbool.h>
#include <stdatomic.h>
 
static atomic_bool cur;
 
void init_flag(void) {
  atomic_init(&cur, false);
}
 
void func(void) {
 init_flag();
 
 bool exp = atomic_load(&cur);
 bool des = function(!exp);
 
  if (!atomic_compare_exchange_weak(&cur, &exp, des);)) {
    /* Handle error */
  }
}

Compliant Solution (atomic_compare_exchange_weak())

A consequence of spurious failure is that nearly all uses of weak compare-and-exchange will be in a loop. This compliant solution calls the atomic_compare_exchange_weak() function from within a while loop to ensure the function does not fail spuriously.  .When  When a compare-and-exchange is in a loop, the weak version will yield better performance on some platforms.

Code Block
bgColor#ccccff
langc
#include <stdbool.h>
#include <stdatomic.h>

static atomic_bool cur;

void init_flag(void) {
  atomic_init(&cur, false);
}
 
void func(void) {
  init_flag();
 
  bool exp = atomic_load(&cur);
  bool des = !exp;
 
  do {
      des = function(!exp);
  } while (!atomic_compare_exchange_weak(&cur, &exp, des));
}

Compliant Solution (atomic_compare_exchange_strong())

When a weak compare-and-exchange would require a loop and a strong one would not, the strong one is preferable.

Code Block
bgColor#ccccff
langc
#include <stdbool.h>
#include <stdatomic.h>

static atomic_bool cur;

void init_flag(void) {
  atomic_init(&cur, false);
}
 
void func(void) {
  init_flag();
 
  bool exp = atomic_load(&cur);
  bool des = function(!exp);
 
  if (!atomic_compare_exchange_strong(&cur, &exp, des); {
    /* Handle error */
  }
}

 

Risk Assessment

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.

Rule

Severity

Likelihood

Remediation Cost

Priority

Level

CON44-C

Low

Unlikely

Medium

P2

L3

Related Guidelines

Bibliography

[ISO/IEC 9899:2011]Subclause 7.17.7.4, "The atomic_compare_exchange Generic Functions"

[Lea 2000]

1.3.2, "Liveness"
3.2.2, "Monitor Mechanics"