sqc 0.4.13

Software Code Quality - CERT C compliance checker
[metadata]
id = "CON07-C"
type = "recommendation"
category = "CON"
number = 7
title = "Ensure that compound operations on shared variables are atomic"
description = """
Compound operations are operations that consist of more than one discrete
operation. Expressions that include postfix or prefix increment (++), postfix or
prefix decrement (--), or compound assignment operators always result in
compound operations. Compound assignment expressions use operators such
as*=,/=,%=,+=,-=,<<=,>>=,^=, and|=. Compound operations on shared variables must
be performed atomically to preventdata races.Noncompliant Code Example (Logical
Negation)This noncompliant code example declares a shared_Boolflagvariable and
provides atoggle_flag()method that negates the current value offlag:#include
<stdbool.h> static bool flag = false; void toggle_flag(void) { flag = !flag; }
bool get_flag(void) { return flag; }Execution of this code may result in adata
racebecause the value offlagis read, negated, and written back.Consider, for
example, two threads that calltoggle_flag(). The expected effect of
togglingflagtwice is that it is restored to its original value. However, the
following scenario leavesflagin the incorrect
state:Timeflag=ThreadAction1truet1Reads the current value offlag,true, into a
cache2truet2Reads the current value offlag, (still)true, into a different
cache3truet1Toggles the temporary variable in the cache tofalse4truet2Toggles
the temporary variable in the different cache tofalse5falset1Writes the cache
variable's value toflag6falset2Writes the different cache variable's value
toflagAs a result, the effect of the call byt2is not reflected inflag; the
program behaves as iftoggle_flag()was called only once, not twice.Compliant
Solution (Mutex)This compliant solution restricts access toflagunder a mutex
lock:#include <threads.h> #include <stdbool.h> static bool flag = false; mtx_t
flag_mutex; /* Initialize flag_mutex */ bool init_mutex(int type) { /* Check
mutex type */ if (thrd_success != mtx_init(&flag_mutex, type)) { return false;
/* Report error */ } return true; } void toggle_flag(void) { if (thrd_success !=
mtx_lock(&flag_mutex)) { /* Handle error */ } flag = !flag; if (thrd_success !=
mtx_unlock(&flag_mutex)) { /* Handle error */ } } bool get_flag(void) { bool
temp_flag; if (thrd_success != mtx_lock(&flag_mutex)) { /* Handle error */ }
temp_flag = flag; if (thrd_success != mtx_unlock(&flag_mutex)) { /* Handle error
*/ } return temp_flag; }This solution guards reads and writes to theflagfield
with a lock on theflag_mutex. This lock ensures that changes toflagare visible
to all threads. Now, only two execution orders are possible. In one execution
order, t1obtains the mutex and completes the operation beforet2can acquire the
mutex, as shown here:Timeflag=ThreadAction1truet1Reads the current value
offlag,true, into a cache variable2truet1Toggles the cache variable
tofalse3falset1Writes the cache variable's value toflag4falset2Reads the current
value offlag,false, into a different cache variable5falset2Toggles the different
cache variable totrue6truet2Writes the different cache variable's value
toflagThe other execution order is similar, except thatt2starts and finishes
beforet1.Compliant Solution (atomic_compare_exchange_weak())This compliant
solution uses atomic variables and a compare-and-exchange operation to guarantee
that the correct value is stored inflag. All updates are visible to other
threads.#include <stdatomic.h> #include <stdbool.h> static atomic_bool flag;
void init_flag(void) { atomic_init(&flag, false); } void toggle_flag(void) {
bool old_flag = atomic_load(&flag); bool new_flag; do { new_flag = !old_flag; }
while (!atomic_compare_exchange_weak(&flag, &old_flag, new_flag)); } bool
get_flag(void) { return atomic_load(&flag); }An alternative solution is to use
theatomic_flagdata type for managing Boolean values atomically.Noncompliant Code
Example (Addition of Primitives)In this noncompliant code example, multiple
threads can invoke theset_values()method to set theaandbfields. Because this
code fails to test for integer overflow, users of this code must also ensure
that the arguments to theset_values()method can be added without overflow
(seeINT32-C. Ensure that operations on signed integers do not result in
overflowfor more information).static int a; static int b; int get_sum(void) {
return a + b; } void set_values(int new_a, int new_b) { a = new_a; b = new_b;
}Theget_sum()method contains a race condition. For example, whenaandbcurrently
have the values0andINT_MAX, respectively, and one thread callsget_sum()while
another callsset_values(INT_MAX, 0), theget_sum()method might return
either0orINT_MAX, or it might overflow. Overflow will occur when the first
thread readsaandbafter the second thread has set the value ofatoINT_MAXbut
before it has set the value ofbto0.Noncompliant Code Example (Addition of Atomic
Integers)In this noncompliant code example,aandbare replaced with atomic
integers.#include <stdatomic.h> static atomic_int a; static atomic_int b; void
init_ab(void) { atomic_init(&a, 0); atomic_init(&b, 0); } int get_sum(void) {
return atomic_load(&a) + atomic_load(&b); } void set_values(int new_a, int
new_b) { atomic_store(&a, new_a); atomic_store(&b, new_b); }The simple
replacement of the twointfields with atomic integers fails to eliminate the race
condition in the sum because the compound operationa.get() + b.get()is still
non-atomic. While a sum of some value ofaand some value ofbwill be returned,
there is no guarantee that this value represents the sum of the values ofaandbat
any particular moment.Compliant Solution (_Atomic struct)This compliant solution
uses an atomic struct, which guarantees that both numbers are read and written
together.#include <stdatomic.h> static _Atomic struct ab_s { int a, b; } ab;
void init_ab(void) { struct ab_s new_ab = {0, 0}; atomic_init(&ab, new_ab); }
int get_sum(void) { struct ab_s new_ab = atomic_load(&ab); return new_ab.a +
new_ab.b; } void set_values(int new_a, int new_b) { struct ab_s new_ab = {new_a,
new_b}; atomic_store(&ab, new_ab); }On most modern platforms, this will compile
to be lock-free.Compliant Solution (Mutex)This compliant solution protects
theset_values()andget_sum()methods with a mutex to ensure atomicity:#include
<threads.h> #include <stdbool.h> static int a; static int b; mtx_t flag_mutex;
/* Initialize everything */ bool init_all(int type) { /* Check mutex type */ a =
0; b = 0; if (thrd_success != mtx_init(&flag_mutex, type)) { return false; /*
Report error */ } return true; } int get_sum(void) { if (thrd_success !=
mtx_lock(&flag_mutex)) { /* Handle error */ } int sum = a + b; if (thrd_success
!= mtx_unlock(&flag_mutex)) { /* Handle error */ } return sum; } void
set_values(int new_a, int new_b) { if (thrd_success != mtx_lock(&flag_mutex)) {
/* Handle error */ } a = new_a; b = new_b; if (thrd_success !=
mtx_unlock(&flag_mutex)) { /* Handle error */ } }Thanks to the mutex, it is now
possible to add overflow checking to theget_sum()function without introducing
the possibility of a race condition.Risk AssessmentWhen operations on shared
variables are not atomic, unexpected results can be produced. For example,
information can be disclosed inadvertently because one user can receive
information about other users.RuleSeverityLikelihoodDetectableRepairablePriority
LevelCON07-CMediumProbableYesNoP8L2Automated
DetectionToolVersionCheckerDescriptionCodeSonar9.1p0CONCURRENCY.DATARACEData
RaceHelix QAC2025.2C1765C1114C1115C1116Related GuidelinesCERT Oracle Secure
Coding Standard for JavaVNA02-J. Ensure that compound operations on shared
variables are atomicMITRE CWECWE-366, Race condition within a
threadCWE-413,Improper resource lockingCWE-567,Unsynchronized access to shared
data in a multithreaded contextCWE-667, Improper lockingBibliography[ISO/IEC
14882:2011]Subclause 7.17, "Atomics"
"""
severity = "Medium"
likelihood = "Probable"
priority = "P8"
level = "L2"
cert_version = "2016 Edition (Wiki)"
last_modified = "Jul 24, 2025"

[rules.cert_c.CON07-C]
enabled = true

[references]
wiki = "https://wiki.sei.cmu.edu/confluence/display/c/CON07-C.+Ensure+that+compound+operations+on+shared+variables+are+atomic"
cwe = ["CWE-366", "CWE-413", "CWE-567", "CWE-667"]