CERT C: Rec. CON01-C
Acquire and release synchronization primitives in the same module, at the same level of abstraction
Description
This checker is deactivated in a default Polyspace® as You Code analysis. See Checkers Deactivated in Polyspace as You Code Analysis (Polyspace Access).
Rule Definition
Acquire and release synchronization primitives in the same module, at the same level of abstraction.1
Polyspace Implementation
The rule checker checks for these issues:
Missing lock.
Missing unlock.
Double lock.
Double unlock.
Extend Checker
For the rule checker to detect issues, your code must use one of the concurrency primitives recognized by Polyspace for thread creation and shared variable protection. Otherwise, you must explicitly specify tasks, interrupts, critical sections, and other multitasking options in your project configuration. See Multitasking.
You can also extend this checker to detect synchronization issues by mapping your multithreading functions to their known POSIX® equivalents. See Extend Concurrency Defect Checkers to Unsupported Multithreading Environments.
Examples
Missing lock occurs when a task calls an unlock function before calling the corresponding lock function.
In multitasking code, a lock function begins a critical section
of code and an unlock function ends it. When a task my_task calls
a lock function my_lock, other tasks calling my_lock must
wait till my_task calls the corresponding unlock
function. Polyspace requires that both lock and unlock functions
must have the form void func(void).
To find this defect, you must specify the multitasking options before analysis. To specify these options, on the Configuration pane, select Multitasking.
A call to an unlock function without a corresponding lock function can indicate a coding error. For instance, perhaps the unlock function does not correspond to the lock function that begins the critical section.
The fix depends on the root cause of the defect. For instance, if the defect occurs because of a mismatch between lock and unlock function, check the lock-unlock function pair in your Polyspace analysis configuration and fix the mismatch.
See examples of fixes below. To avoid the
issue, you can follow the practice of calling the lock and unlock functions in
the same module at the same level of abstraction. For instance, in this example,
func calls the lock and unlock function at the same level
but func2 does
not.
void func() {
my_lock();
{
// ...
}
my_unlock();
}
void func2() {
{
my_lock();
// ...
}
my_unlock();
}If you do not want to fix the issue, add comments to your result or code to avoid another review. See:
Address Results in Polyspace User Interface Through Bug Fixes or Justifications if you review results in the Polyspace user interface.
Address Results in Polyspace Access Through Bug Fixes or Justifications (Polyspace Access) if you review results in a web browser.
Annotate Code and Hide Known or Acceptable Results if you review results in an IDE.
void begin_critical_section(void);
void end_critical_section(void);
int global_var;
void reset(void)
{
begin_critical_section();
global_var = 0;
end_critical_section();
}
void my_task(void)
{
global_var += 1;
end_critical_section(); //Noncompliant
}In this example, to emulate multitasking behavior, you must specify the following options:
| Option | Specification | |
|---|---|---|
| Configure multitasking manually | ||
| Tasks |
| |
| Critical section details | Starting routine | Ending routine |
begin_critical_section | end_critical_section | |
On the command-line, you can use the following:
polyspace-bug-finder
-entry-points my_task,reset
-critical-section-begin begin_critical_section:cs1
-critical-section-end end_critical_section:cs1The example has two entry points, my_task and reset. my_task calls end_critical_section before
calling begin_critical_section.
One possible correction is to call the lock function begin_critical_section before
the instructions in the critical section.
void begin_critical_section(void);
void end_critical_section(void);
int global_var;
void reset(void)
{
begin_critical_section();
global_var = 0;
end_critical_section();
}
void my_task(void)
{
begin_critical_section();
global_var += 1;
end_critical_section();
}
void begin_critical_section(void);
void end_critical_section(void);
int global_var;
void reset() {
begin_critical_section();
global_var=0;
end_critical_section();
}
void my_task(void) {
int index=0;
volatile int numCycles;
while(numCycles) {
if(index%10==0) {
begin_critical_section();
global_var ++;
}
end_critical_section(); //Noncompliant
index++;
}
}In this example, to emulate multitasking behavior, you must specify the following options:
| Option | Specification | |
|---|---|---|
| Configure multitasking manually | ||
| Tasks |
| |
| Critical section details | Starting routine | Ending routine |
begin_critical_section | end_critical_section | |
On the command-line, you can use the following:
polyspace-bug-finder
-entry-points my_task,reset
-critical-section-begin begin_critical_section:cs1
-critical-section-end end_critical_section:cs1The example has two entry points, my_task and reset.
In the while loop, my_task leaves
a critical section through the call end_critical_section();.
In an iteration of the while loop:
If
my_taskenters theifcondition branch, the critical section begins through a call tobegin_critical_section.If
my_taskdoes not enter theifcondition branch and leaves thewhileloop, the critical section does not begin. Therefore, a Missing lock defect occurs.If
my_taskdoes not enter theifcondition branch and continues to the next iteration of thewhileloop, the unlock functionend_critical_sectionis called again. A Double unlock defect occurs.
Because numCycles is a volatile variable,
it can take any value. Any
of the cases above are possible. Therefore, a Missing lock defect
and a Double unlock defect appear on the call end_critical_section.
Missing unlock occurs when:
A task calls a lock function.
The task ends without a call to an unlock function.
In multitasking code, a lock function begins a critical section
of code and an unlock function ends it. When a task, my_task,
calls a lock function, my_lock, other tasks calling my_lock must
wait until my_task calls the corresponding unlock
function. Polyspace requires that both lock and unlock functions
must have the form void func(void).
To find this defect, before analysis, you must specify the multitasking options. On the Configuration pane, select Multitasking.
An unlock function ends a critical section so that other waiting tasks can enter the critical section. A missing unlock function can result in tasks blocked for an unnecessary length of time.
Identify the critical section of code, that is, the section that you want to be executed as an atomic block. At the end of this section, call the unlock function that corresponds to the lock function used at the beginning of the section.
There can be other reasons and corresponding fixes for the defect. Perhaps you called the incorrect unlock function. Check the lock-unlock function pair in your Polyspace analysis configuration and fix the mismatch.
See examples of fixes below. To avoid the
issue, you can follow the practice of calling the lock and unlock functions in
the same module at the same level of abstraction. For instance, in this example,
func calls the lock and unlock function at the same level
but func2 does
not.
void func() {
my_lock();
{
// ...
}
my_unlock();
}
void func2() {
{
my_lock();
// ...
}
my_unlock();
}If you do not want to fix the issue, add comments to your result or code to avoid another review. See:
Address Results in Polyspace User Interface Through Bug Fixes or Justifications if you review results in the Polyspace user interface.
Address Results in Polyspace Access Through Bug Fixes or Justifications (Polyspace Access) if you review results in a web browser.
Annotate Code and Hide Known or Acceptable Results if you review results in an IDE.
void begin_critical_section(void);
void end_critical_section(void);
int global_var;
void reset()
{
begin_critical_section();
global_var = 0;
end_critical_section();
}
void my_task(void)
{
begin_critical_section(); //Noncompliant
global_var += 1;
}In this example, to emulate multitasking behavior, specify the following options:
| Option | Specification | |
|---|---|---|
| Configure multitasking manually | ||
| Tasks |
| |
| Critical section details | Starting routine | Ending routine |
begin_critical_section | end_critical_section | |
On the command-line, you can use the following:
polyspace-bug-finder
-entry-points my_task,reset
-critical-section-begin begin_critical_section:cs1
-critical-section-end end_critical_section:cs1The example has two entry points, my_task and reset. my_task enters
a critical section through the call begin_critical_section();. my_task ends
without calling end_critical_section.
One possible correction is to call the unlock function end_critical_section after
the instructions in the critical section.
void begin_critical_section(void);
void end_critical_section(void);
int global_var;
void reset(void)
{
begin_critical_section();
global_var = 0;
end_critical_section();
}
void my_task(void)
{
begin_critical_section();
global_var += 1;
end_critical_section();
}
void begin_critical_section(void);
void end_critical_section(void);
int global_var;
void reset() {
begin_critical_section();
global_var=0;
end_critical_section();
}
void my_task(void) {
int index=0;
volatile int numCycles;
while(numCycles) {
begin_critical_section(); //Noncompliant
global_var ++;
if(index%10==0) {
global_var = 0;
end_critical_section();
}
index++;
}
}In this example, to emulate multitasking behavior, specify the following options.
| Option | Specification | |
|---|---|---|
| Configure multitasking manually | ||
| Tasks |
| |
| Critical section details | Starting routine | Ending routine |
begin_critical_section | end_critical_section | |
On the command-line, you can use the following:
polyspace-bug-finder
-entry-points my_task,reset
-critical-section-begin begin_critical_section:cs1
-critical-section-end end_critical_section:cs1The example has two entry points, my_task and reset.
In the while loop, my_task enters
a critical section through the call begin_critical_section();.
In an iteration of the while loop:
If
my_taskenters theifcondition branch, the critical section ends through a call toend_critical_section.If
my_taskdoes not enter theifcondition branch and leaves thewhileloop, the critical section does not end. Therefore, a Missing unlock defect occurs.If
my_taskdoes not enter theifcondition branch and continues to the next iteration of thewhileloop, the lock functionbegin_critical_sectionis called again. A Double lock defect occurs.
Because numCycles is a volatile variable,
it can take any value. Any
of the cases above is possible. Therefore, a Missing unlock defect
and a Double lock defect appear on the call begin_critical_section.
One possible correction is to call the unlock function end_critical_section outside
the if condition.
void begin_critical_section(void);
void end_critical_section(void);
int global_var;
void reset() {
begin_critical_section();
global_var=0;
end_critical_section();
}
void my_task(void) {
int index=0;
volatile int numCycles;
while(numCycles) {
begin_critical_section();
global_var ++;
if(index%10==0) {
global_var=0;
}
end_critical_section();
index++;
}
}Another possible correction is to call the unlock function end_critical_section in
every branches of the if condition.
void begin_critical_section(void);
void end_critical_section(void);
int global_var;
void reset() {
begin_critical_section();
global_var=0;
end_critical_section();
}
void my_task(void) {
int index=0;
volatile int numCycles;
while(numCycles) {
begin_critical_section();
global_var ++;
if(index%10==0) {
global_var=0;
end_critical_section();
}
else
end_critical_section();
index++;
}
}Double lock occurs when:
A task calls a lock function
my_lock.The task calls
my_lockagain before calling the corresponding unlock function.
In multitasking code, a lock function begins a critical section
of code and an unlock function ends it. When a task task1 calls
a lock function lock, other tasks calling lock must
wait until task calls the corresponding unlock
function. Polyspace requires that both lock and unlock functions
must have the form void func(void).
To find this defect, you must specify the multitasking options before analysis. To specify these options, on the Configuration pane, select Multitasking.
A call to a lock function begins a critical section so that other tasks have to wait to enter the same critical section. If the same lock function is called again within the critical section, the task blocks itself.
The fix depends on the root cause of the defect. A double lock defect often indicates a coding error. Perhaps you omitted the call to an unlock function to end a previous critical section and started the next critical section. Perhaps you wanted to use a different lock function for the second critical section.
Identify each critical section of code, that is, the section that you want to be executed as an atomic block. Call a lock function at the beginning of the section. Within the critical section, make sure that you do not call the lock function again. At the end of the section, call the unlock function that corresponds to the lock function.
See examples of fixes below. To avoid the
issue, you can follow the practice of calling the lock and unlock functions in
the same module at the same level of abstraction. For instance, in this example,
func calls the lock and unlock function at the same level
but func2 does
not.
void func() {
my_lock();
{
// ...
}
my_unlock();
}
void func2() {
{
my_lock();
// ...
}
my_unlock();
}If you do not want to fix the issue, add comments to your result or code to avoid another review. See:
Address Results in Polyspace User Interface Through Bug Fixes or Justifications if you review results in the Polyspace user interface.
Address Results in Polyspace Access Through Bug Fixes or Justifications (Polyspace Access) if you review results in a web browser.
Annotate Code and Hide Known or Acceptable Results if you review results in an IDE.
int global_var;
void lock(void);
void unlock(void);
void task1(void)
{
lock();
global_var += 1;
lock(); //Noncompliant
global_var += 1;
unlock();
}
void task2(void)
{
lock();
global_var += 1;
unlock();
}
In this example, to emulate multitasking behavior, you must specify the following options:
| Option | Specification | |
|---|---|---|
| Configure multitasking manually | ||
| Tasks |
| |
| Critical section details | Starting routine | Ending routine |
lock | unlock | |
On the command-line, you can use the following:
polyspace-bug-finder
-entry-points task1,task2
-critical-section-begin lock:cs1
-critical-section-end unlock:cs1task1 enters a critical section through the
call lock();. task1 calls lock again
before it leaves the critical section through the call unlock();.
If you want the first global_var+=1; to be
outside the critical section, one possible correction is to remove
the first call to lock. However, if other tasks
are using global_var, this code can produce a Data race error.
int global_var;
void lock(void);
void unlock(void);
void task1(void)
{
global_var += 1;
lock();
global_var += 1;
unlock();
}
void task2(void)
{
lock();
global_var += 1;
unlock();
}
If you want the first global_var+=1; to be
inside the critical section, one possible correction is to remove
the second call to lock.
int global_var;
void lock(void);
void unlock(void);
void task1(void)
{
lock();
global_var += 1;
global_var += 1;
unlock();
}
void task2(void)
{
lock();
global_var += 1;
unlock();
}
If you want the second global_var+=1; to
be inside a critical section, another possible correction is to add
another call to unlock.
int global_var;
void lock(void);
void unlock(void);
void task1(void)
{
lock();
global_var += 1;
unlock();
lock();
global_var += 1;
unlock();
}
void task2(void)
{
lock();
global_var += 1;
unlock();
}
int global_var;
void lock(void);
void unlock(void);
void performOperation(void) {
lock(); //Noncompliant
global_var++;
}
void task1(void)
{
lock();
global_var += 1;
performOperation();
unlock();
}
void task2(void)
{
lock();
global_var += 1;
unlock();
}
In this example, to emulate multitasking behavior, you must specify the following options:
| Option | Specification | |
|---|---|---|
| Configure multitasking manually | ||
| Tasks |
| |
| Critical section details | Starting routine | Ending routine |
lock | unlock | |
On the command-line, you can use the following:
polyspace-bug-finder
-entry-points task1,task2
-critical-section-begin lock:cs1
-critical-section-end unlock:cs1task1 enters a critical section through the
call lock();. task1 calls the
function performOperation. In performOperation, lock is
called again even though task1 has not left the
critical section through the call unlock();.
In the result details for the defect, you see the sequence of instructions leading to the defect. For instance, you see that following the first entry into the critical section, the execution path:
Enters function
performOperation.Inside
performOperation, attempts to enter the same critical section once again.

