JavaScript is not currently enabled, but is required for full CodeSonar manual search and browse functionality.

If you are viewing this file in your hub's Web GUI, enable JavaScript in your browser: you will also need it for GUI functionality.

If you opened this file directly from disk, your browser may be directly suppressing JavaScript functionality: certain browsers perform this suppression on local files (but not files delivered by web servers) for security reasons.

CodeSonar® 9.2p0 CONFIDENTIAL CodeSecure Inc
C and C++

Concurrency Models: Thread Entry Points

One of the critical components of data race detection is the identification of thread entry points: the procedures or methods that start executing in newly-created threads. If CodeSonar cannot identify all the thread entry points in a project, it will generally not be able to detect all locations where a data race can occur.

Signal handler entry points are also identified: signal handlers are essentially treated as a special kind of thread.



Thread Entry Points

The functions that CodeSonar will treat as thread entry points can be divided into four categories:

Standard Program Entry Functions

CodeSonar always treats the following program entry functions as thread entry points:

Functions Specified with Configuration Parameters

There are two relevant configuration parameters.

Modeled Library Functions: Thread Entry Points

CodeSonar ships with library models that allow it to recognize a large number of thread entry point functions. A call to one of these functions will trigger a Thread Entry Point warning (when that class is enabled). Some examples are listed in the following table

Thread entry point functions include...
Apache Portable Runtime (APR) apr_thread_create()
ARINC 653 CREATE_PROCESS()
CMX-RTX K_Task_Create()
FreeRTOS xTaskCreate()
libc g_thread_create()
Linux Kernel kernel_thread()
Mac OS X kernel_thread_start()
Win32/MFC AfxBeginThread()
Netscape Portable Runtime (NSPR) PR_CreateThread()
Qt QThread::start()
ThreadX _tx_thread_create()
uC/OS-III OSTaskCreate()
VxWorks taskInit()
Win32 CreateThread()
wxWidgets wxThread::Create()

Modeled Library Functions: Signal Handler Entry Points

CodeSonar ships with library models that allow it to identify functions such as libc signal() as signal handler entry points. A call to one of these functions will trigger a Signal Handler Entry Point warning (when that class is enabled).

Creating New Models

If you are authoring a model for a function that specifies a thread entry point or signal handler entry point, it is usually best to have the model call the already-modeled function that is most similar. This will ensure that CodeSonar correctly treats the function as specifying an entry point, and includes it in the appropriate checks.

If no existing model is appropriate, write your model using the extension functions provided. In particular, your model should call one of the following functions.

csonar_thread_create() Indicates a thread entry point.
csonar_sighand_create() Indicates a signal handler entry point. It can also be useful for modeling interrupts.

See the function documentation for annotated examples.

Discovering Entry Points

CodeSonar will identify thread entry points if the Data Race warning class is enabled.

The two most likely causes of a failure in entry point discovery are time limits and library modeling issues. If you suspect that CodeSonar has not discovered all the thread entry points in your project:

  1. Open the analysis log.
  2. Search for the text
    Thread entry points:
    Below that heading is a list of the procedures and methods that have been identified as thread entry points, along with various other information.
  3. Check the list of identified thread entry points.

Alternatively, enable warning class Thread Entry Point, so that CodeSonar issues a warning at every identified thread entry point.

For example, the following simple program has two thread entry points: main() and entry_f().

#include <pthread.h>

int x;

void *entry_f( void *a ){
    x = 5;
    return a;
}

int main( int argc, char** argv ){
    pthread_t t;
    pthread_create( &t, NULL, entry_f, NULL );
    x = 4;
    return argc;
}

CodeSonar identifies both entry points:

The relevant part of the analysis log looks (something) like the following.

[...]
Thread entry points:
Thread entry point: entry_f
  lockset map: 0x7fffec1b1318

           [MAK_READ:global_locks #locks: 0 #path_dags: 1 ls:{ }]
           [MAK_WRITE:x #locks: 0 #path_dags: 1 ls:{ }]
           [MAK_WRITE:global_locks-&next #locks: 0 #path_dags: 1 ls:{ }]
             
Thread entry point: main
  lockset map: 0x7ffff7efcbb0

           [MAK_WRITE:x #locks: 0 #path_dags: 1 ls:{ }]
[...]
  

Time limits

Enabling data race detection increases the amount of information that the CodeSonar analysis must gather and store. This can cause various steps in the analysis process to take more time. In some cases, they can take so long that analysis time limits expire, causing CodeSonar to drop data that is needed to identify thread entry points properly. To maintain high precision and ensure that thread entry points are discovered, you may need to increase some of these time limits.

The time limits that are most important to thread entry point discovery are governed by configuration file parameters:

To determine whether time limit expiration is affecting thread entry point discovery for your project:

  1. Open the analysis log.
  2. Search for the text
    TIME_LIMIT_
    This will find all the reports of configured time limits expiring.
  3. If you see many expirations of any of the time limits that are important to thread entry point discovery:
    1. increase the corresponding settings in your general project configuration file, then
    2. run the analysis again.

Library modeling issues

If CodeSonar did not discover any thread entry points (or only main()), there is probably a library modeling issue.

A critical element of thread discovery is identifying thread creation procedures, including understanding how their arguments are used to specify a thread starting point. This requires that library models be provided for thread creation procedures. If a model for your thread creation procedure is not shipped with CodeSonar, you will need to create a model or directly modify your code.

Example

It is relatively common for large code bases to include their own thread entry point wrappers. These wrappers make it hard for CodeSonar to identify true thread entry points, and are themselves candidates for modeling.

Here is a small example:

/* Code Excerpt 1: User code with wrappers. */

/* underlying API function: real_thread_create()
 * thread creation wrapper: thread_create_wrapper()
 * thread entry point: user_thread_entry_point()
 * thread entry wrapper: thread_entry_wrapper()

typedef struct{
   function_pointer f;
   data_pointer d;
} thread_entry_closure;

void thread_entry_wrapper( thread_entry_closure *c ){
   /* ... additional thread setup code */
   c->f( c->d );
   /* ... additional thread teardown code */
}

void thread_create_wrapper( function_pointer fp, data_pointer dp )
{
  thread_entry_closure c = { fp, dp };
  real_thread_create( thread_entry_wrapper, &c );
}

void user_thread_entry_point( data_pointer d ){
   /* ... code that runs in a separate thread */
}

void other_user_code( void ){
  thread_create_wrapper( user_thread_entry_point, xyz );
}

To handle this kind of code, you need to inform CodeSonar that

You can do this either by creating a library model for thread_create_wrapper(), or by directly modifying the source code:

/* Code Excerpt 2: Direct source modification for Code Excerpt 1. */

#ifdef __CODESONAR__
#include <stdlib.h>
#include "csonar.h"
#endif

void thread_create_wrapper( function_pointer fp, data_pointer dp )
{
#ifdef __CODESONAR__
   csonar_thread_create( *((csonar_thread_entry_fn_t*)&fp), dp );
#endif
   thread_entry_closure c = { fp, dp };
   real_thread_create( thread_entry_wrapper, &c );
}
 

To report problems with this documentation, please visit https://support.codesecure.com/.