Main Content

Missing unlock

Lock function without unlock function

Description

This checker is deactivated in a default Polyspace® as You Code analysis. See Checkers Deactivated in Polyspace as You Code Analysis (Polyspace Access).

This defect 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.

To find this defect, specify your lock and unlock functions using one of these methods:

Risk

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.

Fix

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:

Extend Checker

You might be using locking and unlocking functions that are not supported by Polyspace. Extend this checker by mapping these functions to their known POSIX® equivalent. See Extend Concurrency Defect Checkers to Unsupported Multithreading Environments.

Examples

expand all



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(); 
    global_var += 1;
}

In this example, to emulate multitasking behavior, specify the following options:

OptionValue
Configure multitasking manually
Tasks (-entry-points)

my_task, reset

Critical section details (-critical-section-begin -critical-section-end)Starting routineEnding routine
begin_critical_sectionend_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:cs1

The 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.

Correction — Provide Unlock

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();
      global_var ++;
      if(index%10==0) {
        global_var = 0;
        end_critical_section();
      }
      index++;
    }
}

In this example, to emulate multitasking behavior, specify the following options.

OptionSpecification
Configure multitasking manually
Tasks (-entry-points)

my_task, reset

Critical section details (-critical-section-begin -critical-section-end)Starting routineEnding routine
begin_critical_sectionend_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:cs1

The 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_task enters the if condition branch, the critical section ends through a call to end_critical_section.

  • If my_task does not enter the if condition branch and leaves the while loop, the critical section does not end. Therefore, a Missing unlock defect occurs.

  • If my_task does not enter the if condition branch and continues to the next iteration of the while loop, the lock function begin_critical_section is 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.

Correction — Place Unlock Outside Condition

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++;
    }
}
Correction — Place Unlock in Every Conditional Branch

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++;
    }
}

Result Information

Group: Concurrency
Language: C | C++
Default: On
Command-Line Syntax: BAD_LOCK
Impact: High

Version History

Introduced in R2014b