C and C++

Concurrency Models: Data Race Exclusion

Concurrency libraries may reduce or eliminate the risk of data races by guaranteeing certain properties: for example, that a particular operation is atomic, or that two different threads will never use the same memory location. CodeSonar concurrency models can account for these properties.



Excluded Variables

Extension API prototype csonar_relay_ignore() is provided so that you can indicate to the CodeSonar analysis that one or more specific global or file-static variables are exempt from data race checking.

The shipped CodeSonar library models use this mechanism to exclude special variable errno from data race checks. Modern C compilers give each thread its own copy of errno.

Thread-Local Storage Operations

Data located in thread-local storage cannot be subject to data race problems, since only one thread is accessing the data.

Thread-Local Storage Set

CodeSonar ships with library models that allow it to recognize a number of operators and functions that set values in thread-local storage. Some examples are listed below.

Functions recognized as setting values in thread-local storage include...
Apache Portable Runtime (APR) apr_threadkey_private_set()
FreeRTOS vTaskSetThreadLocalStoragePointer()
libc g_private_set()
Netscape Portable Runtime (NSPR) PR_SetThreadPrivate()
Win32 TlsAlloc()

Thread-Local Storage Get

CodeSonar ships with library models that allow it to recognize a number of operators and functions that get values in thread-local storage. Some examples are listed below.

Functions recognized as setting values in thread-local storage include...
Apache Portable Runtime (APR) apr_threadkey_private_get()
FreeRTOS pvTaskGetThreadLocalStoragePointer()
libc g_private_get()
Netscape Portable Runtime (NSPR) PR_GetThreadPrivate()
Win32 TlsGetValue()

Atomic Operations

When a particular block of code is guaranteed to be atomic (that is, to execute without interruption), memory reads and writes within that block will not participate in any data races and can be excluded from data race checks. CodeSonar models the following Win32 functions as atomic.

Win32
  InterlockedBitTestAndComplement()
  InterlockedBitTestAndComplement64()
  InterlockedBitTestAndReset()
  InterlockedBitTestAndResetAcquire()
  InterlockedBitTestAndResetRelease()
  InterlockedBitTestAndReset64()
  InterlockedBitTestAndSet()
  InterlockedBitTestAndSetAcquire()
  InterlockedBitTestAndSetRelease()
  InterlockedBitTestAndSet64()
  InterlockedCompareExchange()
  InterlockedCompareExchangeAcquire()
  InterlockedCompareExchangeRelease()
  InterlockedCompareExchangeNoFence()
  InterlockedCompareExchange16()
  InterlockedCompareExchange16Acquire()
  InterlockedCompareExchange16Release()
  InterlockedCompareExchange16NoFence()
  InterlockedCompareExchange64()
  InterlockedCompareExchange64Acquire()
  InterlockedCompareExchange64Release()
  InterlockedCompareExchange64NoFence()
  InterlockedCompareExchangePointer()
  InterlockedCompareExchangePointerAcquire(
  InterlockedCompareExchangePointerRelease()
  InterlockedCompareExchangePointerNoFence()
  InterlockedCompareExchange128()
  InterlockedCompare64Exchange128()
  InterlockedCompare64ExchangeAcquire128()
  InterlockedCompare64ExchangeRelease128()
  InterlockedCompare64ExchangeNoFence128()
  InterlockedDecrement()
  InterlockedDecrement()
  InterlockedDecrementRelease()
  InterlockedDecrementNoFence()
  InterlockedDecrement16()
  InterlockedDecrement16Acquire()
  InterlockedDecrement16Release()
  InterlockedDecrement16NoFence()
  InterlockedDecrement64()
  InterlockedDecrementAcquire64()
  InterlockedDecrementRelease64()
  InterlockedDecrementNoFence64()
  _InterlockedDecrement()
  _InterlockedDecrement_acq()
  _InterlockedDecrement_rel()
  _InterlockedDecrement16()
  _InterlockedDecrement16_acq()
  _InterlockedDecrement16_rel()
  _InterlockedDecrement64()
  _InterlockedDecrement64_acq()
  _InterlockedDecrement64_rel()
  InterlockedExchange()
  InterlockedExchangeAcquire(
  InterlockedExchangeNoFence()
  InterlockedExchange8()
  InterlockedExchange16()
  InterlockedExchange16Acquire()
  InterlockedExchange16NoFence()
  InterlockedExchange64()
  InterlockedExchangeAcquire64()
  InterlockedExchangeNoFence64()
  InterlockedExchangePointer()
  InterlockedExchangePointerAcquire()
  InterlockedExchangePointerNoFence()
  InterlockedExchangeAdd()
  InterlockedExchangeAddAcquire()
  InterlockedExchangeAddRelease()
  InterlockedExchangeAddNoFence()
  InterlockedExchangeAdd64()
  InterlockedExchangeAddAcquire64()
  InterlockedExchangeAddRelease64()
  InterlockedExchangeAddNoFence64()
  InterlockedIncrement()
  InterlockedIncrementAcquire()
  InterlockedIncrementRelease()
  InterlockedIncrementNoFence()
  nterlockedIncrement16()
  InterlockedIncrement16Acquire()
  InterlockedIncrement16Release()
  InterlockedIncrement16NoFence()
  InterlockedIncrement64()
  InterlockedIncrementAcquire64()
  InterlockedIncrementRelease64()
  InterlockedIncrementNoFence64()
  _InterlockedIncrement()
  _InterlockedIncrement_acq()
  _InterlockedIncrement_rel()
  _InterlockedIncrement16()
  _InterlockedIncrement16_acq()
  _InterlockedIncrement16_rel(
  _InterlockedIncrement64()
  _InterlockedIncrement64_acq()
  _InterlockedIncrement64_rel()

Creating New Models

If you are authoring a model, it is usually best to have the model call the already-modeled function that is most similar.

If no existing model is appropriate, write your model using the extension functions provided.