You can click each event to navigate to the corresponding line in the source code.
One possible correction is to remove the call to lock in task1.
int global_var;
void lock(void);
void unlock(void);
void performOperation(void) {
global_var++;
}
void task1(void)
{
lock();
global_var += 1;
performOperation();
unlock();
}
void task2(void)
{
lock();
global_var += 1;
unlock();
}
Double unlock occurs when:
A task calls a lock function
my_lock.The task calls the corresponding unlock function
my_unlock.The task calls
my_unlockagain. The task does not callmy_locka second time between the two calls tomy_unlock.
In multitasking code, a lock function begins a critical section
of code and an unlock function ends it. When a task task1 calls
a lock function my_lock, other tasks calling my_lock must
wait until task1 calls the corresponding unlock
function. Polyspace requires that both lock and unlock functions
must have the form void func(void).
To find this defect, you must specify the multitasking options before analysis. To specify these options, on the Configuration pane, select Multitasking.
A double unlock defect can indicate a coding error. Perhaps you wanted to call a different unlock function to end a different critical section. Perhaps you called the unlock function prematurely the first time and only the second call indicates the end of the critical section.
The fix depends on the root cause of the defect.
Identify each critical section of code, that is, the section that you want to be executed as an atomic block. Call a lock function at the beginning of the section. Only at the end of the section, call the unlock function that corresponds to the lock function. Remove any other redundant call to the unlock function.
See examples of fixes below. To avoid the
issue, you can follow the practice of calling the lock and unlock functions in
the same module at the same level of abstraction. For instance, in this example,
func calls the lock and unlock function at the same level
but func2 does
not.
void func() {
my_lock();
{
// ...
}
my_unlock();
}
void func2() {
{
my_lock();
// ...
}
my_unlock();
}If you do not want to fix the issue, add comments to your result or code to avoid another review. See:
Address Results in Polyspace User Interface Through Bug Fixes or Justifications if you review results in the Polyspace user interface.
Address Results in Polyspace Access Through Bug Fixes or Justifications (Polyspace Access) if you review results in a web browser.
Annotate Code and Hide Known or Acceptable Results if you review results in an IDE.
int global_var;
void BEGIN_CRITICAL_SECTION(void);
void END_CRITICAL_SECTION(void);
void task1(void)
{
BEGIN_CRITICAL_SECTION();
global_var += 1;
END_CRITICAL_SECTION();
global_var += 1;
END_CRITICAL_SECTION(); //Noncompliant
}
void task2(void)
{
BEGIN_CRITICAL_SECTION();
global_var += 1;
END_CRITICAL_SECTION();
}
In this example, to emulate multitasking behavior, you must specify the following options:
| Option | Value | |
|---|---|---|
| Configure multitasking manually | ||
| Tasks |
| |
| Critical section details | Starting routine | Ending routine |
BEGIN_CRITICAL_SECTION | END_CRITICAL_SECTION | |
On the command-line, you can use the following:
polyspace-bug-finder
-entry-points task1,task2
-critical-section-begin BEGIN_CRITICAL_SECTION:cs1
-critical-section-end END_CRITICAL_SECTION:cs1task1 enters a critical section through the
call BEGIN_CRITICAL_SECTION();. task1 leaves
the critical section through the call END_CRITICAL_SECTION();. task1 calls END_CRITICAL_SECTION again
without an intermediate call to BEGIN_CRITICAL_SECTION.
If you want the second global_var+=1; to
be outside the critical section, one possible correction is to remove
the second call to END_CRITICAL_SECTION. However,
if other tasks are using global_var, this code
can produce a Data race error.
int global_var;
void BEGIN_CRITICAL_SECTION(void);
void END_CRITICAL_SECTION(void);
void task1(void)
{
BEGIN_CRITICAL_SECTION();
global_var += 1;
END_CRITICAL_SECTION();
global_var += 1;
}
void task2(void)
{
BEGIN_CRITICAL_SECTION();
global_var += 1;
END_CRITICAL_SECTION();
}
If you want the second global_var+=1; to
be inside the critical section, one possible correction is to remove
the first call to END_CRITICAL_SECTION.
int global_var;
void BEGIN_CRITICAL_SECTION(void);
void END_CRITICAL_SECTION(void);
void task1(void)
{
BEGIN_CRITICAL_SECTION();
global_var += 1;
global_var += 1;
END_CRITICAL_SECTION();
}
void task2(void)
{
BEGIN_CRITICAL_SECTION();
global_var += 1;
END_CRITICAL_SECTION();
}
If you want the second global_var+=1; to
be inside a critical section, another possible correction is to add
another call to BEGIN_CRITICAL_SECTION.
int global_var;
void BEGIN_CRITICAL_SECTION(void);
void END_CRITICAL_SECTION(void);
void task1(void)
{
BEGIN_CRITICAL_SECTION();
global_var += 1;
END_CRITICAL_SECTION();
BEGIN_CRITICAL_SECTION();
global_var += 1;
END_CRITICAL_SECTION();
}
void task2(void)
{
BEGIN_CRITICAL_SECTION();
global_var += 1;
END_CRITICAL_SECTION();
}
Check Information
| Group: Rec. 14. Concurrency (CON) |
Version History
Introduced in R2019a
See Also
External Websites
1 This software has been created by MathWorks incorporating portions of: the “SEI CERT-C Website,” © 2017 Carnegie Mellon University, the SEI CERT-C++ Web site © 2017 Carnegie Mellon University, ”SEI CERT C Coding Standard – Rules for Developing safe, Reliable and Secure systems – 2016 Edition,” © 2016 Carnegie Mellon University, and “SEI CERT C++ Coding Standard – Rules for Developing safe, Reliable and Secure systems in C++ – 2016 Edition” © 2016 Carnegie Mellon University, with special permission from its Software Engineering Institute.
ANY MATERIAL OF CARNEGIE MELLON UNIVERSITY AND/OR ITS SOFTWARE ENGINEERING INSTITUTE CONTAINED HEREIN IS FURNISHED ON AN "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY KIND, EITHER EXPRESSED OR IMPLIED, AS TO ANY MATTER INCLUDING, BUT NOT LIMITED TO, WARRANTY OF FITNESS FOR PURPOSE OR MERCHANTABILITY, EXCLUSIVITY, OR RESULTS OBTAINED FROM USE OF THE MATERIAL. CARNEGIE MELLON UNIVERSITY DOES NOT MAKE ANY WARRANTY OF ANY KIND WITH RESPECT TO FREEDOM FROM PATENT, TRADEMARK, OR COPYRIGHT INFRINGEMENT.
This software and associated documentation has not been reviewed nor is it endorsed by Carnegie Mellon University or its Software Engineering Institute.
MATLAB Command
You clicked a link that corresponds to this MATLAB command:
Run the command by entering it in the MATLAB Command Window. Web browsers do not support MATLAB commands.
Website auswählen
Wählen Sie eine Website aus, um übersetzte Inhalte (sofern verfügbar) sowie lokale Veranstaltungen und Angebote anzuzeigen. Auf der Grundlage Ihres Standorts empfehlen wir Ihnen die folgende Auswahl: .
Sie können auch eine Website aus der folgenden Liste auswählen:
So erhalten Sie die bestmögliche Leistung auf der Website
Wählen Sie für die bestmögliche Website-Leistung die Website für China (auf Chinesisch oder Englisch). Andere landesspezifische Websites von MathWorks sind für Besuche von Ihrem Standort aus nicht optimiert.
Amerika
- América Latina (Español)
- Canada (English)
- United States (English)
Europa
- Belgium (English)
- Denmark (English)
- Deutschland (Deutsch)
- España (Español)
- Finland (English)
- France (Français)
- Ireland (English)
- Italia (Italiano)
- Luxembourg (English)
- Netherlands (English)
- Norway (English)
- Österreich (Deutsch)
- Portugal (English)
- Sweden (English)
- Switzerland
- United Kingdom (English)